diff options
Diffstat (limited to 'drivers/pci/dwc')
-rw-r--r-- | drivers/pci/dwc/pci-imx6.c | 199 |
1 files changed, 137 insertions, 62 deletions
diff --git a/drivers/pci/dwc/pci-imx6.c b/drivers/pci/dwc/pci-imx6.c index 9242d211c24b..950a014984e4 100644 --- a/drivers/pci/dwc/pci-imx6.c +++ b/drivers/pci/dwc/pci-imx6.c @@ -78,6 +78,10 @@ struct imx_pcie { struct clk *pcie_bus; struct clk *pcie_phy; struct clk *pcie_inbound_axi; + struct clk *pciex2_per; + struct clk *pcie_per; + struct clk *phy_per; + struct clk *misc_per; struct clk *pcie; struct clk *pcie_ext; struct clk *pcie_ext_src; @@ -310,6 +314,10 @@ struct imx_pcie { #define IMX8MM_GPR_PCIE_POWER_OFF BIT(17) #define IMX8MM_GPR_PCIE_SSC_EN BIT(16) +static void pci_imx_clk_disable(struct device *dev); +static void pci_imx_clk_enable(struct imx_pcie *imx_pcie); +static void pci_imx_ltssm_disable(struct device *dev); + static int pcie_phy_poll_ack(struct imx_pcie *imx_pcie, int exp_val) { struct dw_pcie *pci = imx_pcie->pci; @@ -526,21 +534,23 @@ static void imx_pcie_assert_core_reset(struct imx_pcie *imx_pcie) regmap_update_bits(imx_pcie->reg_src, 0x2c, BIT(2), BIT(2)); break; case IMX8QXP: - val = IMX8QM_CSR_PCIEB_OFFSET; - regmap_update_bits(imx_pcie->iomuxc_gpr, - val + IMX8QM_CSR_PCIE_CTRL2_OFFSET, - IMX8QM_CTRL_BUTTON_RST_N, - IMX8QM_CTRL_BUTTON_RST_N); - regmap_update_bits(imx_pcie->iomuxc_gpr, - val + IMX8QM_CSR_PCIE_CTRL2_OFFSET, - IMX8QM_CTRL_PERST_N, - IMX8QM_CTRL_PERST_N); - regmap_update_bits(imx_pcie->iomuxc_gpr, - val + IMX8QM_CSR_PCIE_CTRL2_OFFSET, - IMX8QM_CTRL_POWER_UP_RST_N, - IMX8QM_CTRL_POWER_UP_RST_N); + pci_imx_clk_enable(imx_pcie); + val = IMX8QM_CSR_PCIEB_OFFSET; + regmap_update_bits(imx_pcie->iomuxc_gpr, + val + IMX8QM_CSR_PCIE_CTRL2_OFFSET, + IMX8QM_CTRL_BUTTON_RST_N, + IMX8QM_CTRL_BUTTON_RST_N); + regmap_update_bits(imx_pcie->iomuxc_gpr, + val + IMX8QM_CSR_PCIE_CTRL2_OFFSET, + IMX8QM_CTRL_PERST_N, + IMX8QM_CTRL_PERST_N); + regmap_update_bits(imx_pcie->iomuxc_gpr, + val + IMX8QM_CSR_PCIE_CTRL2_OFFSET, + IMX8QM_CTRL_POWER_UP_RST_N, + IMX8QM_CTRL_POWER_UP_RST_N); break; case IMX8QM: + pci_imx_clk_enable(imx_pcie); for (i = 0; i <= imx_pcie->ctrl_id; i++) { val = IMX8QM_CSR_PCIEA_OFFSET + i * SZ_64K; regmap_update_bits(imx_pcie->iomuxc_gpr, @@ -637,15 +647,88 @@ static int imx_pcie_enable_ref_clk(struct imx_pcie *imx_pcie) IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN); break; - case IMX8QXP: case IMX8QM: + case IMX8QXP: ret = clk_prepare_enable(imx_pcie->pcie_inbound_axi); - if (ret) + if (ret) { dev_err(dev, "unable to enable pcie_axi clock\n"); + return ret; + } + ret = clk_prepare_enable(imx_pcie->pcie_per); + if (ret) { + dev_err(dev, "unable to enable pcie_per clock\n"); + goto err_pcie_per; + } + ret = clk_prepare_enable(imx_pcie->phy_per); + if (unlikely(ret)) { + dev_err(dev, "unable to enable phy per clock\n"); + goto err_phy_per; + } + ret = clk_prepare_enable(imx_pcie->misc_per); + if (unlikely(ret)) { + dev_err(dev, "unable to enable misc per clock\n"); + goto err_misc_per; + } + /* + * PCIA CSR would be touched during the initialization of the + * PCIEB of 8QM. + * Enable the PCIEA peripheral clock for this case here. + */ + if (imx_pcie->variant == IMX8QM && imx_pcie->ctrl_id == 1) { + ret = clk_prepare_enable(imx_pcie->pciex2_per); + if (unlikely(ret)) { + dev_err(dev, "can't enable pciex2 per clock\n"); + goto err_pciex2_per; + } + } + break; + default: break; } return ret; +err_pciex2_per: + clk_disable_unprepare(imx_pcie->misc_per); +err_misc_per: + clk_disable_unprepare(imx_pcie->phy_per); +err_phy_per: + clk_disable_unprepare(imx_pcie->pcie_per); +err_pcie_per: + clk_disable_unprepare(imx_pcie->pcie_inbound_axi); + return ret; +} + +static void pci_imx_clk_enable(struct imx_pcie *imx_pcie) +{ + int ret; + struct dw_pcie *pci = imx_pcie->pci; + struct device *dev = pci->dev; + + ret = clk_prepare_enable(imx_pcie->pcie_phy); + if (ret) + dev_err(dev, "unable to enable pcie_phy clock\n"); + + if (imx_pcie->ext_osc && (imx_pcie->variant == IMX6QP)) + clk_set_parent(imx_pcie->pcie_bus, + imx_pcie->pcie_ext_src); + ret = clk_prepare_enable(imx_pcie->pcie_bus); + if (ret) + dev_err(dev, "unable to enable pcie_bus clock\n"); + + ret = clk_prepare_enable(imx_pcie->pcie_ext); + if (ret) + dev_err(dev, "unable to enable pcie_ext clock\n"); + + ret = clk_prepare_enable(imx_pcie->pcie); + if (ret) + dev_err(dev, "unable to enable pcie clock\n"); + + ret = imx_pcie_enable_ref_clk(imx_pcie); + if (ret) + dev_err(dev, "unable to enable pcie ref clock\n"); + + /* allow the clocks to stabilize */ + udelay(200); } static int imx7d_pcie_wait_for_phy_pll_lock(struct imx_pcie *imx_pcie) @@ -765,42 +848,16 @@ static int imx_pcie_deassert_core_reset(struct imx_pcie *imx_pcie) if (imx_pcie->dis_gpiod) gpiod_set_value_cansleep(imx_pcie->dis_gpiod, 0); - ret = clk_prepare_enable(imx_pcie->pcie); - if (ret) { - dev_err(dev, "unable to enable pcie clock\n"); - goto err_pcie; - } - - if (imx_pcie->ext_osc && (imx_pcie->variant == IMX6QP)) - clk_set_parent(imx_pcie->pcie_bus, - imx_pcie->pcie_ext_src); - ret = clk_prepare_enable(imx_pcie->pcie_bus); - if (ret) { - dev_err(dev, "unable to enable pcie_bus clock\n"); - goto err_pcie_bus; - } - - ret = clk_prepare_enable(imx_pcie->pcie_ext); - if (ret) { - dev_err(dev, "unable to enable pcie_ext clock\n"); - goto err_pcie_bus; - } - - ret = clk_prepare_enable(imx_pcie->pcie_phy); - if (ret) { - dev_err(dev, "unable to enable pcie_phy clock\n"); - goto err_pcie_phy; - } - - ret = imx_pcie_enable_ref_clk(imx_pcie); - if (ret) { - dev_err(dev, "unable to enable pcie ref clock\n"); - goto err_ref_clk; + switch (imx_pcie->variant) { + case IMX8QXP: + case IMX8QM: + /* ClKs had been enabled */ + break; + default: + pci_imx_clk_enable(imx_pcie); + break; } - /* allow the clocks to stabilize */ - udelay(200); - switch (imx_pcie->variant) { case IMX6SX: regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR5, @@ -971,13 +1028,7 @@ static int imx_pcie_deassert_core_reset(struct imx_pcie *imx_pcie) if (ret == 0) return ret; -err_ref_clk: - clk_disable_unprepare(imx_pcie->pcie_phy); -err_pcie_phy: - clk_disable_unprepare(imx_pcie->pcie_bus); -err_pcie_bus: - clk_disable_unprepare(imx_pcie->pcie); -err_pcie: + pci_imx_clk_disable(dev); if (imx_pcie->vpcie && regulator_is_enabled(imx_pcie->vpcie) > 0) { ret = regulator_disable(imx_pcie->vpcie); if (ret) @@ -1497,9 +1548,14 @@ static void pci_imx_clk_disable(struct device *dev) IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN, 0); break; - case IMX8QXP: case IMX8QM: + if (imx_pcie->ctrl_id == 1) + clk_disable_unprepare(imx_pcie->pciex2_per); + case IMX8QXP: + clk_disable_unprepare(imx_pcie->pcie_per); clk_disable_unprepare(imx_pcie->pcie_inbound_axi); + clk_disable_unprepare(imx_pcie->phy_per); + clk_disable_unprepare(imx_pcie->misc_per); break; } } @@ -2081,8 +2137,7 @@ static int pci_imx_suspend_noirq(struct device *dev) IMX6Q_GPR1_PCIE_TEST_PD, IMX6Q_GPR1_PCIE_TEST_PD); } else { - pm_runtime_put_sync(dev); - + pci_imx_ltssm_disable(dev); pci_imx_clk_disable(dev); imx_pcie_phy_pwr_dn(imx_pcie); @@ -2151,9 +2206,6 @@ static int pci_imx_resume_noirq(struct device *dev) regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_TEST_PD, 0); } else { - pm_runtime_get_sync(dev); - - pci_imx_ltssm_disable(dev); imx_pcie_assert_core_reset(imx_pcie); imx_pcie_init_phy(imx_pcie); ret = imx_pcie_deassert_core_reset(imx_pcie); @@ -2499,6 +2551,29 @@ static int imx_pcie_probe(struct platform_device *pdev) ("fsl,imx6sx-iomuxc-gpr"); } else if (imx_pcie->variant == IMX8QM || imx_pcie->variant == IMX8QXP) { + imx_pcie->pcie_per = devm_clk_get(dev, "pcie_per"); + if (IS_ERR(imx_pcie->pcie_per)) { + dev_err(dev, "pcie_per clock source missing or invalid\n"); + return PTR_ERR(imx_pcie->pcie_per); + } + imx_pcie->phy_per = devm_clk_get(dev, "phy_per"); + if (IS_ERR(imx_pcie->phy_per)) { + dev_err(dev, "failed to get per clock.\n"); + return PTR_ERR(imx_pcie->phy_per); + } + imx_pcie->misc_per = devm_clk_get(dev, "misc_per"); + if (IS_ERR(imx_pcie->misc_per)) { + dev_err(dev, "failed to get per clock.\n"); + return PTR_ERR(imx_pcie->misc_per); + } + if (imx_pcie->variant == IMX8QM && imx_pcie->ctrl_id == 1) { + imx_pcie->pciex2_per = devm_clk_get(dev, "pciex2_per"); + if (IS_ERR(imx_pcie->pciex2_per)) { + dev_err(dev, "can't get pciex2_per.\n"); + return PTR_ERR(imx_pcie->pciex2_per); + } + } + imx_pcie->iomuxc_gpr = syscon_regmap_lookup_by_phandle(node, "hsio"); imx_pcie->pcie_inbound_axi = devm_clk_get(&pdev->dev, |