summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorAnson Huang <Anson.Huang@nxp.com>2016-01-28 22:21:52 +0800
committerRobin Gong <yibin.gong@nxp.com>2016-02-18 11:04:18 +0800
commitc37c9082141177f7c26db59279c0cde7acd85d60 (patch)
treec4911e3171f9be985df0d3a400c2df6e8eb5c918 /arch
parentb63b738ca6f850c119ef0ea6b3f5f18b1ad6b64c (diff)
MLK-12375 ARM: imx: improve ARM power up time for i.MX6UL TO1.1
On i.MX6UL, PGC_CPU_PUPSCR_SW's counter uses IPG/2048 as clock source, as IPG is at 1.5MHz during low power idle, so the power up time can be up to 1.3mS which is too long for idle. Since TO1.1, design team re-define the bit[5], if this bit is set to 1, the clock will be IPG/32, ~22us, enable this function for TO1.1, the latency value for low power idle needs to be adjusted accordingly. Signed-off-by: Anson Huang <Anson.Huang@nxp.com> Signed-off-by: Robin Gong <yibin.gong@nxp.com> (cherry picked from commit 1036fbdba0111d7fa21acb810e01907db8997a31)
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-imx/common.h1
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6ul.c51
-rw-r--r--arch/arm/mach-imx/gpc.c36
3 files changed, 87 insertions, 1 deletions
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 246415b66321..d8d2620f1ac6 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -128,6 +128,7 @@ void imx7_pm_map_io(void);
void imx_src_init(void);
void imx_gpc_pre_suspend(bool arm_power_off);
void imx_gpc_post_resume(void);
+void imx_gpc_switch_pupscr_clk(bool flag);
unsigned int imx_gpc_is_mf_mix_off(void);
void imx_gpcv2_pre_suspend(bool arm_power_off);
void imx_gpcv2_post_resume(void);
diff --git a/arch/arm/mach-imx/cpuidle-imx6ul.c b/arch/arm/mach-imx/cpuidle-imx6ul.c
index 8046bd6f8b34..6533c792c852 100644
--- a/arch/arm/mach-imx/cpuidle-imx6ul.c
+++ b/arch/arm/mach-imx/cpuidle-imx6ul.c
@@ -97,6 +97,15 @@ static int imx6ul_enter_wait(struct cpuidle_device *dev,
if ((index == 1) || ((mode != BUS_FREQ_LOW) && index == 2)) {
cpu_do_idle();
} else {
+ /*
+ * i.MX6UL TO1.0 ARM power up uses IPG/2048 as clock source,
+ * from TO1.1, PGC_CPU_PUPSCR bit [5] is re-defined to switch
+ * clock to IPG/32, enable this bit to speed up the ARM power
+ * up process in low power idle case.
+ */
+ if (cpu_is_imx6ul() && imx_get_soc_revision() >
+ IMX_CHIP_REVISION_1_0)
+ imx_gpc_switch_pupscr_clk(true);
/* Need to notify there is a cpu pm operation. */
cpu_pm_enter();
cpu_cluster_pm_enter();
@@ -106,6 +115,10 @@ static int imx6ul_enter_wait(struct cpuidle_device *dev,
cpu_cluster_pm_exit();
cpu_pm_exit();
imx6_enable_rbc(false);
+
+ if (cpu_is_imx6ul() && imx_get_soc_revision() >
+ IMX_CHIP_REVISION_1_0)
+ imx_gpc_switch_pupscr_clk(false);
}
imx6q_set_lpm(WAIT_CLOCKED);
@@ -113,6 +126,38 @@ static int imx6ul_enter_wait(struct cpuidle_device *dev,
return index;
}
+static struct cpuidle_driver imx6ul_cpuidle_driver_v2 = {
+ .name = "imx6ul_cpuidle",
+ .owner = THIS_MODULE,
+ .states = {
+ /* WFI */
+ ARM_CPUIDLE_WFI_STATE,
+ /* WAIT */
+ {
+ .exit_latency = 50,
+ .target_residency = 75,
+ .enter = imx6ul_enter_wait,
+ .name = "WAIT",
+ .desc = "Clock off",
+ },
+ /* LOW POWER IDLE */
+ {
+ /*
+ * RBC 130us + ARM gating 43us + RBC clear 65us
+ * + PLL2 relock 450us and some margin, here set
+ * it to 700us.
+ */
+ .exit_latency = 700,
+ .target_residency = 1000,
+ .enter = imx6ul_enter_wait,
+ .name = "LOW-POWER-IDLE",
+ .desc = "ARM power off",
+ }
+ },
+ .state_count = 3,
+ .safe_state_index = 0,
+};
+
static struct cpuidle_driver imx6ul_cpuidle_driver = {
.name = "imx6ul_cpuidle",
.owner = THIS_MODULE,
@@ -252,5 +297,9 @@ int __init imx6ul_cpuidle_init(void)
*/
val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG1);
- return cpuidle_register(&imx6ul_cpuidle_driver, NULL);
+ /* ARM power up time is reduced since TO1.1 */
+ if (imx_get_soc_revision() > IMX_CHIP_REVISION_1_0)
+ return cpuidle_register(&imx6ul_cpuidle_driver_v2, NULL);
+ else
+ return cpuidle_register(&imx6ul_cpuidle_driver, NULL);
}
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 568e4bc4ccab..250029da9e7c 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -415,6 +415,42 @@ int imx_gpc_mf_request_on(unsigned int irq, unsigned int on)
}
EXPORT_SYMBOL_GPL(imx_gpc_mf_request_on);
+void imx_gpc_switch_pupscr_clk(bool flag)
+{
+ static u32 pupscr_sw2iso, pupscr_sw;
+ u32 ratio, pupscr = readl_relaxed(gpc_base + GPC_PGC_CPU_PUPSCR);
+
+ if (flag) {
+ /* save the init clock setting IPG/2048 for IPG@66Mhz */
+ pupscr_sw2iso = (pupscr >> GPC_PGC_CPU_SW2ISO_SHIFT) &
+ GPC_PGC_CPU_SW2ISO_MASK;
+ pupscr_sw = (pupscr >> GPC_PGC_CPU_SW_SHIFT) &
+ GPC_PGC_CPU_SW_MASK;
+ /*
+ * i.MX6UL TO1.0 ARM power up uses IPG/2048 as clock source,
+ * from TO1.1, PGC_CPU_PUPSCR bit [5] is re-defined to switch
+ * clock to IPG/32, enable this bit to speed up the ARM power
+ * up process in low power idle case(IPG@1.5Mhz). So the sw and
+ * sw2iso need to be adjusted as below:
+ * sw_new(sw2iso_new) = (2048 * 1.5 / 66 * 32) * sw(sw2iso)
+ */
+ ratio = 3072 / (66 * 32);
+ pupscr &= ~(GPC_PGC_CPU_SW_MASK << GPC_PGC_CPU_SW_SHIFT |
+ GPC_PGC_CPU_SW2ISO_MASK << GPC_PGC_CPU_SW2ISO_SHIFT);
+ pupscr |= (ratio * pupscr_sw + 1) << GPC_PGC_CPU_SW_SHIFT |
+ 1 << 5 | (ratio * pupscr_sw2iso + 1) <<
+ GPC_PGC_CPU_SW2ISO_SHIFT;
+ writel_relaxed(pupscr, gpc_base + GPC_PGC_CPU_PUPSCR);
+ } else {
+ /* restore back after exit from low power idle */
+ pupscr &= ~(GPC_PGC_CPU_SW_MASK << GPC_PGC_CPU_SW_SHIFT |
+ GPC_PGC_CPU_SW2ISO_MASK << GPC_PGC_CPU_SW2ISO_SHIFT);
+ pupscr |= pupscr_sw << GPC_PGC_CPU_SW_SHIFT |
+ pupscr_sw2iso << GPC_PGC_CPU_SW2ISO_SHIFT;
+ writel_relaxed(pupscr, gpc_base + GPC_PGC_CPU_PUPSCR);
+ }
+}
+
static int imx_pcie_regulator_notify(struct notifier_block *nb,
unsigned long event,
void *ignored)