[PATCH V2] ARM: imx: add cpuidle support for i.mx6sl
Shawn Guo
shawn.guo at linaro.org
Thu Jan 9 02:22:23 EST 2014
On Thu, Jan 09, 2014 at 12:06:42PM +0800, Anson Huang wrote:
> Add cpuidle support for i.MX6SL, currently only support
> two cpuidle levels(ARM wfi and WAIT mode), and add software
> workaround for WAIT mode errata as below:
>
> ERR005311 CCM: After exit from WAIT mode, unwanted interrupt(s) taken
> during WAIT mode entry process could cause cache memory
> corruption.
>
> Software workaround:
> To prevent this issue from occurring, software should ensure that
> the ARM to IPG clock ratio is less than 12:5 (that is < 2.4x), before
> entering WAIT mode.
>
> Signed-off-by: Anson Huang <b20788 at freescale.com>
The patch looks fine to me. But I failed to apply it to my tree. You
need to base it on my for-next branch below.
git://git.linaro.org/people/shawnguo/linux-2.6.git for-next
Shawn
> ---
> Changes since V1:
> 1. Add Errata description for software workaround of WAIT mode;
> 2. Improve variable type from u32 to unsigned long.
>
> arch/arm/mach-imx/Makefile | 1 +
> arch/arm/mach-imx/clk-imx6sl.c | 26 ++++++++++++++++
> arch/arm/mach-imx/common.h | 1 +
> arch/arm/mach-imx/cpuidle-imx6sl.c | 57 ++++++++++++++++++++++++++++++++++++
> arch/arm/mach-imx/cpuidle.h | 5 ++++
> arch/arm/mach-imx/mach-imx6sl.c | 7 +++++
> 6 files changed, 97 insertions(+)
> create mode 100644 arch/arm/mach-imx/cpuidle-imx6sl.c
>
> diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
> index d8205fb..1fcd273 100644
> --- a/arch/arm/mach-imx/Makefile
> +++ b/arch/arm/mach-imx/Makefile
> @@ -30,6 +30,7 @@ obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
> ifeq ($(CONFIG_CPU_IDLE),y)
> obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o
> obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o
> +obj-$(CONFIG_SOC_IMX6SL) += cpuidle-imx6sl.o
> endif
>
> ifdef CONFIG_SND_IMX_SOC
> diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c
> index e6900e9..0e3e182 100644
> --- a/arch/arm/mach-imx/clk-imx6sl.c
> +++ b/arch/arm/mach-imx/clk-imx6sl.c
> @@ -66,6 +66,32 @@ static struct clk_div_table video_div_table[] = {
> static struct clk *clks[IMX6SL_CLK_END];
> static struct clk_onecell_data clk_data;
>
> +/*
> + * ERR005311 CCM: After exit from WAIT mode, unwanted interrupt(s) taken
> + * during WAIT mode entry process could cause cache memory
> + * corruption.
> + *
> + * Software workaround:
> + * To prevent this issue from occurring, software should ensure that the
> + * ARM to IPG clock ratio is less than 12:5 (that is < 2.4x), before
> + * entering WAIT mode.
> + *
> + * This function will set the ARM clk to max value within the 12:5 limit.
> + */
> +void imx6sl_set_wait_clk(bool enter)
> +{
> + static unsigned long saved_arm_rate;
> +
> + if (enter) {
> + unsigned long ipg_rate = clk_get_rate(clks[IMX6SL_CLK_IPG]);
> + unsigned long max_arm_wait_rate = (12 * ipg_rate) / 5;
> + saved_arm_rate = clk_get_rate(clks[IMX6SL_CLK_ARM]);
> + clk_set_rate(clks[IMX6SL_CLK_ARM], max_arm_wait_rate);
> + } else {
> + clk_set_rate(clks[IMX6SL_CLK_ARM], saved_arm_rate);
> + }
> +}
> +
> static void __init imx6sl_clocks_init(struct device_node *ccm_node)
> {
> struct device_node *np;
> diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
> index 2b0151f..524c4cb 100644
> --- a/arch/arm/mach-imx/common.h
> +++ b/arch/arm/mach-imx/common.h
> @@ -140,6 +140,7 @@ void imx_anatop_pre_suspend(void);
> void imx_anatop_post_resume(void);
> int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
> void imx6q_set_chicken_bit(void);
> +void imx6sl_set_wait_clk(bool enter);
>
> void imx_cpu_die(unsigned int cpu);
> int imx_cpu_kill(unsigned int cpu);
> diff --git a/arch/arm/mach-imx/cpuidle-imx6sl.c b/arch/arm/mach-imx/cpuidle-imx6sl.c
> new file mode 100644
> index 0000000..d4b6b81
> --- /dev/null
> +++ b/arch/arm/mach-imx/cpuidle-imx6sl.c
> @@ -0,0 +1,57 @@
> +/*
> + * Copyright (C) 2014 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 <linux/cpuidle.h>
> +#include <linux/module.h>
> +#include <asm/cpuidle.h>
> +#include <asm/proc-fns.h>
> +
> +#include "common.h"
> +#include "cpuidle.h"
> +
> +static int imx6sl_enter_wait(struct cpuidle_device *dev,
> + struct cpuidle_driver *drv, int index)
> +{
> + imx6q_set_lpm(WAIT_UNCLOCKED);
> + /*
> + * Software workaround for ERR005311, see function
> + * description for details.
> + */
> + imx6sl_set_wait_clk(true);
> + cpu_do_idle();
> + imx6sl_set_wait_clk(false);
> + imx6q_set_lpm(WAIT_CLOCKED);
> +
> + return index;
> +}
> +
> +static struct cpuidle_driver imx6sl_cpuidle_driver = {
> + .name = "imx6sl_cpuidle",
> + .owner = THIS_MODULE,
> + .states = {
> + /* WFI */
> + ARM_CPUIDLE_WFI_STATE,
> + /* WAIT */
> + {
> + .exit_latency = 50,
> + .target_residency = 75,
> + .flags = CPUIDLE_FLAG_TIME_VALID |
> + CPUIDLE_FLAG_TIMER_STOP,
> + .enter = imx6sl_enter_wait,
> + .name = "WAIT",
> + .desc = "Clock off",
> + },
> + },
> + .state_count = 2,
> + .safe_state_index = 0,
> +};
> +
> +int __init imx6sl_cpuidle_init(void)
> +{
> + return cpuidle_register(&imx6sl_cpuidle_driver, NULL);
> +}
> diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h
> index 786f98e..24e3367 100644
> --- a/arch/arm/mach-imx/cpuidle.h
> +++ b/arch/arm/mach-imx/cpuidle.h
> @@ -13,6 +13,7 @@
> #ifdef CONFIG_CPU_IDLE
> extern int imx5_cpuidle_init(void);
> extern int imx6q_cpuidle_init(void);
> +extern int imx6sl_cpuidle_init(void);
> #else
> static inline int imx5_cpuidle_init(void)
> {
> @@ -22,4 +23,8 @@ static inline int imx6q_cpuidle_init(void)
> {
> return 0;
> }
> +static inline int imx6sl_cpuidle_init(void)
> +{
> + return 0;
> +}
> #endif
> diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c
> index 7fdd4e8..1cb6f6e 100644
> --- a/arch/arm/mach-imx/mach-imx6sl.c
> +++ b/arch/arm/mach-imx/mach-imx6sl.c
> @@ -17,6 +17,7 @@
> #include <asm/mach/map.h>
>
> #include "common.h"
> +#include "cpuidle.h"
>
> static void __init imx6sl_fec_init(void)
> {
> @@ -52,6 +53,11 @@ static void __init imx6sl_init_machine(void)
> imx6q_pm_init();
> }
>
> +static void __init imx6sl_init_late(void)
> +{
> + imx6sl_cpuidle_init();
> +}
> +
> static void __init imx6sl_map_io(void)
> {
> debug_ll_io_init();
> @@ -78,4 +84,5 @@ DT_MACHINE_START(IMX6SL, "Freescale i.MX6 SoloLite (Device Tree)")
> .init_machine = imx6sl_init_machine,
> .dt_compat = imx6sl_dt_compat,
> .restart = mxc_restart,
> + .init_late = imx6sl_init_late,
> MACHINE_END
> --
> 1.7.9.5
>
>
More information about the linux-arm-kernel
mailing list