From: Richard Zhu Date: Thu, 25 Dec 2014 06:30:38 +0000 (+0800) Subject: MLK-10058-3 arm: gpc: add pcie phy power gpc operations X-Git-Tag: C0P2-H0.0--20200415~4264 X-Git-Url: https://git.somdevices.com/?a=commitdiff_plain;h=aad8d7f984719f48e86ffd34a5c31d7a00369a84;p=linux.git MLK-10058-3 arm: gpc: add pcie phy power gpc operations 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 (cherry picked from commit 2a7df81caf4c63044739f974e5ce3766412dccb2) --- diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 873fbc4429f9..f02722836936 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -26,6 +26,10 @@ #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); }