summaryrefslogtreecommitdiff
path: root/drivers/pci/dwc/pci-imx6.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/dwc/pci-imx6.c')
-rw-r--r--drivers/pci/dwc/pci-imx6.c199
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,