Re: [PATCH v2 04/11] PCI: dwc: pcie-kirin: add support for Kirin 970 PCIe controller

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Feb 3, 2021 at 1:02 AM Mauro Carvalho Chehab
<mchehab+huawei@xxxxxxxxxx> wrote:
>
> From: Manivannan Sadhasivam <manivannan.sadhasivam@xxxxxxxxxx>
>
> Add support for HiSilicon Kirin 970 (hi3670) SoC PCIe controller, based
> on Synopsys DesignWare PCIe controller IP.
>
> [mchehab+huawei@xxxxxxxxxx: fix merge conflicts]
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@xxxxxxxxxx>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@xxxxxxxxxx>
> ---
>  drivers/pci/controller/dwc/pcie-kirin.c | 723 +++++++++++++++++++++++-
>  1 file changed, 707 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c
> index 026fd1e42a55..5925d2b345a8 100644
> --- a/drivers/pci/controller/dwc/pcie-kirin.c
> +++ b/drivers/pci/controller/dwc/pcie-kirin.c
> @@ -29,6 +29,7 @@
>  #define to_kirin_pcie(x) dev_get_drvdata((x)->dev)
>
>  #define REF_CLK_FREQ                   100000000
> +#define AXI_CLK_FREQ                   207500000
>
>  /* PCIe ELBI registers */
>  #define SOC_PCIECTRL_CTRL0_ADDR                0x000
> @@ -60,6 +61,65 @@
>  #define PCIE_DEBOUNCE_PARAM    0xF0F400
>  #define PCIE_OE_BYPASS         (0x3 << 28)
>
> +/* PCIe CTRL registers */
> +#define SOC_PCIECTRL_CTRL0_ADDR   0x000
> +#define SOC_PCIECTRL_CTRL1_ADDR   0x004
> +#define SOC_PCIECTRL_CTRL7_ADDR   0x01c
> +#define SOC_PCIECTRL_CTRL12_ADDR  0x030
> +#define SOC_PCIECTRL_CTRL20_ADDR  0x050
> +#define SOC_PCIECTRL_CTRL21_ADDR  0x054
> +#define SOC_PCIECTRL_STATE0_ADDR  0x400
> +
> +/* PCIe PHY registers */
> +#define SOC_PCIEPHY_CTRL0_ADDR    0x000
> +#define SOC_PCIEPHY_CTRL1_ADDR    0x004
> +#define SOC_PCIEPHY_CTRL2_ADDR    0x008
> +#define SOC_PCIEPHY_CTRL3_ADDR    0x00c
> +#define SOC_PCIEPHY_CTRL38_ADDR   0x0098
> +#define SOC_PCIEPHY_STATE0_ADDR   0x400
> +
> +#define PCIE_LINKUP_ENABLE            (0x8020)
> +#define PCIE_ELBI_SLV_DBI_ENABLE      (0x1 << 21)
> +#define PCIE_LTSSM_ENABLE_BIT         (0x1 << 11)
> +#define PCIEPHY_RESET_BIT             (0x1 << 17)
> +#define PCIEPHY_PIPE_LINE0_RESET_BIT  (0x1 << 19)
> +
> +#define PORT_MSI_CTRL_ADDR            0x820
> +#define PORT_MSI_CTRL_UPPER_ADDR      0x824
> +#define PORT_MSI_CTRL_INT0_ENABLE     0x828

These are common DWC 'port logic' registers. I think the core DWC
should handle them if not already.

> +
> +#define EYEPARAM_NOCFG 0xFFFFFFFF
> +#define RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1 0x3001
> +#define SUP_DIG_LVL_OVRD_IN 0xf
> +#define LANEN_DIG_ASIC_TX_OVRD_IN_1 0x1002
> +#define LANEN_DIG_ASIC_TX_OVRD_IN_2 0x1003
> +
> +/* kirin970 pciephy register */
> +#define SOC_PCIEPHY_MMC1PLL_CTRL1  0xc04
> +#define SOC_PCIEPHY_MMC1PLL_CTRL16 0xC40
> +#define SOC_PCIEPHY_MMC1PLL_CTRL17 0xC44
> +#define SOC_PCIEPHY_MMC1PLL_CTRL20 0xC50
> +#define SOC_PCIEPHY_MMC1PLL_CTRL21 0xC54
> +#define SOC_PCIEPHY_MMC1PLL_STAT0  0xE00

This looks like it is almost all phy related. I think it should all be
moved to a separate phy driver. Yes, we have some other PCI drivers
controlling their phys directly where the phy registers are
intermingled with the PCI host registers, but I think those either
predate the phy subsystem or are really simple. I also have a dream to
move all the phy control to the DWC core code.

> +
> +#define CRGPERIPH_PEREN12   0x470
> +#define CRGPERIPH_PERDIS12  0x474
> +#define CRGPERIPH_PCIECTRL0 0x800
> +
> +/* define ie,oe cfg */
> +#define IO_IE_EN_HARD_BYPASS         (0x1 << 27)
> +#define IO_OE_EN_HARD_BYPASS         (0x1 << 11)
> +#define IO_HARD_CTRL_DEBOUNCE_BYPASS (0x1 << 10)
> +#define IO_OE_GT_MODE                (0x2 << 7)
> +#define DEBOUNCE_WAITCFG_IN          (0xf << 20)
> +#define DEBOUNCE_WAITCFG_OUT         (0xf << 13)
> +
> +/* noc power domain */
> +#define NOC_POWER_IDLEREQ_1 0x38c
> +#define NOC_POWER_IDLE_1    0x394
> +#define NOC_PW_MASK         0x10000
> +#define NOC_PW_SET_BIT      0x1
> +
>  /* peri_crg ctrl */
>  #define CRGCTRL_PCIE_ASSERT_OFFSET     0x88
>  #define CRGCTRL_PCIE_ASSERT_BIT                0x8c000000
> @@ -84,12 +144,21 @@ struct kirin_pcie {
>         void __iomem    *phy_base;
>         struct regmap   *crgctrl;
>         struct regmap   *sysctrl;
> +       struct regmap   *pmctrl;
>         struct clk      *apb_sys_clk;
>         struct clk      *apb_phy_clk;
>         struct clk      *phy_ref_clk;
>         struct clk      *pcie_aclk;
>         struct clk      *pcie_aux_clk;
> -       int             gpio_id_reset;
> +       int             gpio_id_reset[4];
> +       int             gpio_id_clkreq[3];
> +       u32             eye_param[5];
> +};
> +
> +struct kirin_pcie_ops {
> +       long (*get_resource)(struct kirin_pcie *kirin_pcie,
> +                            struct platform_device *pdev);
> +       int (*power_on)(struct kirin_pcie *kirin_pcie);

Never need to power off?

>  };
>
>  /* Registers in PCIeCTRL */
> @@ -116,6 +185,28 @@ static inline u32 kirin_apb_phy_readl(struct kirin_pcie *kirin_pcie, u32 reg)
>         return readl(kirin_pcie->phy_base + reg);
>  }
>
> +static inline void kirin970_apb_phy_writel(struct kirin_pcie *kirin_pcie,
> +                                       u32 val, u32 reg)
> +{
> +       writel(val, kirin_pcie->phy_base + 0x40000 + reg);

That definitely looks like the phy is a separate block.

> +}
> +
> +static inline u32 kirin970_apb_phy_readl(struct kirin_pcie *kirin_pcie, u32 reg)
> +{
> +       return readl(kirin_pcie->phy_base + 0x40000 + reg);
> +}
> +
> +static inline void kirin_apb_natural_phy_writel(struct kirin_pcie *kirin_pcie,
> +                                       u32 val, u32 reg)
> +{
> +       writel(val, kirin_pcie->phy_base + reg * 4);
> +}
> +
> +static inline u32 kirin_apb_natural_phy_readl(struct kirin_pcie *kirin_pcie, u32 reg)
> +{
> +       return readl(kirin_pcie->phy_base + reg * 4);
> +}
> +
>  static long kirin_pcie_get_clk(struct kirin_pcie *kirin_pcie,
>                                struct platform_device *pdev)
>  {
> @@ -144,9 +235,68 @@ static long kirin_pcie_get_clk(struct kirin_pcie *kirin_pcie,
>         return 0;
>  }
>
> -static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,
> -                                   struct platform_device *pdev)
> +void kirin970_pcie_get_eyeparam(struct kirin_pcie *pcie)
>  {
> +       struct device *dev = pcie->pci->dev;
> +       int i;
> +       struct device_node *np;
> +
> +       np = dev->of_node;
> +
> +       if (of_property_read_u32_array(np, "eye_param", pcie->eye_param, 5)) {
> +               for (i = 0; i < 5; i++)
> +               pcie->eye_param[i] = EYEPARAM_NOCFG;
> +       }
> +
> +       dev_dbg(dev, "eye_param_vboost = [0x%x]\n", pcie->eye_param[0]);
> +       dev_dbg(dev, "eye_param_iboost = [0x%x]\n", pcie->eye_param[1]);
> +       dev_dbg(dev, "eye_param_pre = [0x%x]\n", pcie->eye_param[2]);
> +       dev_dbg(dev, "eye_param_post = [0x%x]\n", pcie->eye_param[3]);
> +       dev_dbg(dev, "eye_param_main = [0x%x]\n", pcie->eye_param[4]);
> +}
> +
> +static void kirin970_pcie_set_eyeparam(struct kirin_pcie *kirin_pcie)
> +{
> +       u32 val;
> +
> +       val = kirin_apb_natural_phy_readl(kirin_pcie, RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1);
> +
> +       if (kirin_pcie->eye_param[1] != EYEPARAM_NOCFG) {
> +               val &= (~0xf00);
> +               val |= (kirin_pcie->eye_param[1] << 8) | (0x1 << 12);
> +       }
> +       kirin_apb_natural_phy_writel(kirin_pcie, val, RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1);
> +
> +       val = kirin_apb_natural_phy_readl(kirin_pcie, LANEN_DIG_ASIC_TX_OVRD_IN_2);
> +       val &= (~0x1FBF);
> +       if (kirin_pcie->eye_param[2] != EYEPARAM_NOCFG)
> +               val |= (kirin_pcie->eye_param[2]<< 0) | (0x1 << 6);
> +
> +       if (kirin_pcie->eye_param[3] != EYEPARAM_NOCFG)
> +               val |= (kirin_pcie->eye_param[3] << 7) | (0x1 << 13);
> +
> +       kirin_apb_natural_phy_writel(kirin_pcie, val, LANEN_DIG_ASIC_TX_OVRD_IN_2);
> +
> +       val = kirin_apb_natural_phy_readl(kirin_pcie, SUP_DIG_LVL_OVRD_IN);
> +       if (kirin_pcie->eye_param[0] != EYEPARAM_NOCFG) {
> +               val &= (~0x1C0);
> +               val |= (kirin_pcie->eye_param[0] << 6) | (0x1 << 9);
> +       }
> +       kirin_apb_natural_phy_writel(kirin_pcie, val, SUP_DIG_LVL_OVRD_IN);
> +
> +       val = kirin_apb_natural_phy_readl(kirin_pcie, LANEN_DIG_ASIC_TX_OVRD_IN_1);
> +       if (kirin_pcie->eye_param[4] != EYEPARAM_NOCFG) {
> +               val &= (~0x7E00);
> +               val |= (kirin_pcie->eye_param[4] << 9) | (0x1 << 15);
> +       }
> +       kirin_apb_natural_phy_writel(kirin_pcie, val, LANEN_DIG_ASIC_TX_OVRD_IN_1);
> +}
> +
> +static long kirin960_pcie_get_resource(struct kirin_pcie *kirin_pcie,
> +                                      struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +
>         kirin_pcie->apb_base =
>                 devm_platform_ioremap_resource_byname(pdev, "apb");
>         if (IS_ERR(kirin_pcie->apb_base))
> @@ -167,6 +317,122 @@ static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,
>         if (IS_ERR(kirin_pcie->sysctrl))
>                 return PTR_ERR(kirin_pcie->sysctrl);
>
> +       kirin_pcie->gpio_id_reset[0] = of_get_named_gpio(dev->of_node,
> +                                                     "reset-gpios", 0);
> +       if (kirin_pcie->gpio_id_reset[0] < 0)
> +               return -ENODEV;
> +
> +       return 0;
> +}
> +
> +static long kirin970_pcie_get_resource(struct kirin_pcie *kirin_pcie,
> +                                     struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct resource *apb;
> +       struct resource *phy;
> +       struct resource *dbi;
> +       int ret;
> +
> +       apb = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apb");
> +       kirin_pcie->apb_base = devm_ioremap_resource(dev, apb);
> +       if (IS_ERR(kirin_pcie->apb_base))
> +               return PTR_ERR(kirin_pcie->apb_base);
> +
> +       phy = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
> +       kirin_pcie->phy_base = devm_ioremap_resource(dev, phy);
> +       if (IS_ERR(kirin_pcie->phy_base))
> +               return PTR_ERR(kirin_pcie->phy_base);
> +
> +       dbi = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
> +       kirin_pcie->pci->dbi_base = devm_ioremap_resource(dev, dbi);

The DWC core handles this now.

> +       if (IS_ERR(kirin_pcie->pci->dbi_base))
> +               return PTR_ERR(kirin_pcie->pci->dbi_base);
> +
> +       kirin970_pcie_get_eyeparam(kirin_pcie);
> +
> +       kirin_pcie->gpio_id_reset[0] = of_get_named_gpio(dev->of_node,
> +                                               "switch,reset-gpios", 0);
> +       if (kirin_pcie->gpio_id_reset[0] < 0)
> +               return -ENODEV;
> +
> +       kirin_pcie->gpio_id_reset[1] = of_get_named_gpio(dev->of_node,
> +                                               "eth,reset-gpios", 0);
> +       if (kirin_pcie->gpio_id_reset[1] < 0)
> +               return -ENODEV;
> +
> +       kirin_pcie->gpio_id_reset[2] = of_get_named_gpio(dev->of_node,
> +                                               "m_2,reset-gpios", 0);
> +       if (kirin_pcie->gpio_id_reset[2] < 0)
> +               return -ENODEV;
> +
> +       kirin_pcie->gpio_id_reset[3] = of_get_named_gpio(dev->of_node,
> +                                               "mini1,reset-gpios", 0);
> +       if (kirin_pcie->gpio_id_reset[3] < 0)

I've already explained how all this is wrong.

> +               return -ENODEV;
> +
> +       ret = devm_gpio_request(dev, kirin_pcie->gpio_id_reset[0],
> +                                   "pcie_switch_reset");
> +       if (ret)
> +               return ret;
> +       ret = devm_gpio_request(dev, kirin_pcie->gpio_id_reset[1],
> +                                   "pcie_eth_reset");
> +       if (ret)
> +               return ret;
> +       ret = devm_gpio_request(dev, kirin_pcie->gpio_id_reset[2],
> +                                   "pcie_m_2_reset");
> +       if (ret)
> +               return ret;
> +       ret = devm_gpio_request(dev, kirin_pcie->gpio_id_reset[3],
> +                                   "pcie_mini1_reset");
> +       if (ret)
> +               return ret;
> +
> +       kirin_pcie->gpio_id_clkreq[0] = of_get_named_gpio(dev->of_node,
> +                                               "eth,clkreq-gpios", 0);
> +       if (kirin_pcie->gpio_id_clkreq[0] < 0)
> +               return -ENODEV;
> +
> +       kirin_pcie->gpio_id_clkreq[1] = of_get_named_gpio(dev->of_node,
> +                                               "m_2,clkreq-gpios", 0);
> +       if (kirin_pcie->gpio_id_clkreq[1] < 0)
> +               return -ENODEV;
> +
> +       kirin_pcie->gpio_id_clkreq[2] = of_get_named_gpio(dev->of_node,
> +                                               "mini1,clkreq-gpios", 0);
> +       if (kirin_pcie->gpio_id_clkreq[2] < 0)
> +               return -ENODEV;
> +
> +       ret = devm_gpio_request(dev, kirin_pcie->gpio_id_clkreq[0],
> +                                   "pcie_eth_clkreq");
> +       if (ret)
> +               return ret;
> +
> +       ret = devm_gpio_request(dev, kirin_pcie->gpio_id_clkreq[1],
> +                                   "pcie_m_2_clkreq");
> +       if (ret)
> +               return ret;
> +
> +       ret = devm_gpio_request(dev, kirin_pcie->gpio_id_clkreq[2],
> +                                   "pcie_mini1_clkreq");
> +       if (ret)
> +               return ret;
> +
> +       kirin_pcie->crgctrl =
> +               syscon_regmap_lookup_by_compatible("hisilicon,hi3670-crgctrl");
> +       if (IS_ERR(kirin_pcie->crgctrl))
> +               return PTR_ERR(kirin_pcie->crgctrl);
> +
> +       kirin_pcie->sysctrl =
> +               syscon_regmap_lookup_by_compatible("hisilicon,hi3670-sctrl");
> +       if (IS_ERR(kirin_pcie->sysctrl))
> +               return PTR_ERR(kirin_pcie->sysctrl);
> +
> +       kirin_pcie->pmctrl =
> +               syscon_regmap_lookup_by_compatible("hisilicon,hi3670-pmctrl");
> +       if (IS_ERR(kirin_pcie->sysctrl))
> +               return PTR_ERR(kirin_pcie->sysctrl);
> +
>         return 0;
>  }
>
> @@ -208,6 +474,21 @@ static void kirin_pcie_oe_enable(struct kirin_pcie *kirin_pcie)
>         regmap_write(kirin_pcie->sysctrl, SCTRL_PCIE_OE_OFFSET, val);
>  }
>
> +static int kirin970_pcie_clk_ctrl(struct clk *clk, int clk_on)
> +{
> +       int ret = 0;
> +
> +       if (clk_on) {
> +               ret = clk_prepare_enable(clk);
> +               if (ret)
> +                       return ret;
> +       } else {
> +               clk_disable_unprepare(clk);
> +       }
> +
> +       return ret;
> +}
> +
>  static int kirin_pcie_clk_ctrl(struct kirin_pcie *kirin_pcie, bool enable)
>  {
>         int ret = 0;
> @@ -255,7 +536,401 @@ static int kirin_pcie_clk_ctrl(struct kirin_pcie *kirin_pcie, bool enable)
>         return ret;
>  }
>
> -static int kirin_pcie_power_on(struct kirin_pcie *kirin_pcie)
> +static void kirin970_pcie_natural_cfg(struct kirin_pcie *kirin_pcie)
> +{
> +       u32 val;
> +
> +       /* change 2p mem_ctrl */
> +       kirin_apb_ctrl_writel(kirin_pcie, 0x02605550, SOC_PCIECTRL_CTRL20_ADDR);
> +
> +       /* pull up sys_aux_pwr_det */
> +       val = kirin_apb_ctrl_readl(kirin_pcie, SOC_PCIECTRL_CTRL7_ADDR);
> +       val |= (0x1 << 10);
> +       kirin_apb_ctrl_writel(kirin_pcie, val, SOC_PCIECTRL_CTRL7_ADDR);
> +
> +       /* output, pull down */
> +       val = kirin_apb_ctrl_readl(kirin_pcie, SOC_PCIECTRL_CTRL12_ADDR);
> +       val &= ~(0x3 << 2);
> +       val |= (0x1 << 1);
> +       val &= ~(0x1 << 0);
> +       kirin_apb_ctrl_writel(kirin_pcie, val, SOC_PCIECTRL_CTRL12_ADDR);
> +
> +       /* Handle phy_reset and lane0_reset to HW */
> +       val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_CTRL1_ADDR);
> +       val |= PCIEPHY_RESET_BIT;
> +       val &= ~PCIEPHY_PIPE_LINE0_RESET_BIT;
> +       kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_CTRL1_ADDR);
> +
> +       /* fix chip bug: TxDetectRx fail */
> +       val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_CTRL38_ADDR);
> +       val |= (0x1 << 2);
> +       kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_CTRL38_ADDR);
> +}
> +
> +static void kirin970_pcie_pll_init(struct kirin_pcie *kirin_pcie)
> +{
> +       u32 val;
> +
> +       /* choose FNPLL */
> +       val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL1);
> +       val |= (0x1 << 27);
> +       kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL1);
> +
> +       val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL16);
> +       val &= 0xF000FFFF;
> +       /* fnpll fbdiv = 0xD0 */
> +       val |= (0xd0 << 16);
> +       kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL16);
> +
> +       val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL17);
> +       val &= 0xFF000000;
> +       /* fnpll fracdiv = 0x555555 */
> +       val |= (0x555555 << 0);
> +       kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL17);
> +
> +       val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL20);
> +       val &= 0xF5FF88FF;
> +       /* fnpll dll_en = 0x1 */
> +       val |= (0x1 << 27);
> +       /* fnpll postdiv1 = 0x5 */
> +       val |= (0x5 << 8);
> +       /* fnpll postdiv2 = 0x4 */
> +       val |= (0x4 << 12);
> +       /* fnpll pll_mode = 0x0 */
> +       val &= ~(0x1 << 25);
> +       kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL20);
> +
> +       kirin970_apb_phy_writel(kirin_pcie, 0x20, SOC_PCIEPHY_MMC1PLL_CTRL21);
> +}
> +
> +static int kirin970_pcie_pll_ctrl(struct kirin_pcie *kirin_pcie, bool enable)
> +{
> +       struct device *dev = kirin_pcie->pci->dev;
> +       u32 val;
> +       int time = 200;
> +
> +       if (enable) {
> +               /* pd = 0 */
> +               val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL16);
> +               val &= ~(0x1 << 0);
> +               kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL16);
> +
> +               val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_STAT0);
> +
> +               /* choose FNPLL */
> +               while (!(val & 0x10)) {
> +                       if (!time) {
> +                               dev_err(dev, "wait for pll_lock timeout\n");
> +                               return -1;
> +                       }
> +                       time --;
> +                       udelay(1);
> +                       val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_STAT0);
> +               }
> +
> +               /* pciepll_bp = 0 */
> +               val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL20);
> +               val &= ~(0x1 << 16);
> +               kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL20);
> +
> +       } else {
> +               /* pd = 1 */
> +               val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL16);
> +               val |= (0x1 << 0);
> +               kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL16);
> +
> +               /* pciepll_bp = 1 */
> +               val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL20);
> +               val |= (0x1 << 16);
> +               kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL20);
> +       }
> +
> +        return 0;
> +}
> +
> +static void kirin970_pcie_hp_debounce_gt(struct kirin_pcie *kirin_pcie, bool open)
> +{
> +       if (open)
> +               /* gt_clk_pcie_hp/gt_clk_pcie_debounce open */
> +               regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PEREN12, 0x9000);
> +       else
> +               /* gt_clk_pcie_hp/gt_clk_pcie_debounce close */
> +               regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PERDIS12, 0x9000);
> +}
> +
> +static void kirin970_pcie_phyref_gt(struct kirin_pcie *kirin_pcie, bool open)
> +{
> +       unsigned int val;
> +
> +       regmap_read(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, &val);
> +
> +       if (open)
> +               val &= ~(0x1 << 1); //enable hard gt mode
> +       else
> +               val |= (0x1 << 1); //disable hard gt mode
> +
> +       regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, val);
> +
> +       /* disable soft gt mode */
> +       regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PERDIS12, 0x4000);
> +}
> +
> +static void kirin970_pcie_oe_ctrl(struct kirin_pcie *kirin_pcie, bool en_flag)
> +{
> +       unsigned int val;
> +
> +       regmap_read(kirin_pcie->crgctrl , CRGPERIPH_PCIECTRL0, &val);
> +
> +       /* set ie cfg */
> +       val |= IO_IE_EN_HARD_BYPASS;
> +
> +       /* set oe cfg */
> +       val &= ~IO_HARD_CTRL_DEBOUNCE_BYPASS;
> +
> +       /* set phy_debounce in&out time */
> +       val |= (DEBOUNCE_WAITCFG_IN | DEBOUNCE_WAITCFG_OUT);
> +
> +       /* select oe_gt_mode */
> +       val |= IO_OE_GT_MODE;
> +
> +       if (en_flag)
> +               val &= ~IO_OE_EN_HARD_BYPASS;
> +       else
> +               val |= IO_OE_EN_HARD_BYPASS;
> +
> +       regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, val);
> +}
> +
> +static void kirin970_pcie_ioref_gt(struct kirin_pcie *kirin_pcie, bool open)
> +{
> +       unsigned int val;
> +
> +       if (open) {
> +               kirin_apb_ctrl_writel(kirin_pcie, 0x20000070, SOC_PCIECTRL_CTRL21_ADDR);
> +
> +               kirin970_pcie_oe_ctrl(kirin_pcie, true);
> +
> +               /* en hard gt mode */
> +               regmap_read(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, &val);
> +               val &= ~(0x1 << 0);
> +               regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, val);
> +
> +               /* disable soft gt mode */
> +               regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PERDIS12, 0x2000);
> +
> +       } else {
> +               /* disable hard gt mode */
> +               regmap_read(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, &val);
> +               val |= (0x1 << 0);
> +               regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, val);
> +
> +               /* disable soft gt mode */
> +               regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PERDIS12, 0x2000);
> +
> +               kirin970_pcie_oe_ctrl(kirin_pcie, false);
> +       }
> +}
> +
> +static int kirin970_pcie_allclk_ctrl(struct kirin_pcie *kirin_pcie, bool clk_on)
> +{
> +       struct device *dev = kirin_pcie->pci->dev;
> +       u32 val;
> +       int ret = 0;
> +
> +       if (!clk_on)
> +               goto ALL_CLOSE;
> +
> +       /* choose 100MHz clk src: Bit[8]==1 pad, Bit[8]==0 pll */
> +       val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_CTRL1_ADDR);
> +       val &= ~(0x1 << 8);
> +       kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_CTRL1_ADDR);
> +
> +       kirin970_pcie_pll_init(kirin_pcie);
> +
> +       ret = kirin970_pcie_pll_ctrl(kirin_pcie, true);
> +       if (ret) {
> +               dev_err(dev, "Failed to enable pll\n");
> +               return -1;
> +       }
> +       kirin970_pcie_hp_debounce_gt(kirin_pcie, true);
> +       kirin970_pcie_phyref_gt(kirin_pcie, true);
> +       kirin970_pcie_ioref_gt(kirin_pcie, true);
> +
> +       ret = clk_set_rate(kirin_pcie->pcie_aclk, AXI_CLK_FREQ);
> +       if (ret) {
> +               dev_err(dev, "Failed to set rate\n");
> +               goto GT_CLOSE;
> +       }
> +
> +       ret = kirin970_pcie_clk_ctrl(kirin_pcie->pcie_aclk, true);
> +       if (ret) {
> +               dev_err(dev, "Failed to enable pcie_aclk\n");
> +               goto GT_CLOSE;
> +       }
> +
> +       ret = kirin970_pcie_clk_ctrl(kirin_pcie->pcie_aux_clk, true);
> +       if (ret) {
> +               dev_err(dev, "Failed to enable pcie_aux_clk\n");
> +               goto AUX_CLK_FAIL;
> +       }
> +
> +       return 0;
> +
> +ALL_CLOSE:
> +       kirin970_pcie_clk_ctrl(kirin_pcie->pcie_aux_clk, false);
> +AUX_CLK_FAIL:
> +       kirin970_pcie_clk_ctrl(kirin_pcie->pcie_aclk, false);
> +GT_CLOSE:
> +       kirin970_pcie_ioref_gt(kirin_pcie, false);
> +       kirin970_pcie_phyref_gt(kirin_pcie, false);
> +       kirin970_pcie_hp_debounce_gt(kirin_pcie, false);
> +
> +       kirin970_pcie_pll_ctrl(kirin_pcie, false);
> +
> +       return ret;
> +}
> +
> +static bool is_pipe_clk_stable(struct kirin_pcie *kirin_pcie)
> +{
> +       struct device *dev = kirin_pcie->pci->dev;
> +       u32 val;
> +       u32 time = 100;
> +       u32 pipe_clk_stable = 0x1 << 19;
> +
> +       val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_STATE0_ADDR);
> +       while (val & pipe_clk_stable) {
> +               mdelay(1);
> +               if (time == 0) {
> +                       dev_err(dev, "PIPE clk is not stable\n");
> +                       return false;
> +               }
> +               time--;
> +               val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_STATE0_ADDR);
> +       }
> +
> +       return true;
> +}
> +
> +static int kirin970_pcie_noc_power(struct kirin_pcie *kirin_pcie, bool enable)
> +{
> +       struct device *dev = kirin_pcie->pci->dev;
> +       u32 time = 100;
> +       unsigned int val = NOC_PW_MASK;
> +       int rst;
> +
> +       if (enable)
> +               val = NOC_PW_MASK | NOC_PW_SET_BIT;
> +       else
> +               val = NOC_PW_MASK;
> +       rst = enable ? 1 : 0;
> +
> +       regmap_write(kirin_pcie->pmctrl, NOC_POWER_IDLEREQ_1, val);
> +
> +       time = 100;
> +       regmap_read(kirin_pcie->pmctrl, NOC_POWER_IDLE_1, &val);
> +       while((val & NOC_PW_SET_BIT) != rst) {
> +               udelay(10);
> +               if (!time) {
> +                       dev_err(dev, "Failed to reverse noc power-status\n");
> +                       return -1;
> +               }
> +               time--;
> +               regmap_read(kirin_pcie->pmctrl, NOC_POWER_IDLE_1, &val);
> +       }
> +
> +       return 0;
> +}
> +
> +static int kirin970_pcie_power_on(struct kirin_pcie *kirin_pcie)
> +{
> +       struct device *dev = kirin_pcie->pci->dev;
> +       int ret;
> +       u32 val;
> +
> +       /* Power supply for Host */
> +       regmap_write(kirin_pcie->sysctrl,
> +                    SCTRL_PCIE_CMOS_OFFSET, SCTRL_PCIE_CMOS_BIT);
> +       usleep_range(TIME_CMOS_MIN, TIME_CMOS_MAX);
> +       kirin_pcie_oe_enable(kirin_pcie);
> +
> +       ret = gpio_direction_output(kirin_pcie->gpio_id_clkreq[0], 0);
> +       if (ret)
> +               dev_err(dev, "Failed to pulse eth clkreq signal\n");
> +
> +       ret = gpio_direction_output(kirin_pcie->gpio_id_clkreq[1], 0);
> +       if (ret)
> +               dev_err(dev, "Failed to pulse m.2 clkreq signal\n");
> +
> +       ret = gpio_direction_output(kirin_pcie->gpio_id_clkreq[2], 0);
> +       if (ret)
> +               dev_err(dev, "Failed to pulse mini1 clkreq signal\n");
> +
> +       ret = kirin_pcie_clk_ctrl(kirin_pcie, true);
> +       if (ret)
> +               return ret;
> +
> +       /* ISO disable, PCIeCtrl, PHY assert and clk gate clear */
> +       regmap_write(kirin_pcie->sysctrl,
> +                    SCTRL_PCIE_ISO_OFFSET, SCTRL_PCIE_ISO_BIT);
> +       regmap_write(kirin_pcie->crgctrl,
> +                    CRGCTRL_PCIE_ASSERT_OFFSET, CRGCTRL_PCIE_ASSERT_BIT);
> +       regmap_write(kirin_pcie->sysctrl,
> +                    SCTRL_PCIE_HPCLK_OFFSET, SCTRL_PCIE_HPCLK_BIT);
> +
> +       kirin970_pcie_natural_cfg(kirin_pcie);
> +
> +       ret = kirin970_pcie_allclk_ctrl(kirin_pcie, true);
> +       if (ret)
> +               goto close_clk;
> +
> +       /* pull down phy_test_powerdown signal */
> +       val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_CTRL0_ADDR);
> +       val &= ~(0x1 << 22);
> +       kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_CTRL0_ADDR);
> +
> +       /* deassert controller perst_n */
> +       val = kirin_apb_ctrl_readl(kirin_pcie, SOC_PCIECTRL_CTRL12_ADDR);
> +       val |= (0x1 << 2);
> +       kirin_apb_ctrl_writel(kirin_pcie, val, SOC_PCIECTRL_CTRL12_ADDR);
> +       udelay(10);
> +
> +       /* perst assert Endpoints */
> +       usleep_range(21000, 23000);
> +       ret = gpio_direction_output(kirin_pcie->gpio_id_reset[0], 1);
> +       if (ret)
> +               goto close_clk;
> +
> +       ret = gpio_direction_output(kirin_pcie->gpio_id_reset[1], 1);
> +       if (ret)
> +               goto close_clk;
> +
> +       ret = gpio_direction_output(kirin_pcie->gpio_id_reset[2], 1);
> +       if (ret)
> +               goto close_clk;
> +
> +       ret = gpio_direction_output(kirin_pcie->gpio_id_reset[3], 1);
> +       if (ret)
> +               goto close_clk;
> +
> +       usleep_range(10000, 11000);
> +
> +       ret = is_pipe_clk_stable(kirin_pcie);
> +       if (!ret)
> +               goto close_clk;
> +
> +       kirin970_pcie_set_eyeparam(kirin_pcie);
> +
> +       ret = kirin970_pcie_noc_power(kirin_pcie, false);
> +       if (ret)
> +               goto close_clk;
> +
> +       return 0;
> +close_clk:
> +       kirin_pcie_clk_ctrl(kirin_pcie, false);
> +       return ret;
> +}
> +
> +static int kirin960_pcie_power_on(struct kirin_pcie *kirin_pcie)
>  {
>         int ret;
>
> @@ -282,9 +957,9 @@ static int kirin_pcie_power_on(struct kirin_pcie *kirin_pcie)
>                 goto close_clk;
>
>         /* perst assert Endpoint */
> -       if (!gpio_request(kirin_pcie->gpio_id_reset, "pcie_perst")) {
> +       if (!gpio_request(kirin_pcie->gpio_id_reset[0], "pcie_perst")) {
>                 usleep_range(REF_2_PERST_MIN, REF_2_PERST_MAX);
> -               ret = gpio_direction_output(kirin_pcie->gpio_id_reset, 1);
> +               ret = gpio_direction_output(kirin_pcie->gpio_id_reset[0], 1);
>                 if (ret)
>                         goto close_clk;
>                 usleep_range(PERST_2_ACCESS_MIN, PERST_2_ACCESS_MAX);
> @@ -419,11 +1094,29 @@ static const struct dw_pcie_host_ops kirin_pcie_host_ops = {
>         .host_init = kirin_pcie_host_init,
>  };
>
> +struct kirin_pcie_ops kirin960_pcie_ops = {
> +       .get_resource = kirin960_pcie_get_resource,
> +       .power_on = kirin960_pcie_power_on,
> +};
> +
> +struct kirin_pcie_ops kirin970_pcie_ops = {
> +       .get_resource = kirin970_pcie_get_resource,
> +       .power_on = kirin970_pcie_power_on,
> +};
> +
> +static const struct of_device_id kirin_pcie_match[] = {
> +       { .compatible = "hisilicon,kirin960-pcie", .data = &kirin960_pcie_ops },
> +       { .compatible = "hisilicon,kirin970-pcie", .data = &kirin970_pcie_ops },
> +       {},
> +};
> +
>  static int kirin_pcie_probe(struct platform_device *pdev)
>  {
>         struct device *dev = &pdev->dev;
>         struct kirin_pcie *kirin_pcie;
>         struct dw_pcie *pci;
> +       const struct of_device_id *of_id;
> +       struct kirin_pcie_ops *ops;
>         int ret;
>
>         if (!dev->of_node) {
> @@ -431,6 +1124,9 @@ static int kirin_pcie_probe(struct platform_device *pdev)
>                 return -EINVAL;
>         }
>
> +       of_id = of_match_node(kirin_pcie_match, dev->of_node);
> +       ops = (struct kirin_pcie_ops *)of_id->data;

of_device_get_match_data()

> +
>         kirin_pcie = devm_kzalloc(dev, sizeof(struct kirin_pcie), GFP_KERNEL);
>         if (!kirin_pcie)
>                 return -ENOMEM;
> @@ -448,20 +1144,20 @@ static int kirin_pcie_probe(struct platform_device *pdev)
>         if (ret)
>                 return ret;
>
> -       ret = kirin_pcie_get_resource(kirin_pcie, pdev);
> +       ret = ops->get_resource(kirin_pcie, pdev);
>         if (ret)
>                 return ret;
>
> -       kirin_pcie->gpio_id_reset = of_get_named_gpio(dev->of_node,
> +       kirin_pcie->gpio_id_reset[0] = of_get_named_gpio(dev->of_node,
>                                                       "reset-gpios", 0);
> -       if (kirin_pcie->gpio_id_reset == -EPROBE_DEFER) {
> +       if (kirin_pcie->gpio_id_reset[0] == -EPROBE_DEFER) {
>                 return -EPROBE_DEFER;
> -       } else if (!gpio_is_valid(kirin_pcie->gpio_id_reset)) {
> +       } else if (!gpio_is_valid(kirin_pcie->gpio_id_reset[0])) {
>                 dev_err(dev, "unable to get a valid gpio pin\n");
>                 return -ENODEV;
>         }
>
> -       ret = kirin_pcie_power_on(kirin_pcie);
> +       ret = ops->power_on(kirin_pcie);
>         if (ret)
>                 return ret;
>
> @@ -470,11 +1166,6 @@ static int kirin_pcie_probe(struct platform_device *pdev)
>         return dw_pcie_host_init(&pci->pp);
>  }
>
> -static const struct of_device_id kirin_pcie_match[] = {
> -       { .compatible = "hisilicon,kirin960-pcie" },
> -       {},
> -};
> -
>  static struct platform_driver kirin_pcie_driver = {
>         .probe                  = kirin_pcie_probe,
>         .driver                 = {
> --
> 2.29.2
>



[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux