MLK-16817-2 PCI: imx: enable the pm on imx8qm/qxp
authorRichard Zhu <hongxing.zhu@nxp.com>
Tue, 14 Nov 2017 05:36:31 +0000 (13:36 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 20:46:58 +0000 (15:46 -0500)
Enable the pcie pm on imx8qm/qxp

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
drivers/clk/imx/clk-imx8qm.c
drivers/pci/host/pci-imx6.c

index 277bcce..4bc8330 100644 (file)
@@ -878,7 +878,7 @@ static int imx8qm_clk_probe(struct platform_device *pdev)
        clks[IMX8QM_HSIO_PCIE_B_SLV_AXI_CLK] = imx_clk_gate2_scu("hsio_pcieB_slv_axi_clk", "axi_hsio_clk_root", LPCG_ADDR(HSIO_PCIE_X1_LPCG), 20, FUNCTION_NAME(PD_HSIO_PCIE_B));
        clks[IMX8QM_HSIO_PCIE_B_DBI_AXI_CLK] = imx_clk_gate2_scu("hsio_pcieB_dbi_axi_clk", "axi_hsio_clk_root", LPCG_ADDR(HSIO_PCIE_X1_LPCG), 24, FUNCTION_NAME(PD_HSIO_PCIE_B));
        clks[IMX8QM_HSIO_PCIE_X1_PER_CLK] = imx_clk_gate2_scu("hsio_pcie_x1_per_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_PCIE_X1_CRR3_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_B));
-       clks[IMX8QM_HSIO_PCIE_X2_PER_CLK] = imx_clk_gate2_scu("hsio_pcie_x2_per_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_PCIE_X2_CRR2_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_B));
+       clks[IMX8QM_HSIO_PCIE_X2_PER_CLK] = imx_clk_gate2_scu("hsio_pcie_x2_per_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_PCIE_X2_CRR2_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_A));
        clks[IMX8QM_HSIO_SATA_PER_CLK] = imx_clk_gate2_scu("hsio_sata_per_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_SATA_CRR4_LPCG), 16, FUNCTION_NAME(PD_HSIO_SATA_0));
        clks[IMX8QM_HSIO_PHY_X1_PER_CLK] = imx_clk_gate2_scu("hsio_phy_x1_per_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_PHY_X1_CRR1_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_B));
        clks[IMX8QM_HSIO_PHY_X2_PER_CLK] = imx_clk_gate2_scu("hsio_phy_x2_per_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_PHY_X2_CRR0_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_A));
index 5893f61..850c8a3 100644 (file)
@@ -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,