diff options
author | Anson Huang <b20788@freescale.com> | 2015-04-07 14:32:09 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2015-05-08 16:34:11 +0800 |
commit | 39601d70efcf49a91da01be7dff6e8c0d4b061ad (patch) | |
tree | ad44fcf06eca075194e627b64fa5cce9eacdfde1 /arch/arm/mach-imx/gpc.c | |
parent | b041b5f575a521d38ee021970a1bd51444aeb59b (diff) |
MLK-10591-2 ARM: imx: add necessary delay for gpc power switch
Per design team's requirement, when GPC switch power req is
assert and self-clear, need to add delay to make sure power
switch is actually up, the delay value can be got from below:
delay = 2us * 66MHz / IPG_RATE,
here we add 2us margin to make it more reliable, currently only
display mix and pu mix are a power switch.
Signed-off-by: Anson Huang <b20788@freescale.com>
Diffstat (limited to 'arch/arm/mach-imx/gpc.c')
-rw-r--r-- | arch/arm/mach-imx/gpc.c | 41 |
1 files changed, 31 insertions, 10 deletions
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 03731b7a90f3..983bf3319866 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -53,6 +53,8 @@ #define GPU_VPU_PDN_REQ BIT(0) #define GPC_CLK_MAX 10 +#define DEFAULT_IPG_RATE 66000000 +#define GPC_PU_UP_DELAY_MARGIN 2 struct pu_domain { struct generic_pm_domain base; @@ -78,6 +80,7 @@ static struct notifier_block nb_pcie; static struct pu_domain imx6q_pu_domain; static bool pu_on; /* keep always on i.mx6qp */ static void imx6q_pu_pgc_power_off(struct pu_domain *pu, bool off); +static struct clk *ipg; void imx_gpc_add_m4_wake_up_irq(u32 irq, bool enable) { @@ -363,6 +366,9 @@ static void imx6q_pu_pgc_power_off(struct pu_domain *pu, bool off) iso = val & 0x3f; iso2sw = (val >> 8) & 0x3f; + /* Wait ISO + ISO2SW IPG clock cycles */ + ndelay((iso + iso2sw) * 1000 / 66); + /* Gate off PU domain when GPU/VPU when powered down */ writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN); @@ -371,11 +377,11 @@ static void imx6q_pu_pgc_power_off(struct pu_domain *pu, bool off) val |= GPU_VPU_PDN_REQ; writel_relaxed(val, gpc_base + GPC_CNTR); - /* Wait ISO + ISO2SW IPG clock cycles */ - ndelay((iso + iso2sw) * 1000 / 66); + while (readl_relaxed(gpc_base + GPC_CNTR) & GPU_VPU_PDN_REQ) + ; } else { int i, sw, sw2iso; - u32 val; + u32 val, ipg_rate = clk_get_rate(ipg); /* Enable reset clocks for all devices in the PU domain */ for (i = 0; i < pu->num_clks; i++) @@ -389,13 +395,20 @@ static void imx6q_pu_pgc_power_off(struct pu_domain *pu, bool off) sw = val & 0x3f; sw2iso = (val >> 8) & 0x3f; + /* Wait ISO + ISO2SW IPG clock cycles */ + ndelay((sw + sw2iso) * 1000 / 66); + /* Request GPC to power up GPU/VPU */ val = readl_relaxed(gpc_base + GPC_CNTR); val |= GPU_VPU_PUP_REQ; writel_relaxed(val, gpc_base + GPC_CNTR); - /* Wait ISO + ISO2SW IPG clock cycles */ - ndelay((sw + sw2iso) * 1000 / 66); + while (readl_relaxed(gpc_base + GPC_CNTR) & GPU_VPU_PUP_REQ) + ; + + /* Wait power switch done */ + udelay(2 * DEFAULT_IPG_RATE / ipg_rate + + GPC_PU_UP_DELAY_MARGIN); /* Disable reset clocks for all devices in the PU domain */ for (i = 0; i < pu->num_clks; i++) @@ -450,6 +463,7 @@ static int imx_pm_dispmix_on(struct generic_pm_domain *genpd) struct disp_domain *disp = container_of(genpd, struct disp_domain, base); u32 val = readl_relaxed(gpc_base + GPC_CNTR); int i; + u32 ipg_rate = clk_get_rate(ipg); if ((cpu_is_imx6sl() && imx_get_soc_revision() >= IMX_CHIP_REVISION_1_2) || cpu_is_imx6sx()) { @@ -465,6 +479,10 @@ static int imx_pm_dispmix_on(struct generic_pm_domain *genpd) writel_relaxed(0x1, gpc_base + GPC_PGC_DISP_SR_OFFSET); + /* Wait power switch done */ + udelay(2 * DEFAULT_IPG_RATE / ipg_rate + + GPC_PU_UP_DELAY_MARGIN); + /* Disable reset clocks for all devices in the disp domain */ for (i = 0; i < disp->num_clks; i++) clk_disable_unprepare(disp->clk[i]); @@ -538,7 +556,7 @@ static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg) { struct clk *clk; bool is_off; - int pu_clks, disp_clks; + int pu_clks, disp_clks, ipg_clks = 1; int i = 0, k = 0; imx6q_pu_domain.base.of_node = dev->of_node; @@ -549,12 +567,12 @@ static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg) if ((cpu_is_imx6sl() && imx_get_soc_revision() >= IMX_CHIP_REVISION_1_2)) { pu_clks = 2 ; - disp_clks = 6; + disp_clks = 5; } else if (cpu_is_imx6sx()) { pu_clks = 1; - disp_clks = 8; + disp_clks = 7; } else { - pu_clks = GPC_CLK_MAX; + pu_clks = 6; disp_clks = 0; } @@ -567,8 +585,11 @@ static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg) } imx6q_pu_domain.num_clks = i; + ipg = of_clk_get(dev->of_node, pu_clks); + /* Get disp domain clks */ - for (k = 0, i = pu_clks; i < pu_clks + disp_clks ; i++, k++) { + for (k = 0, i = pu_clks + ipg_clks; i < pu_clks + ipg_clks + disp_clks; + i++, k++) { clk = of_clk_get(dev->of_node, i); if (IS_ERR(clk)) break; |