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

From: Rob Herring
Date: Wed Feb 03 2021 - 09:37:01 EST


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
>