aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-imx/Makefile1
-rw-r--r--arch/arm/mach-imx/clk-imx6sl.c26
-rw-r--r--arch/arm/mach-imx/common.h1
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6sl.c57
-rw-r--r--arch/arm/mach-imx/cpuidle.h5
-rw-r--r--arch/arm/mach-imx/mach-imx6sl.c3
6 files changed, 93 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index ec419649320f..21114a9a2ae7 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
30ifeq ($(CONFIG_CPU_IDLE),y) 30ifeq ($(CONFIG_CPU_IDLE),y)
31obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o 31obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o
32obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o 32obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o
33obj-$(CONFIG_SOC_IMX6SL) += cpuidle-imx6sl.o
33endif 34endif
34 35
35ifdef CONFIG_SND_IMX_SOC 36ifdef CONFIG_SND_IMX_SOC
diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c
index c5f17c2d4951..6f21a1333fe4 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[] = {
66static struct clk *clks[IMX6SL_CLK_END]; 66static struct clk *clks[IMX6SL_CLK_END];
67static struct clk_onecell_data clk_data; 67static struct clk_onecell_data clk_data;
68 68
69/*
70 * ERR005311 CCM: After exit from WAIT mode, unwanted interrupt(s) taken
71 * during WAIT mode entry process could cause cache memory
72 * corruption.
73 *
74 * Software workaround:
75 * To prevent this issue from occurring, software should ensure that the
76 * ARM to IPG clock ratio is less than 12:5 (that is < 2.4x), before
77 * entering WAIT mode.
78 *
79 * This function will set the ARM clk to max value within the 12:5 limit.
80 */
81void imx6sl_set_wait_clk(bool enter)
82{
83 static unsigned long saved_arm_rate;
84
85 if (enter) {
86 unsigned long ipg_rate = clk_get_rate(clks[IMX6SL_CLK_IPG]);
87 unsigned long max_arm_wait_rate = (12 * ipg_rate) / 5;
88 saved_arm_rate = clk_get_rate(clks[IMX6SL_CLK_ARM]);
89 clk_set_rate(clks[IMX6SL_CLK_ARM], max_arm_wait_rate);
90 } else {
91 clk_set_rate(clks[IMX6SL_CLK_ARM], saved_arm_rate);
92 }
93}
94
69static void __init imx6sl_clocks_init(struct device_node *ccm_node) 95static void __init imx6sl_clocks_init(struct device_node *ccm_node)
70{ 96{
71 struct device_node *np; 97 struct device_node *np;
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index cdbddfa2a42f..b909b689619b 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);
140void imx_anatop_post_resume(void); 140void imx_anatop_post_resume(void);
141int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); 141int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
142void imx6q_set_int_mem_clk_lpm(void); 142void imx6q_set_int_mem_clk_lpm(void);
143void imx6sl_set_wait_clk(bool enter);
143 144
144void imx_cpu_die(unsigned int cpu); 145void imx_cpu_die(unsigned int cpu);
145int imx_cpu_kill(unsigned int cpu); 146int 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 000000000000..d4b6b8171fa9
--- /dev/null
+++ b/arch/arm/mach-imx/cpuidle-imx6sl.c
@@ -0,0 +1,57 @@
1/*
2 * Copyright (C) 2014 Freescale Semiconductor, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/cpuidle.h>
10#include <linux/module.h>
11#include <asm/cpuidle.h>
12#include <asm/proc-fns.h>
13
14#include "common.h"
15#include "cpuidle.h"
16
17static int imx6sl_enter_wait(struct cpuidle_device *dev,
18 struct cpuidle_driver *drv, int index)
19{
20 imx6q_set_lpm(WAIT_UNCLOCKED);
21 /*
22 * Software workaround for ERR005311, see function
23 * description for details.
24 */
25 imx6sl_set_wait_clk(true);
26 cpu_do_idle();
27 imx6sl_set_wait_clk(false);
28 imx6q_set_lpm(WAIT_CLOCKED);
29
30 return index;
31}
32
33static struct cpuidle_driver imx6sl_cpuidle_driver = {
34 .name = "imx6sl_cpuidle",
35 .owner = THIS_MODULE,
36 .states = {
37 /* WFI */
38 ARM_CPUIDLE_WFI_STATE,
39 /* WAIT */
40 {
41 .exit_latency = 50,
42 .target_residency = 75,
43 .flags = CPUIDLE_FLAG_TIME_VALID |
44 CPUIDLE_FLAG_TIMER_STOP,
45 .enter = imx6sl_enter_wait,
46 .name = "WAIT",
47 .desc = "Clock off",
48 },
49 },
50 .state_count = 2,
51 .safe_state_index = 0,
52};
53
54int __init imx6sl_cpuidle_init(void)
55{
56 return cpuidle_register(&imx6sl_cpuidle_driver, NULL);
57}
diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h
index 786f98ecc145..24e33670417c 100644
--- a/arch/arm/mach-imx/cpuidle.h
+++ b/arch/arm/mach-imx/cpuidle.h
@@ -13,6 +13,7 @@
13#ifdef CONFIG_CPU_IDLE 13#ifdef CONFIG_CPU_IDLE
14extern int imx5_cpuidle_init(void); 14extern int imx5_cpuidle_init(void);
15extern int imx6q_cpuidle_init(void); 15extern int imx6q_cpuidle_init(void);
16extern int imx6sl_cpuidle_init(void);
16#else 17#else
17static inline int imx5_cpuidle_init(void) 18static inline int imx5_cpuidle_init(void)
18{ 19{
@@ -22,4 +23,8 @@ static inline int imx6q_cpuidle_init(void)
22{ 23{
23 return 0; 24 return 0;
24} 25}
26static inline int imx6sl_cpuidle_init(void)
27{
28 return 0;
29}
25#endif 30#endif
diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c
index 0f4fd4c0ab8e..a26fdb2b1a6f 100644
--- a/arch/arm/mach-imx/mach-imx6sl.c
+++ b/arch/arm/mach-imx/mach-imx6sl.c
@@ -17,6 +17,7 @@
17#include <asm/mach/map.h> 17#include <asm/mach/map.h>
18 18
19#include "common.h" 19#include "common.h"
20#include "cpuidle.h"
20 21
21static void __init imx6sl_fec_init(void) 22static void __init imx6sl_fec_init(void)
22{ 23{
@@ -39,6 +40,8 @@ static void __init imx6sl_init_late(void)
39 /* imx6sl reuses imx6q cpufreq driver */ 40 /* imx6sl reuses imx6q cpufreq driver */
40 if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) 41 if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
41 platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0); 42 platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
43
44 imx6sl_cpuidle_init();
42} 45}
43 46
44static void __init imx6sl_init_machine(void) 47static void __init imx6sl_init_machine(void)