[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