diff options
author | Richard Zhu <hongxing.zhu@nxp.com> | 2017-11-14 13:36:31 +0800 |
---|---|---|
committer | Leonard Crestez <leonard.crestez@nxp.com> | 2018-08-24 12:41:33 +0300 |
commit | edd70b285e0e663fe93774acfd04839c88236ff3 (patch) | |
tree | b1bb2a31887ee6890587be0c15ffae1deba980d6 /drivers/pci/host | |
parent | acaa1ae88c9e2765b6371e5cba999d7bcbd9d7c0 (diff) |
MLK-16817-2 PCI: imx: enable the pm on imx8qm/qxp
Enable the pcie pm on imx8qm/qxp
Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
Diffstat (limited to 'drivers/pci/host')
-rw-r--r-- | drivers/pci/host/pci-imx6.c | 60 |
1 files changed, 54 insertions, 6 deletions
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index 5893f613fb6d..850c8a39d3ab 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -72,6 +72,7 @@ struct imx6_pcie { struct clk *pcie_bus; struct clk *pcie_inbound_axi; struct clk *pcie_phy; + struct clk *pcie_per; struct clk *pcie; struct clk *pcie_ext_src; struct regmap *iomuxc_gpr; @@ -180,10 +181,13 @@ struct imx6_pcie { #define IMX8QM_LPCG_PHY_PCG1 BIT(5) #define IMX8QM_CTRL_LTSSM_ENABLE BIT(4) +#define IMX8QM_CTRL_READY_ENTR_L23 BIT(5) +#define IMX8QM_CTRL_PM_XMT_TURNOFF BIT(9) #define IMX8QM_CTRL_BUTTON_RST_N BIT(21) #define IMX8QM_CTRL_PERST_N BIT(22) #define IMX8QM_CTRL_POWER_UP_RST_N BIT(23) +#define IMX8QM_CTRL_STTS0_PM_LINKST_IN_L2 BIT(13) #define IMX8QM_CTRL_STTS0_PM_REQ_CORE_RST BIT(19) #define IMX8QM_STTS0_LANE0_TX_PLL_LOCK BIT(4) #define IMX8QM_STTS0_LANE1_TX_PLL_LOCK BIT(12) @@ -526,6 +530,13 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) dev_err(dev, "unable to enable pcie_axi clock\n"); break; } + ret = clk_prepare_enable(imx6_pcie->pcie_per); + if (ret) { + dev_err(dev, "unable to enable pcie_per clock\n"); + clk_disable_unprepare(imx6_pcie->pcie_inbound_axi); + break; + } + break; } @@ -1207,6 +1218,7 @@ static void pci_imx_clk_disable(struct device *dev) break; case IMX8QXP: case IMX8QM: + clk_disable_unprepare(imx6_pcie->pcie_per); clk_disable_unprepare(imx6_pcie->pcie_inbound_axi); break; } @@ -1605,7 +1617,8 @@ static void imx6_pcie_setup_ep(struct pcie_port *pp) /* PM_TURN_OFF */ static void pci_imx_pm_turn_off(struct imx6_pcie *imx6_pcie) { - u32 val; + int i; + u32 dst, val; struct pcie_port *pp = &imx6_pcie->pp; struct device *dev = pp->dev; @@ -1628,19 +1641,45 @@ static void pci_imx_pm_turn_off(struct imx6_pcie *imx6_pcie) case IMX7D: case IMX8MQ: if (imx6_pcie->ctrl_id == 0) - val = IMX8MQ_SRC_PCIEPHY_RCR_OFFSET; + dst = IMX8MQ_SRC_PCIEPHY_RCR_OFFSET; else - val = IMX8MQ_SRC_PCIE2PHY_RCR_OFFSET; - regmap_update_bits(imx6_pcie->reg_src, val, + dst = IMX8MQ_SRC_PCIE2PHY_RCR_OFFSET; + regmap_update_bits(imx6_pcie->reg_src, dst, IMX8MQ_PCIE_CTRL_APPS_TURNOFF, IMX8MQ_PCIE_CTRL_APPS_TURNOFF); - regmap_update_bits(imx6_pcie->reg_src, val, + regmap_update_bits(imx6_pcie->reg_src, dst, IMX8MQ_PCIE_CTRL_APPS_TURNOFF, 0); break; - case IMX6Q: case IMX8QXP: case IMX8QM: + dst = IMX8QM_CSR_PCIEA_OFFSET + imx6_pcie->ctrl_id * SZ_64K; + regmap_update_bits(imx6_pcie->iomuxc_gpr, + dst + IMX8QM_CSR_PCIE_CTRL2_OFFSET, + IMX8QM_CTRL_PM_XMT_TURNOFF, + IMX8QM_CTRL_PM_XMT_TURNOFF); + regmap_update_bits(imx6_pcie->iomuxc_gpr, + dst + IMX8QM_CSR_PCIE_CTRL2_OFFSET, + IMX8QM_CTRL_PM_XMT_TURNOFF, + 0); + regmap_update_bits(imx6_pcie->iomuxc_gpr, + dst + IMX8QM_CSR_PCIE_CTRL2_OFFSET, + IMX8QM_CTRL_READY_ENTR_L23, + IMX8QM_CTRL_READY_ENTR_L23); + /* check the L2 is entered or not. */ + for (i = 0; i < 10000; i++) { + regmap_read(imx6_pcie->iomuxc_gpr, + dst + IMX8QM_CSR_PCIE_STTS0_OFFSET, + &val); + if (val & IMX8QM_CTRL_STTS0_PM_LINKST_IN_L2) + break; + udelay(10); + } + if ((val & IMX8QM_CTRL_STTS0_PM_LINKST_IN_L2) == 0) + dev_err(dev, "PCIE%d can't enter into L2.\n", + imx6_pcie->ctrl_id); + break; + case IMX6Q: dev_info(dev, "Info: don't support pm_turn_off yet.\n"); break; } @@ -1715,6 +1754,9 @@ static void pci_imx_ltssm_disable(struct device *dev) regmap_update_bits(imx6_pcie->iomuxc_gpr, val + IMX8QM_CSR_PCIE_CTRL2_OFFSET, IMX8QM_CTRL_LTSSM_ENABLE, 0); + regmap_update_bits(imx6_pcie->iomuxc_gpr, + val + IMX8QM_CSR_PCIE_CTRL2_OFFSET, + IMX8QM_CTRL_READY_ENTR_L23, 0); break; } } @@ -1982,6 +2024,12 @@ static int imx6_pcie_probe(struct platform_device *pdev) ("fsl,imx6sx-iomuxc-gpr"); } else if (imx6_pcie->variant == IMX8QM || imx6_pcie->variant == IMX8QXP) { + imx6_pcie->pcie_per = devm_clk_get(dev, "pcie_per"); + if (IS_ERR(imx6_pcie->pcie_per)) { + dev_err(dev, "pcie_per clock source missing or invalid\n"); + return PTR_ERR(imx6_pcie->pcie_per); + } + imx6_pcie->iomuxc_gpr = syscon_regmap_lookup_by_phandle(node, "hsio"); imx6_pcie->pcie_inbound_axi = devm_clk_get(&pdev->dev, |