summaryrefslogtreecommitdiff
path: root/arch/arm/mach-imx/gpc.c
diff options
context:
space:
mode:
authorAnson Huang <b20788@freescale.com>2015-04-07 14:32:09 +0800
committerJason Liu <r64343@freescale.com>2015-05-08 16:34:11 +0800
commit39601d70efcf49a91da01be7dff6e8c0d4b061ad (patch)
treead44fcf06eca075194e627b64fa5cce9eacdfde1 /arch/arm/mach-imx/gpc.c
parentb041b5f575a521d38ee021970a1bd51444aeb59b (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.c41
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;