MLK-10058-3 arm: gpc: add pcie phy power gpc operations
authorRichard Zhu <Richard.Zhu@freescale.com>
Thu, 25 Dec 2014 06:30:38 +0000 (14:30 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 19:48:39 +0000 (14:48 -0500)
For PCIe module on i.mx6sx, some GPC operations would
be mandatory required when PCIe PHY is powered on/off.
So we need update gpc driver for the new requirements.
We implement it by regulator notify framwork in gpc driver.
NOTE:
make sure gpc driver is ready before PCIe driver is probed.
Otherwise, cause system hang during PCIe driver probe,
because the notify NOT installed ready and the gpc will
NOT power on PCIe.

Signed-off-by: Richard Zhu <Richard.Zhu@freescale.com>
(cherry picked from commit 2a7df81caf4c63044739f974e5ce3766412dccb2)

arch/arm/mach-imx/gpc.c

index 873fbc4..f027228 100644 (file)
 #include "hardware.h"
 
 #define GPC_CNTR               0x000
+#define GPC_CNTR_PCIE_PHY_PDU_SHIFT    0x7
+#define GPC_CNTR_PCIE_PHY_PDN_SHIFT    0x6
+#define PGC_PCIE_PHY_CTRL              0x200
+#define PGC_PCIE_PHY_PDN_EN            0x1
 #define GPC_IMR1               0x008
 #define GPC_PGC_MF_PDN         0x220
 #define GPC_PGC_GPU_PDN                0x260
@@ -70,6 +74,7 @@ static u32 gpc_saved_imrs[IMR_NUM];
 static u32 gpc_mf_irqs[IMR_NUM];
 static u32 gpc_mf_request_on[IMR_NUM];
 static DEFINE_SPINLOCK(gpc_lock);
+static struct notifier_block nb_pcie;
 
 void imx_gpc_add_m4_wake_up_irq(u32 hwirq, bool enable)
 {
@@ -370,6 +375,30 @@ int imx_gpc_mf_request_on(unsigned int irq, unsigned int on)
 }
 EXPORT_SYMBOL_GPL(imx_gpc_mf_request_on);
 
+static int imx_pcie_regulator_notify(struct notifier_block *nb,
+                                       unsigned long event,
+                                       void *ignored)
+{
+       u32 value = readl_relaxed(gpc_base + GPC_CNTR);
+
+       switch (event) {
+       case REGULATOR_EVENT_PRE_DO_ENABLE:
+               value |= 1 << GPC_CNTR_PCIE_PHY_PDU_SHIFT;
+               writel_relaxed(value, gpc_base + GPC_CNTR);
+               break;
+       case REGULATOR_EVENT_PRE_DO_DISABLE:
+               value |= 1 << GPC_CNTR_PCIE_PHY_PDN_SHIFT;
+               writel_relaxed(value, gpc_base + GPC_CNTR);
+               writel_relaxed(PGC_PCIE_PHY_PDN_EN,
+                               gpc_base + PGC_PCIE_PHY_CTRL);
+               break;
+       default:
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
 static int __init imx_gpc_init(struct device_node *node,
                               struct device_node *parent)
 {
@@ -658,6 +687,25 @@ static int imx_gpc_probe(struct platform_device *pdev)
        if (bypass)
                regulator_allow_bypass(pu_reg, true);
 
+       if (cpu_is_imx6sx()) {
+               struct regulator *pcie_reg;
+
+               pcie_reg = devm_regulator_get(&pdev->dev, "pcie-phy");
+               if (IS_ERR(pcie_reg)) {
+                       ret = PTR_ERR(pcie_reg);
+                       dev_info(&pdev->dev, "pcie regulator not ready.\n");
+                       return ret;
+               }
+               nb_pcie.notifier_call = &imx_pcie_regulator_notify;
+
+               ret = regulator_register_notifier(pcie_reg, &nb_pcie);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "pcie regulator notifier request failed\n");
+                       return ret;
+               }
+       }
+
        return imx_gpc_genpd_init(&pdev->dev, pu_reg);
 }