From mboxrd@z Thu Jan 1 00:00:00 1970 From: l.stach@pengutronix.de (Lucas Stach) Date: Tue, 04 Aug 2015 10:54:08 +0200 Subject: [PATCH] ARM: imx: add cpuidle support for i.mx6ul In-Reply-To: <1438705972-3082-1-git-send-email-b20788@freescale.com> References: <1438705972-3082-1-git-send-email-b20788@freescale.com> Message-ID: <1438678448.2458.26.camel@pengutronix.de> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Am Mittwoch, den 05.08.2015, 00:32 +0800 schrieb Anson Huang: > This patch introduces an independent cpuidle driver for > i.MX6UL, totally 3 levels of cpuidle are supported as below: > > 1. ARM WFI; > 2. SOC in WAIT mode; > 3. SOC in WAIT mode + ARM power off. > > Signed-off-by: Anson Huang > --- > arch/arm/mach-imx/Makefile | 1 + > arch/arm/mach-imx/cpuidle-imx6ul.c | 106 +++++++++++++++++++++++++++++++++++++ > arch/arm/mach-imx/cpuidle.h | 5 ++ > arch/arm/mach-imx/mach-imx6ul.c | 8 +++ > 4 files changed, 120 insertions(+) > create mode 100644 arch/arm/mach-imx/cpuidle-imx6ul.c > > diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile > index fb689d8..1d7df9c 100644 > --- a/arch/arm/mach-imx/Makefile > +++ b/arch/arm/mach-imx/Makefile > @@ -28,6 +28,7 @@ obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o > obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o > obj-$(CONFIG_SOC_IMX6SL) += cpuidle-imx6sl.o > obj-$(CONFIG_SOC_IMX6SX) += cpuidle-imx6sx.o > +obj-$(CONFIG_SOC_IMX6UL) += cpuidle-imx6ul.o > endif > > ifdef CONFIG_SND_IMX_SOC > diff --git a/arch/arm/mach-imx/cpuidle-imx6ul.c b/arch/arm/mach-imx/cpuidle-imx6ul.c > new file mode 100644 > index 0000000..93793a1 > --- /dev/null > +++ b/arch/arm/mach-imx/cpuidle-imx6ul.c > @@ -0,0 +1,106 @@ > +/* > + * Copyright (C) 2015 Freescale Semiconductor, Inc. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "common.h" > +#include "cpuidle.h" > + > +static int imx6ul_idle_finish(unsigned long val) > +{ > + flush_cache_all(); > + cpu_do_idle(); > + > + return 0; > +} > + > +static int imx6ul_enter_wait(struct cpuidle_device *dev, > + struct cpuidle_driver *drv, int index) > +{ > + imx6_set_lpm(WAIT_UNCLOCKED); > + > + switch (index) { > + case 1: > + cpu_do_idle(); > + break; > + case 2: > + imx6_enable_rbc(true); > + imx_gpc_set_arm_power_in_lpm(true); > + imx_set_cpu_jump(0, v7_cpu_resume); > + /* Need to notify there is a cpu pm operation. */ > + cpu_pm_enter(); > + cpu_cluster_pm_enter(); > + > + cpu_suspend(0, imx6ul_idle_finish); > + > + cpu_cluster_pm_exit(); > + cpu_pm_exit(); > + imx_gpc_set_arm_power_in_lpm(false); > + imx6_enable_rbc(false); > + break; > + default: > + break; > + } > + > + imx6_set_lpm(WAIT_CLOCKED); > + > + return index; > +} > + > +static struct cpuidle_driver imx6ul_cpuidle_driver = { > + .name = "imx6ul_cpuidle", > + .owner = THIS_MODULE, > + .states = { > + /* WFI */ > + ARM_CPUIDLE_WFI_STATE, > + /* WAIT */ > + { > + .exit_latency = 50, > + .target_residency = 75, > + .flags = CPUIDLE_FLAG_TIMER_STOP, > + .enter = imx6ul_enter_wait, > + .name = "WAIT", > + .desc = "Clock off", > + }, > + /* WAIT + ARM power off */ > + { > + /* > + * ARM gating 31us * 5 + RBC clear 65us > + * and some margin for SW execution, here set it > + * to 300us. > + */ > + .exit_latency = 300, > + .target_residency = 500, Why is ".flags = CPUIDLE_FLAG_TIMER_STOP," omitted here? > + .enter = imx6ul_enter_wait, > + .name = "LOW-POWER-IDLE", > + .desc = "ARM power off", > + }, > + }, > + .state_count = 3, > + .safe_state_index = 0, > +}; > + > +int __init imx6ul_cpuidle_init(void) > +{ > + imx6_enable_rbc(false); > + /* > + * set ARM power up/down timing to the fastest, > + * sw2iso and sw can be set to one 32K cycle = 31us > + * except for power up sw2iso which need to be > + * larger than LDO ramp up time. > + */ > + imx_gpc_set_arm_power_up_timing(2, 1); > + imx_gpc_set_arm_power_down_timing(1, 1); > + > + return cpuidle_register(&imx6ul_cpuidle_driver, NULL); > +} > diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h > index f914012..4dcf71d 100644 > --- a/arch/arm/mach-imx/cpuidle.h > +++ b/arch/arm/mach-imx/cpuidle.h > @@ -15,6 +15,7 @@ extern int imx5_cpuidle_init(void); > extern int imx6q_cpuidle_init(void); > extern int imx6sl_cpuidle_init(void); > extern int imx6sx_cpuidle_init(void); > +extern int imx6ul_cpuidle_init(void); > #else > static inline int imx5_cpuidle_init(void) > { > @@ -32,4 +33,8 @@ static inline int imx6sx_cpuidle_init(void) > { > return 0; > } > +static inline int imx6ul_cpuidle_init(void) > +{ > + return 0; > +} > #endif > diff --git a/arch/arm/mach-imx/mach-imx6ul.c b/arch/arm/mach-imx/mach-imx6ul.c > index f206506..0f4b95c 100644 > --- a/arch/arm/mach-imx/mach-imx6ul.c > +++ b/arch/arm/mach-imx/mach-imx6ul.c > @@ -11,6 +11,7 @@ > #include > > #include "common.h" > +#include "cpuidle.h" > > static void __init imx6ul_init_machine(void) > { > @@ -29,6 +30,12 @@ static void __init imx6ul_init_irq(void) > imx_init_revision_from_anatop(); > imx_src_init(); > irqchip_init(); > + imx6_pm_ccm_init("fsl,imx6ul-ccm"); > +} > + > +static void __init imx6ul_init_late(void) > +{ > + imx6ul_cpuidle_init(); > } > > static const char *imx6ul_dt_compat[] __initconst = { > @@ -40,4 +47,5 @@ DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)") > .init_irq = imx6ul_init_irq, > .init_machine = imx6ul_init_machine, > .dt_compat = imx6ul_dt_compat, > + .init_late = imx6ul_init_late, > MACHINE_END -- Pengutronix e.K. | Lucas Stach | Industrial Linux Solutions | http://www.pengutronix.de/ |