diff options
author | Ranjani Vaidyanathan <ra5478@freescale.com> | 2013-08-26 14:50:03 -0400 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:05:33 -0400 |
commit | 2503fa545b9c6441080ae1903a87882ecd40e2a5 (patch) | |
tree | d03b4fa0fd70f537781c8b13846e189482283fbd /arch | |
parent | f7acad14c0eea241c5a5ed0378c8f45bb002d14b (diff) |
ENGR00277382-2 [MX6SL] Add WaIT mode support for MX6SL.
Enable WAIT mode support for MX6SL. Need to ensure that the
ARM:IPG clock ratio is maintained at 12:5 when WFI is executed.
This is the fix for the WAIT mode issue on MX6SL.
Set AHB to 132Mhz at boot, which is the recommended freq for AHB.
Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-imx/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/clk-imx6sl.c | 29 | ||||
-rw-r--r-- | arch/arm/mach-imx/common.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/cpuidle-imx6sl.c | 54 | ||||
-rw-r--r-- | arch/arm/mach-imx/cpuidle.h | 7 | ||||
-rw-r--r-- | arch/arm/mach-imx/mach-imx6sl.c | 4 |
6 files changed, 95 insertions, 1 deletions
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index e53fb59eaf95..9b80b2328785 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile | |||
@@ -31,6 +31,7 @@ obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o | |||
31 | ifeq ($(CONFIG_CPU_IDLE),y) | 31 | ifeq ($(CONFIG_CPU_IDLE),y) |
32 | obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o | 32 | obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o |
33 | obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o | 33 | obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o |
34 | obj-$(CONFIG_SOC_IMX6SL) += cpuidle-imx6sl.o | ||
34 | endif | 35 | endif |
35 | 36 | ||
36 | ifdef CONFIG_SND_IMX_SOC | 37 | ifdef CONFIG_SND_IMX_SOC |
diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c index cc054d122830..5a7e76af7698 100644 --- a/arch/arm/mach-imx/clk-imx6sl.c +++ b/arch/arm/mach-imx/clk-imx6sl.c | |||
@@ -67,6 +67,30 @@ static struct clk_div_table video_div_table[] = { | |||
67 | 67 | ||
68 | static struct clk *clks[IMX6SL_CLK_CLK_END]; | 68 | static struct clk *clks[IMX6SL_CLK_CLK_END]; |
69 | static struct clk_onecell_data clk_data; | 69 | static struct clk_onecell_data clk_data; |
70 | static u32 cur_arm_podf; | ||
71 | |||
72 | /* | ||
73 | * On MX6SL, need to ensure that the ARM:IPG clock ratio is maintained | ||
74 | * within 12:5 when the clocks to ARM are gated when the SOC enters | ||
75 | * WAIT mode. This is necessary to avoid WAIT mode issue (an early | ||
76 | * interrupt waking up the ARM). | ||
77 | * This function will set the ARM clk to max value within the 12:5 limit. | ||
78 | */ | ||
79 | void imx6sl_set_wait_clk(bool enter) | ||
80 | { | ||
81 | u32 parent_rate = clk_get_rate(clk_get_parent(clks[IMX6SL_CLK_ARM])); | ||
82 | |||
83 | if (enter) { | ||
84 | u32 ipg_rate = clk_get_rate(clks[IMX6SL_CLK_IPG]); | ||
85 | u32 max_arm_wait_clk = (12 * ipg_rate) / 5; | ||
86 | u32 wait_podf = (parent_rate + max_arm_wait_clk - 1) / | ||
87 | max_arm_wait_clk; | ||
88 | |||
89 | cur_arm_podf = parent_rate / clk_get_rate(clks[IMX6SL_CLK_ARM]); | ||
90 | clk_set_rate(clks[IMX6SL_CLK_ARM], parent_rate / wait_podf); | ||
91 | } else | ||
92 | clk_set_rate(clks[IMX6SL_CLK_ARM], parent_rate / cur_arm_podf); | ||
93 | } | ||
70 | 94 | ||
71 | static void __init imx6sl_clocks_init(struct device_node *ccm_node) | 95 | static void __init imx6sl_clocks_init(struct device_node *ccm_node) |
72 | { | 96 | { |
@@ -258,6 +282,11 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) | |||
258 | clk_register_clkdev(clks[IMX6SL_CLK_GPT], "ipg", "imx-gpt.0"); | 282 | clk_register_clkdev(clks[IMX6SL_CLK_GPT], "ipg", "imx-gpt.0"); |
259 | clk_register_clkdev(clks[IMX6SL_CLK_GPT_SERIAL], "per", "imx-gpt.0"); | 283 | clk_register_clkdev(clks[IMX6SL_CLK_GPT_SERIAL], "per", "imx-gpt.0"); |
260 | 284 | ||
285 | /* Ensure the AHB clk is at 132MHz. */ | ||
286 | ret = clk_set_rate(clks[IMX6SL_CLK_AHB], 132000000); | ||
287 | if (ret) | ||
288 | pr_warn("%s: failed to set AHB clock rate %d\n", __func__, ret); | ||
289 | |||
261 | /* | 290 | /* |
262 | * To prevent the bus clock from being disabled accidently when | 291 | * To prevent the bus clock from being disabled accidently when |
263 | * clk_disable() gets called on child clock, let's increment the use | 292 | * clk_disable() gets called on child clock, let's increment the use |
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 790ca9678843..36647133e3e6 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h | |||
@@ -146,6 +146,7 @@ extern void imx_anatop_post_resume(void); | |||
146 | extern void imx_anatop_pu_enable(bool enable); | 146 | extern void imx_anatop_pu_enable(bool enable); |
147 | extern int imx6_set_lpm(enum mxc_cpu_pwr_mode mode); | 147 | extern int imx6_set_lpm(enum mxc_cpu_pwr_mode mode); |
148 | extern void imx6_set_cache_lpm_in_wait(bool enable); | 148 | extern void imx6_set_cache_lpm_in_wait(bool enable); |
149 | extern void imx6sl_set_wait_clk(bool enter); | ||
149 | 150 | ||
150 | extern void imx_cpu_die(unsigned int cpu); | 151 | extern void imx_cpu_die(unsigned int cpu); |
151 | extern int imx_cpu_kill(unsigned int cpu); | 152 | extern 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 000000000000..7d8ed7c90043 --- /dev/null +++ b/arch/arm/mach-imx/cpuidle-imx6sl.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012-2013 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 <linux/of.h> | ||
12 | #include <asm/cpuidle.h> | ||
13 | #include <asm/proc-fns.h> | ||
14 | |||
15 | #include "common.h" | ||
16 | #include "cpuidle.h" | ||
17 | |||
18 | static int imx6sl_enter_wait(struct cpuidle_device *dev, | ||
19 | struct cpuidle_driver *drv, int index) | ||
20 | { | ||
21 | imx6_set_lpm(WAIT_UNCLOCKED); | ||
22 | imx6sl_set_wait_clk(true); | ||
23 | cpu_do_idle(); | ||
24 | imx6sl_set_wait_clk(false); | ||
25 | imx6_set_lpm(WAIT_CLOCKED); | ||
26 | |||
27 | return index; | ||
28 | } | ||
29 | |||
30 | static struct cpuidle_driver imx6sl_cpuidle_driver = { | ||
31 | .name = "imx6sl_cpuidle", | ||
32 | .owner = THIS_MODULE, | ||
33 | .states = { | ||
34 | /* WFI */ | ||
35 | ARM_CPUIDLE_WFI_STATE, | ||
36 | /* WAIT */ | ||
37 | { | ||
38 | .exit_latency = 50, | ||
39 | .target_residency = 75, | ||
40 | .flags = CPUIDLE_FLAG_TIME_VALID | | ||
41 | CPUIDLE_FLAG_TIMER_STOP, | ||
42 | .enter = imx6sl_enter_wait, | ||
43 | .name = "WAIT", | ||
44 | .desc = "Clock off", | ||
45 | }, | ||
46 | }, | ||
47 | .state_count = 2, | ||
48 | .safe_state_index = 0, | ||
49 | }; | ||
50 | |||
51 | int __init imx6sl_cpuidle_init(void) | ||
52 | { | ||
53 | return cpuidle_register(&imx6sl_cpuidle_driver, NULL); | ||
54 | } | ||
diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h index 786f98ecc145..0cdeeaff08f7 100644 --- a/arch/arm/mach-imx/cpuidle.h +++ b/arch/arm/mach-imx/cpuidle.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2012 Freescale Semiconductor, Inc. | 2 | * Copyright 2012-2013 Freescale Semiconductor, Inc. |
3 | * Copyright 2012 Linaro Ltd. | 3 | * Copyright 2012 Linaro Ltd. |
4 | * | 4 | * |
5 | * The code contained herein is licensed under the GNU General Public | 5 | * The code contained herein is licensed under the GNU General Public |
@@ -13,6 +13,7 @@ | |||
13 | #ifdef CONFIG_CPU_IDLE | 13 | #ifdef CONFIG_CPU_IDLE |
14 | extern int imx5_cpuidle_init(void); | 14 | extern int imx5_cpuidle_init(void); |
15 | extern int imx6q_cpuidle_init(void); | 15 | extern int imx6q_cpuidle_init(void); |
16 | extern int imx6sl_cpuidle_init(void); | ||
16 | #else | 17 | #else |
17 | static inline int imx5_cpuidle_init(void) | 18 | static 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 | } |
26 | static 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 0578373c9bfe..e1c83798bc3d 100644 --- a/arch/arm/mach-imx/mach-imx6sl.c +++ b/arch/arm/mach-imx/mach-imx6sl.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <asm/mach/map.h> | 19 | #include <asm/mach/map.h> |
20 | 20 | ||
21 | #include "common.h" | 21 | #include "common.h" |
22 | #include "cpuidle.h" | ||
22 | #include "hardware.h" | 23 | #include "hardware.h" |
23 | 24 | ||
24 | static struct platform_device imx6sl_cpufreq_pdev = { | 25 | static struct platform_device imx6sl_cpufreq_pdev = { |
@@ -94,6 +95,9 @@ static void __init imx6sl_init_late(void) | |||
94 | else | 95 | else |
95 | pr_err("failed to find fsl,imx6sl-iomux-gpr regmap\n"); | 96 | pr_err("failed to find fsl,imx6sl-iomux-gpr regmap\n"); |
96 | 97 | ||
98 | /* Init CPUIDLE */ | ||
99 | imx6sl_cpuidle_init(); | ||
100 | |||
97 | if (IS_ENABLED(CONFIG_ARM_IMX6_CPUFREQ)) { | 101 | if (IS_ENABLED(CONFIG_ARM_IMX6_CPUFREQ)) { |
98 | imx6sl_opp_init(&imx6sl_cpufreq_pdev.dev); | 102 | imx6sl_opp_init(&imx6sl_cpufreq_pdev.dev); |
99 | platform_device_register(&imx6sl_cpufreq_pdev); | 103 | platform_device_register(&imx6sl_cpufreq_pdev); |