aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorRobert Lee <rob.lee@linaro.org>2012-05-21 18:50:26 -0400
committerSascha Hauer <s.hauer@pengutronix.de>2012-06-05 02:49:10 -0400
commit565fa91f236524b6ba4872903dc9cc9c874493e6 (patch)
treebf0872ac1d86158da8209341b4d1eef0755f9150 /arch/arm
parenteee4f4003824b0887251a3ba4493217371816a57 (diff)
ARM: imx: clean and consolidate imx5 suspend and idle code
The imx5 idle code that existed in mm-imx5.c is moved to pm-imx5.c. The imx5_pm_init call is now exported and called during the MACHINE_START late_init in supported imx5 platforms. Remove various enabling/disabling of the gpc_dvfs clock and enable it once during initialization. This is a very low power clock that must be enabled during low power operations. There are only two "suspend_state_t" imx5 low power modes ever used. STOP_POWER_OFF for suspend to mem and WAIT_UNCLOCKED_POWER_OFF for idle and suspend to standby. The latter mode only requires 500 nanoseconds of extra hardware exit time beyond a basic WFI operation (WAIT_CLOCKED mode) so no other idle mode is necessary. Given this information, it is more efficient to keep the registers in the often used WAIT_UNCLOCKED_POWER_OFF state and only to and from the STOP_POWER_OFF register state as needed when suspend to mem is required. Signed-off-by: Robert Lee <rob.lee@linaro.org> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-imx/mm-imx5.c21
-rw-r--r--arch/arm/mach-imx/pm-imx5.c67
-rw-r--r--arch/arm/plat-mxc/include/mach/common.h3
3 files changed, 44 insertions, 47 deletions
diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c
index feeee17da96b..d84421e1467d 100644
--- a/arch/arm/mach-imx/mm-imx5.c
+++ b/arch/arm/mach-imx/mm-imx5.c
@@ -16,7 +16,6 @@
16#include <linux/clk.h> 16#include <linux/clk.h>
17#include <linux/pinctrl/machine.h> 17#include <linux/pinctrl/machine.h>
18 18
19#include <asm/system_misc.h>
20#include <asm/mach/map.h> 19#include <asm/mach/map.h>
21 20
22#include <mach/hardware.h> 21#include <mach/hardware.h>
@@ -24,24 +23,6 @@
24#include <mach/devices-common.h> 23#include <mach/devices-common.h>
25#include <mach/iomux-v3.h> 24#include <mach/iomux-v3.h>
26 25
27static struct clk *gpc_dvfs_clk;
28
29static void imx5_idle(void)
30{
31 /* gpc clock is needed for SRPG */
32 if (gpc_dvfs_clk == NULL) {
33 gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
34 if (IS_ERR(gpc_dvfs_clk))
35 return;
36 clk_prepare(gpc_dvfs_clk);
37 }
38 clk_enable(gpc_dvfs_clk);
39 mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
40 if (!tzic_enable_wake())
41 cpu_do_idle();
42 clk_disable(gpc_dvfs_clk);
43}
44
45/* 26/*
46 * Define the MX50 memory map. 27 * Define the MX50 memory map.
47 */ 28 */
@@ -105,7 +86,6 @@ void __init imx51_init_early(void)
105 mxc_set_cpu_type(MXC_CPU_MX51); 86 mxc_set_cpu_type(MXC_CPU_MX51);
106 mxc_iomux_v3_init(MX51_IO_ADDRESS(MX51_IOMUXC_BASE_ADDR)); 87 mxc_iomux_v3_init(MX51_IO_ADDRESS(MX51_IOMUXC_BASE_ADDR));
107 mxc_arch_reset_init(MX51_IO_ADDRESS(MX51_WDOG1_BASE_ADDR)); 88 mxc_arch_reset_init(MX51_IO_ADDRESS(MX51_WDOG1_BASE_ADDR));
108 arm_pm_idle = imx5_idle;
109} 89}
110 90
111void __init imx53_init_early(void) 91void __init imx53_init_early(void)
@@ -241,4 +221,5 @@ void __init imx53_soc_init(void)
241void __init imx51_init_late(void) 221void __init imx51_init_late(void)
242{ 222{
243 mx51_neon_fixup(); 223 mx51_neon_fixup();
224 imx51_pm_init();
244} 225}
diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c
index e26a9cb05ed8..baf93214f899 100644
--- a/arch/arm/mach-imx/pm-imx5.c
+++ b/arch/arm/mach-imx/pm-imx5.c
@@ -13,18 +13,27 @@
13#include <linux/io.h> 13#include <linux/io.h>
14#include <linux/err.h> 14#include <linux/err.h>
15#include <asm/cacheflush.h> 15#include <asm/cacheflush.h>
16#include <asm/system_misc.h>
16#include <asm/tlbflush.h> 17#include <asm/tlbflush.h>
17#include <mach/common.h> 18#include <mach/common.h>
18#include <mach/hardware.h> 19#include <mach/hardware.h>
19#include "crm-regs-imx5.h" 20#include "crm-regs-imx5.h"
20 21
21static struct clk *gpc_dvfs_clk; 22/*
23 * The WAIT_UNCLOCKED_POWER_OFF state only requires <= 500ns to exit.
24 * This is also the lowest power state possible without affecting
25 * non-cpu parts of the system. For these reasons, imx5 should default
26 * to always using this state for cpu idling. The PM_SUSPEND_STANDBY also
27 * uses this state and needs to take no action when registers remain confgiured
28 * for this state.
29 */
30#define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF
22 31
23/* 32/*
24 * set cpu low power mode before WFI instruction. This function is called 33 * set cpu low power mode before WFI instruction. This function is called
25 * mx5 because it can be used for mx50, mx51, and mx53. 34 * mx5 because it can be used for mx50, mx51, and mx53.
26 */ 35 */
27void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode) 36static void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
28{ 37{
29 u32 plat_lpc, arm_srpgcr, ccm_clpcr; 38 u32 plat_lpc, arm_srpgcr, ccm_clpcr;
30 u32 empgc0, empgc1; 39 u32 empgc0, empgc1;
@@ -87,11 +96,6 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
87 } 96 }
88} 97}
89 98
90static int mx5_suspend_prepare(void)
91{
92 return clk_prepare_enable(gpc_dvfs_clk);
93}
94
95static int mx5_suspend_enter(suspend_state_t state) 99static int mx5_suspend_enter(suspend_state_t state)
96{ 100{
97 switch (state) { 101 switch (state) {
@@ -99,7 +103,7 @@ static int mx5_suspend_enter(suspend_state_t state)
99 mx5_cpu_lp_set(STOP_POWER_OFF); 103 mx5_cpu_lp_set(STOP_POWER_OFF);
100 break; 104 break;
101 case PM_SUSPEND_STANDBY: 105 case PM_SUSPEND_STANDBY:
102 mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); 106 /* DEFAULT_IDLE_STATE already configured */
103 break; 107 break;
104 default: 108 default:
105 return -EINVAL; 109 return -EINVAL;
@@ -114,12 +118,10 @@ static int mx5_suspend_enter(suspend_state_t state)
114 __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR); 118 __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR);
115 } 119 }
116 cpu_do_idle(); 120 cpu_do_idle();
117 return 0;
118}
119 121
120static void mx5_suspend_finish(void) 122 /* return registers to default idle state */
121{ 123 mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
122 clk_disable_unprepare(gpc_dvfs_clk); 124 return 0;
123} 125}
124 126
125static int mx5_pm_valid(suspend_state_t state) 127static int mx5_pm_valid(suspend_state_t state)
@@ -129,25 +131,38 @@ static int mx5_pm_valid(suspend_state_t state)
129 131
130static const struct platform_suspend_ops mx5_suspend_ops = { 132static const struct platform_suspend_ops mx5_suspend_ops = {
131 .valid = mx5_pm_valid, 133 .valid = mx5_pm_valid,
132 .prepare = mx5_suspend_prepare,
133 .enter = mx5_suspend_enter, 134 .enter = mx5_suspend_enter,
134 .finish = mx5_suspend_finish,
135}; 135};
136 136
137static int __init mx5_pm_init(void) 137static void imx5_pm_idle(void)
138{ 138{
139 if (!cpu_is_mx51() && !cpu_is_mx53()) 139 if (likely(!tzic_enable_wake()))
140 return 0; 140 cpu_do_idle();
141}
142
143static int __init imx5_pm_common_init(void)
144{
145 int ret;
146 struct clk *gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
147
148 if (IS_ERR(gpc_dvfs_clk))
149 return PTR_ERR(gpc_dvfs_clk);
141 150
142 if (gpc_dvfs_clk == NULL) 151 ret = clk_prepare_enable(gpc_dvfs_clk);
143 gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs"); 152 if (ret)
153 return ret;
144 154
145 if (!IS_ERR(gpc_dvfs_clk)) { 155 arm_pm_idle = imx5_pm_idle;
146 if (cpu_is_mx51()) 156
147 suspend_set_ops(&mx5_suspend_ops); 157 /* Set the registers to the default cpu idle state. */
148 } else 158 mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
149 return -EPERM;
150 159
151 return 0; 160 return 0;
152} 161}
153device_initcall(mx5_pm_init); 162
163void __init imx51_pm_init(void)
164{
165 int ret = imx5_pm_common_init();
166 if (!ret)
167 suspend_set_ops(&mx5_suspend_ops);
168}
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index cf663d84e7c1..f65d068e1820 100644
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -95,7 +95,6 @@ enum mx3_cpu_pwr_mode {
95}; 95};
96 96
97extern void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode); 97extern void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode);
98extern void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode);
99extern void imx_print_silicon_rev(const char *cpu, int srev); 98extern void imx_print_silicon_rev(const char *cpu, int srev);
100 99
101void avic_handle_irq(struct pt_regs *); 100void avic_handle_irq(struct pt_regs *);
@@ -146,8 +145,10 @@ extern void imx6q_clock_map_io(void);
146 145
147#ifdef CONFIG_PM 146#ifdef CONFIG_PM
148extern void imx6q_pm_init(void); 147extern void imx6q_pm_init(void);
148extern void imx51_pm_init(void);
149#else 149#else
150static inline void imx6q_pm_init(void) {} 150static inline void imx6q_pm_init(void) {}
151static inline void imx51_pm_init(void) {}
151#endif 152#endif
152 153
153#ifdef CONFIG_NEON 154#ifdef CONFIG_NEON