diff options
author | Anson Huang <b20788@freescale.com> | 2013-08-20 11:30:19 -0400 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:01:23 -0400 |
commit | c4b48f2fe3c15e63de453e9fa06096f29650db70 (patch) | |
tree | 469efc9d7ff12566a528f7d8e3ef165f78d66be1 | |
parent | d5954fd96aa9b7657e8ba43d48c34e12445115d0 (diff) |
ENGR00275821-1 ARM: imx: rename pm-imx6q.c
To support all i.MX6 SOCs' suspend/resume, need to
rename pm-imx6q.c to pm-imx6.c and move common code
of ccm setting from platform specific clk file to
pm-imx6.c to avoid duplicated code.
Signed-off-by: Anson Huang <b20788@freescale.com>
-rw-r--r-- | arch/arm/mach-imx/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/mach-imx/clk-imx6q.c | 187 | ||||
-rw-r--r-- | arch/arm/mach-imx/common.h | 10 | ||||
-rw-r--r-- | arch/arm/mach-imx/cpuidle-imx6q.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-imx/mach-imx6q.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-imx/pm-imx6.c | 333 | ||||
-rw-r--r-- | arch/arm/mach-imx/pm-imx6q.c | 152 |
7 files changed, 346 insertions, 348 deletions
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 1a76d593e713..64aacbe49e61 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile | |||
@@ -102,9 +102,7 @@ obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o | |||
102 | obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o | 102 | obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o |
103 | 103 | ||
104 | AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a | 104 | AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a |
105 | ifeq ($(CONFIG_PM),y) | 105 | obj-$(CONFIG_PM) += pm-imx6.o headsmp.o suspend-imx6.o |
106 | obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o suspend-imx6.o | ||
107 | endif | ||
108 | 106 | ||
109 | # i.MX5 based machines | 107 | # i.MX5 based machines |
110 | obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o | 108 | obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o |
diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index 549568df147c..77d17eca0d9b 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/types.h> | 14 | #include <linux/types.h> |
15 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
16 | #include <linux/clkdev.h> | 16 | #include <linux/clkdev.h> |
17 | #include <linux/delay.h> | ||
18 | #include <linux/err.h> | 17 | #include <linux/err.h> |
19 | #include <linux/io.h> | 18 | #include <linux/io.h> |
20 | #include <linux/of.h> | 19 | #include <linux/of.h> |
@@ -25,188 +24,6 @@ | |||
25 | #include "common.h" | 24 | #include "common.h" |
26 | #include "hardware.h" | 25 | #include "hardware.h" |
27 | 26 | ||
28 | #define CCR 0x0 | ||
29 | #define BM_CCR_WB_COUNT (0x7 << 16) | ||
30 | #define BM_CCR_RBC_BYPASS_COUNT (0x3f << 21) | ||
31 | #define BM_CCR_RBC_EN (0x1 << 27) | ||
32 | |||
33 | #define CCGR0 0x68 | ||
34 | #define CCGR1 0x6c | ||
35 | #define CCGR2 0x70 | ||
36 | #define CCGR3 0x74 | ||
37 | #define CCGR4 0x78 | ||
38 | #define CCGR5 0x7c | ||
39 | #define CCGR6 0x80 | ||
40 | #define CCGR7 0x84 | ||
41 | |||
42 | #define CLPCR 0x54 | ||
43 | #define BP_CLPCR_LPM 0 | ||
44 | #define BM_CLPCR_LPM (0x3 << 0) | ||
45 | #define BM_CLPCR_BYPASS_PMIC_READY (0x1 << 2) | ||
46 | #define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) | ||
47 | #define BM_CLPCR_SBYOS (0x1 << 6) | ||
48 | #define BM_CLPCR_DIS_REF_OSC (0x1 << 7) | ||
49 | #define BM_CLPCR_VSTBY (0x1 << 8) | ||
50 | #define BP_CLPCR_STBY_COUNT 9 | ||
51 | #define BM_CLPCR_STBY_COUNT (0x3 << 9) | ||
52 | #define BM_CLPCR_COSC_PWRDOWN (0x1 << 11) | ||
53 | #define BM_CLPCR_WB_PER_AT_LPM (0x1 << 16) | ||
54 | #define BM_CLPCR_WB_CORE_AT_LPM (0x1 << 17) | ||
55 | #define BM_CLPCR_BYP_MMDC_CH0_LPM_HS (0x1 << 19) | ||
56 | #define BM_CLPCR_BYP_MMDC_CH1_LPM_HS (0x1 << 21) | ||
57 | #define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22) | ||
58 | #define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23) | ||
59 | #define BM_CLPCR_MASK_CORE2_WFI (0x1 << 24) | ||
60 | #define BM_CLPCR_MASK_CORE3_WFI (0x1 << 25) | ||
61 | #define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) | ||
62 | #define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) | ||
63 | |||
64 | #define CGPR 0x64 | ||
65 | #define BM_CGPR_INT_MEM_CLK_LPM (0x1 << 17) | ||
66 | |||
67 | #define MX6Q_INT_IOMUXC 32 | ||
68 | |||
69 | static void __iomem *ccm_base; | ||
70 | |||
71 | void imx6q_set_cache_lpm_in_wait(bool enable) | ||
72 | { | ||
73 | if ((cpu_is_imx6q() && imx_get_soc_revision() > | ||
74 | IMX_CHIP_REVISION_1_1) || | ||
75 | (cpu_is_imx6dl() && imx_get_soc_revision() > | ||
76 | IMX_CHIP_REVISION_1_0)) { | ||
77 | u32 val; | ||
78 | |||
79 | val = readl_relaxed(ccm_base + CGPR); | ||
80 | if (enable) | ||
81 | val |= BM_CGPR_INT_MEM_CLK_LPM; | ||
82 | else | ||
83 | val &= ~BM_CGPR_INT_MEM_CLK_LPM; | ||
84 | writel_relaxed(val, ccm_base + CGPR); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | static void imx6q_enable_rbc(bool enable) | ||
89 | { | ||
90 | u32 val; | ||
91 | static bool last_rbc_mode; | ||
92 | |||
93 | if (last_rbc_mode == enable) | ||
94 | return; | ||
95 | /* | ||
96 | * need to mask all interrupts in GPC before | ||
97 | * operating RBC configurations | ||
98 | */ | ||
99 | imx_gpc_mask_all(); | ||
100 | |||
101 | /* configure RBC enable bit */ | ||
102 | val = readl_relaxed(ccm_base + CCR); | ||
103 | val &= ~BM_CCR_RBC_EN; | ||
104 | val |= enable ? BM_CCR_RBC_EN : 0; | ||
105 | writel_relaxed(val, ccm_base + CCR); | ||
106 | |||
107 | /* configure RBC count */ | ||
108 | val = readl_relaxed(ccm_base + CCR); | ||
109 | val &= ~BM_CCR_RBC_BYPASS_COUNT; | ||
110 | val |= enable ? BM_CCR_RBC_BYPASS_COUNT : 0; | ||
111 | writel(val, ccm_base + CCR); | ||
112 | |||
113 | /* | ||
114 | * need to delay at least 2 cycles of CKIL(32K) | ||
115 | * due to hardware design requirement, which is | ||
116 | * ~61us, here we use 65us for safe | ||
117 | */ | ||
118 | udelay(65); | ||
119 | |||
120 | /* restore GPC interrupt mask settings */ | ||
121 | imx_gpc_restore_all(); | ||
122 | |||
123 | last_rbc_mode = enable; | ||
124 | } | ||
125 | |||
126 | static void imx6q_enable_wb(bool enable) | ||
127 | { | ||
128 | u32 val; | ||
129 | static bool last_wb_mode; | ||
130 | |||
131 | if (last_wb_mode == enable) | ||
132 | return; | ||
133 | |||
134 | /* configure well bias enable bit */ | ||
135 | val = readl_relaxed(ccm_base + CLPCR); | ||
136 | val &= ~BM_CLPCR_WB_PER_AT_LPM; | ||
137 | val |= enable ? BM_CLPCR_WB_PER_AT_LPM : 0; | ||
138 | writel_relaxed(val, ccm_base + CLPCR); | ||
139 | |||
140 | /* configure well bias count */ | ||
141 | val = readl_relaxed(ccm_base + CCR); | ||
142 | val &= ~BM_CCR_WB_COUNT; | ||
143 | val |= enable ? BM_CCR_WB_COUNT : 0; | ||
144 | writel_relaxed(val, ccm_base + CCR); | ||
145 | |||
146 | last_wb_mode = enable; | ||
147 | } | ||
148 | |||
149 | int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) | ||
150 | { | ||
151 | u32 val = readl_relaxed(ccm_base + CLPCR); | ||
152 | struct irq_desc *desc = irq_to_desc(MX6Q_INT_IOMUXC); | ||
153 | |||
154 | /* | ||
155 | * CCM state machine has restriction, before enabling | ||
156 | * LPM mode, need to make sure last LPM mode is waked up | ||
157 | * by dsm_wakeup_signal, which means the wakeup source | ||
158 | * must be seen by GPC, then CCM will clean its state machine | ||
159 | * and re-sample necessary signal to decide whether it can | ||
160 | * enter LPM mode. We force irq #32 to be always pending, | ||
161 | * unmask it before we enable LPM mode and mask it after LPM | ||
162 | * is enabled, this flow will make sure CCM state machine in | ||
163 | * reliable status before entering LPM mode. Otherwise, CCM | ||
164 | * may enter LPM mode by mistake which will cause system bus | ||
165 | * locked by CPU access not finished, as when CCM enter | ||
166 | * LPM mode, CPU will stop running. | ||
167 | */ | ||
168 | imx_gpc_irq_unmask(&desc->irq_data); | ||
169 | |||
170 | val &= ~BM_CLPCR_LPM; | ||
171 | switch (mode) { | ||
172 | case WAIT_CLOCKED: | ||
173 | imx6q_enable_wb(false); | ||
174 | imx6q_enable_rbc(false); | ||
175 | break; | ||
176 | case WAIT_UNCLOCKED: | ||
177 | val |= 0x1 << BP_CLPCR_LPM; | ||
178 | val |= BM_CLPCR_ARM_CLK_DIS_ON_LPM; | ||
179 | break; | ||
180 | case STOP_POWER_ON: | ||
181 | val |= 0x2 << BP_CLPCR_LPM; | ||
182 | val &= ~BM_CLPCR_VSTBY; | ||
183 | val &= ~BM_CLPCR_SBYOS; | ||
184 | val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; | ||
185 | break; | ||
186 | case WAIT_UNCLOCKED_POWER_OFF: | ||
187 | val |= 0x1 << BP_CLPCR_LPM; | ||
188 | val &= ~BM_CLPCR_VSTBY; | ||
189 | val &= ~BM_CLPCR_SBYOS; | ||
190 | break; | ||
191 | case STOP_POWER_OFF: | ||
192 | val |= 0x2 << BP_CLPCR_LPM; | ||
193 | val |= 0x3 << BP_CLPCR_STBY_COUNT; | ||
194 | val |= BM_CLPCR_VSTBY; | ||
195 | val |= BM_CLPCR_SBYOS; | ||
196 | val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; | ||
197 | imx6q_enable_wb(true); | ||
198 | break; | ||
199 | default: | ||
200 | imx_gpc_irq_mask(&desc->irq_data); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | writel_relaxed(val, ccm_base + CLPCR); | ||
205 | imx_gpc_irq_mask(&desc->irq_data); | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static const char *step_sels[] = { "osc", "pll2_pfd2_396m", }; | 27 | static const char *step_sels[] = { "osc", "pll2_pfd2_396m", }; |
211 | static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; | 28 | static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; |
212 | static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", }; | 29 | static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", }; |
@@ -400,7 +217,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) | |||
400 | np = ccm_node; | 217 | np = ccm_node; |
401 | base = of_iomap(np, 0); | 218 | base = of_iomap(np, 0); |
402 | WARN_ON(!base); | 219 | WARN_ON(!base); |
403 | ccm_base = base; | 220 | imx6_pm_set_ccm_base(base); |
404 | 221 | ||
405 | /* name reg shift width parent_names num_parents */ | 222 | /* name reg shift width parent_names num_parents */ |
406 | clk[step] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); | 223 | clk[step] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); |
@@ -667,7 +484,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) | |||
667 | pr_warn("failed to set up CLKO: %d\n", ret); | 484 | pr_warn("failed to set up CLKO: %d\n", ret); |
668 | 485 | ||
669 | /* Set initial power mode */ | 486 | /* Set initial power mode */ |
670 | imx6q_set_lpm(WAIT_CLOCKED); | 487 | imx6_set_lpm(WAIT_CLOCKED); |
671 | 488 | ||
672 | np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); | 489 | np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); |
673 | base = of_iomap(np, 0); | 490 | base = of_iomap(np, 0); |
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 310867dbca88..ab19a1f839f6 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h | |||
@@ -143,18 +143,20 @@ extern void imx_gpc_restore_all(void); | |||
143 | extern void imx_anatop_init(void); | 143 | extern void imx_anatop_init(void); |
144 | extern void imx_anatop_pre_suspend(void); | 144 | extern void imx_anatop_pre_suspend(void); |
145 | extern void imx_anatop_post_resume(void); | 145 | extern void imx_anatop_post_resume(void); |
146 | extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); | 146 | extern int imx6_set_lpm(enum mxc_cpu_pwr_mode mode); |
147 | extern void imx6q_set_cache_lpm_in_wait(bool enable); | 147 | extern void imx6_set_cache_lpm_in_wait(bool enable); |
148 | 148 | ||
149 | extern void imx_cpu_die(unsigned int cpu); | 149 | extern void imx_cpu_die(unsigned int cpu); |
150 | extern int imx_cpu_kill(unsigned int cpu); | 150 | extern int imx_cpu_kill(unsigned int cpu); |
151 | 151 | ||
152 | #ifdef CONFIG_PM | 152 | #ifdef CONFIG_PM |
153 | extern void imx6q_pm_init(void); | 153 | extern void imx6_pm_init(void); |
154 | extern void imx6_pm_set_ccm_base(void __iomem *base); | ||
154 | extern void imx51_pm_init(void); | 155 | extern void imx51_pm_init(void); |
155 | extern void imx53_pm_init(void); | 156 | extern void imx53_pm_init(void); |
156 | #else | 157 | #else |
157 | static inline void imx6q_pm_init(void) {} | 158 | static inline void imx6_pm_init(void) {} |
159 | static inline void imx6_pm_set_ccm_base(void __iomem *base) {} | ||
158 | static inline void imx51_pm_init(void) {} | 160 | static inline void imx51_pm_init(void) {} |
159 | static inline void imx53_pm_init(void) {} | 161 | static inline void imx53_pm_init(void) {} |
160 | #endif | 162 | #endif |
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c index 8065e185daed..d74d0ce794ab 100644 --- a/arch/arm/mach-imx/cpuidle-imx6q.c +++ b/arch/arm/mach-imx/cpuidle-imx6q.c | |||
@@ -27,9 +27,9 @@ static int imx6q_enter_wait(struct cpuidle_device *dev, | |||
27 | */ | 27 | */ |
28 | if (!spin_trylock(&master_lock)) | 28 | if (!spin_trylock(&master_lock)) |
29 | goto idle; | 29 | goto idle; |
30 | imx6q_set_lpm(WAIT_UNCLOCKED); | 30 | imx6_set_lpm(WAIT_UNCLOCKED); |
31 | cpu_do_idle(); | 31 | cpu_do_idle(); |
32 | imx6q_set_lpm(WAIT_CLOCKED); | 32 | imx6_set_lpm(WAIT_CLOCKED); |
33 | spin_unlock(&master_lock); | 33 | spin_unlock(&master_lock); |
34 | goto done; | 34 | goto done; |
35 | } | 35 | } |
@@ -69,7 +69,7 @@ int __init imx6q_cpuidle_init(void) | |||
69 | imx_scu_standby_enable(); | 69 | imx_scu_standby_enable(); |
70 | 70 | ||
71 | /* Set cache lpm bit for reliable WAIT mode support */ | 71 | /* Set cache lpm bit for reliable WAIT mode support */ |
72 | imx6q_set_cache_lpm_in_wait(true); | 72 | imx6_set_cache_lpm_in_wait(true); |
73 | 73 | ||
74 | return cpuidle_register(&imx6q_cpuidle_driver, NULL); | 74 | return cpuidle_register(&imx6q_cpuidle_driver, NULL); |
75 | } | 75 | } |
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index e1e334380534..cfa93827c9ad 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c | |||
@@ -213,7 +213,7 @@ static void __init imx6q_init_machine(void) | |||
213 | of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); | 213 | of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); |
214 | 214 | ||
215 | imx_anatop_init(); | 215 | imx_anatop_init(); |
216 | imx6q_pm_init(); | 216 | imx6_pm_init(); |
217 | imx6q_1588_init(); | 217 | imx6q_1588_init(); |
218 | imx6q_lvds_cabc_init(); | 218 | imx6q_lvds_cabc_init(); |
219 | } | 219 | } |
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c new file mode 100644 index 000000000000..e1c5eb5e03a1 --- /dev/null +++ b/arch/arm/mach-imx/pm-imx6.c | |||
@@ -0,0 +1,333 @@ | |||
1 | /* | ||
2 | * Copyright 2011-2013 Freescale Semiconductor, Inc. | ||
3 | * Copyright 2011 Linaro Ltd. | ||
4 | * | ||
5 | * The code contained herein is licensed under the GNU General Public | ||
6 | * License. You may obtain a copy of the GNU General Public License | ||
7 | * Version 2 or later at the following locations: | ||
8 | * | ||
9 | * http://www.opensource.org/licenses/gpl-license.html | ||
10 | * http://www.gnu.org/copyleft/gpl.html | ||
11 | */ | ||
12 | |||
13 | #include <linux/delay.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/of.h> | ||
17 | #include <linux/of_device.h> | ||
18 | #include <linux/of_irq.h> | ||
19 | #include <linux/suspend.h> | ||
20 | #include <linux/genalloc.h> | ||
21 | #include <asm/cacheflush.h> | ||
22 | #include <asm/fncpy.h> | ||
23 | #include <asm/proc-fns.h> | ||
24 | #include <asm/suspend.h> | ||
25 | #include <asm/hardware/cache-l2x0.h> | ||
26 | #include <asm/mach/map.h> | ||
27 | |||
28 | #include "common.h" | ||
29 | #include "hardware.h" | ||
30 | |||
31 | #define CCR 0x0 | ||
32 | #define BM_CCR_WB_COUNT (0x7 << 16) | ||
33 | #define BM_CCR_RBC_BYPASS_COUNT (0x3f << 21) | ||
34 | #define BM_CCR_RBC_EN (0x1 << 27) | ||
35 | |||
36 | #define CLPCR 0x54 | ||
37 | #define BP_CLPCR_LPM 0 | ||
38 | #define BM_CLPCR_LPM (0x3 << 0) | ||
39 | #define BM_CLPCR_BYPASS_PMIC_READY (0x1 << 2) | ||
40 | #define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) | ||
41 | #define BM_CLPCR_SBYOS (0x1 << 6) | ||
42 | #define BM_CLPCR_DIS_REF_OSC (0x1 << 7) | ||
43 | #define BM_CLPCR_VSTBY (0x1 << 8) | ||
44 | #define BP_CLPCR_STBY_COUNT 9 | ||
45 | #define BM_CLPCR_STBY_COUNT (0x3 << 9) | ||
46 | #define BM_CLPCR_COSC_PWRDOWN (0x1 << 11) | ||
47 | #define BM_CLPCR_WB_PER_AT_LPM (0x1 << 16) | ||
48 | #define BM_CLPCR_WB_CORE_AT_LPM (0x1 << 17) | ||
49 | #define BM_CLPCR_BYP_MMDC_CH0_LPM_HS (0x1 << 19) | ||
50 | #define BM_CLPCR_BYP_MMDC_CH1_LPM_HS (0x1 << 21) | ||
51 | #define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22) | ||
52 | #define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23) | ||
53 | #define BM_CLPCR_MASK_CORE2_WFI (0x1 << 24) | ||
54 | #define BM_CLPCR_MASK_CORE3_WFI (0x1 << 25) | ||
55 | #define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) | ||
56 | #define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) | ||
57 | |||
58 | #define CGPR 0x64 | ||
59 | #define BM_CGPR_INT_MEM_CLK_LPM (0x1 << 17) | ||
60 | |||
61 | #define MX6_INT_IOMUXC 32 | ||
62 | |||
63 | static struct gen_pool *iram_pool; | ||
64 | static void *suspend_iram_base; | ||
65 | static unsigned long iram_size, iram_paddr; | ||
66 | static int (*suspend_in_iram_fn)(void *iram_vbase, | ||
67 | unsigned long iram_pbase, unsigned int cpu_type); | ||
68 | static unsigned int cpu_type; | ||
69 | static void __iomem *ccm_base; | ||
70 | |||
71 | void imx6_set_cache_lpm_in_wait(bool enable) | ||
72 | { | ||
73 | if ((cpu_is_imx6q() && imx_get_soc_revision() > | ||
74 | IMX_CHIP_REVISION_1_1) || | ||
75 | (cpu_is_imx6dl() && imx_get_soc_revision() > | ||
76 | IMX_CHIP_REVISION_1_0)) { | ||
77 | u32 val; | ||
78 | |||
79 | val = readl_relaxed(ccm_base + CGPR); | ||
80 | if (enable) | ||
81 | val |= BM_CGPR_INT_MEM_CLK_LPM; | ||
82 | else | ||
83 | val &= ~BM_CGPR_INT_MEM_CLK_LPM; | ||
84 | writel_relaxed(val, ccm_base + CGPR); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | static void imx6_enable_rbc(bool enable) | ||
89 | { | ||
90 | u32 val; | ||
91 | static bool last_rbc_mode; | ||
92 | |||
93 | if (last_rbc_mode == enable) | ||
94 | return; | ||
95 | /* | ||
96 | * need to mask all interrupts in GPC before | ||
97 | * operating RBC configurations | ||
98 | */ | ||
99 | imx_gpc_mask_all(); | ||
100 | |||
101 | /* configure RBC enable bit */ | ||
102 | val = readl_relaxed(ccm_base + CCR); | ||
103 | val &= ~BM_CCR_RBC_EN; | ||
104 | val |= enable ? BM_CCR_RBC_EN : 0; | ||
105 | writel_relaxed(val, ccm_base + CCR); | ||
106 | |||
107 | /* configure RBC count */ | ||
108 | val = readl_relaxed(ccm_base + CCR); | ||
109 | val &= ~BM_CCR_RBC_BYPASS_COUNT; | ||
110 | val |= enable ? BM_CCR_RBC_BYPASS_COUNT : 0; | ||
111 | writel(val, ccm_base + CCR); | ||
112 | |||
113 | /* | ||
114 | * need to delay at least 2 cycles of CKIL(32K) | ||
115 | * due to hardware design requirement, which is | ||
116 | * ~61us, here we use 65us for safe | ||
117 | */ | ||
118 | udelay(65); | ||
119 | |||
120 | /* restore GPC interrupt mask settings */ | ||
121 | imx_gpc_restore_all(); | ||
122 | |||
123 | last_rbc_mode = enable; | ||
124 | } | ||
125 | |||
126 | static void imx6_enable_wb(bool enable) | ||
127 | { | ||
128 | u32 val; | ||
129 | static bool last_wb_mode; | ||
130 | |||
131 | if (last_wb_mode == enable) | ||
132 | return; | ||
133 | |||
134 | /* configure well bias enable bit */ | ||
135 | val = readl_relaxed(ccm_base + CLPCR); | ||
136 | val &= ~BM_CLPCR_WB_PER_AT_LPM; | ||
137 | val |= enable ? BM_CLPCR_WB_PER_AT_LPM : 0; | ||
138 | writel_relaxed(val, ccm_base + CLPCR); | ||
139 | |||
140 | /* configure well bias count */ | ||
141 | val = readl_relaxed(ccm_base + CCR); | ||
142 | val &= ~BM_CCR_WB_COUNT; | ||
143 | val |= enable ? BM_CCR_WB_COUNT : 0; | ||
144 | writel_relaxed(val, ccm_base + CCR); | ||
145 | |||
146 | last_wb_mode = enable; | ||
147 | } | ||
148 | |||
149 | int imx6_set_lpm(enum mxc_cpu_pwr_mode mode) | ||
150 | { | ||
151 | u32 val = readl_relaxed(ccm_base + CLPCR); | ||
152 | struct irq_desc *desc = irq_to_desc(MX6_INT_IOMUXC); | ||
153 | |||
154 | /* | ||
155 | * CCM state machine has restriction, before enabling | ||
156 | * LPM mode, need to make sure last LPM mode is waked up | ||
157 | * by dsm_wakeup_signal, which means the wakeup source | ||
158 | * must be seen by GPC, then CCM will clean its state machine | ||
159 | * and re-sample necessary signal to decide whether it can | ||
160 | * enter LPM mode. We force irq #32 to be always pending, | ||
161 | * unmask it before we enable LPM mode and mask it after LPM | ||
162 | * is enabled, this flow will make sure CCM state machine in | ||
163 | * reliable status before entering LPM mode. Otherwise, CCM | ||
164 | * may enter LPM mode by mistake which will cause system bus | ||
165 | * locked by CPU access not finished, as when CCM enter | ||
166 | * LPM mode, CPU will stop running. | ||
167 | */ | ||
168 | imx_gpc_irq_unmask(&desc->irq_data); | ||
169 | |||
170 | val &= ~BM_CLPCR_LPM; | ||
171 | switch (mode) { | ||
172 | case WAIT_CLOCKED: | ||
173 | imx6_enable_wb(false); | ||
174 | imx6_enable_rbc(false); | ||
175 | break; | ||
176 | case WAIT_UNCLOCKED: | ||
177 | val |= 0x1 << BP_CLPCR_LPM; | ||
178 | val |= BM_CLPCR_ARM_CLK_DIS_ON_LPM; | ||
179 | break; | ||
180 | case STOP_POWER_ON: | ||
181 | val |= 0x2 << BP_CLPCR_LPM; | ||
182 | val &= ~BM_CLPCR_VSTBY; | ||
183 | val &= ~BM_CLPCR_SBYOS; | ||
184 | val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; | ||
185 | break; | ||
186 | case WAIT_UNCLOCKED_POWER_OFF: | ||
187 | val |= 0x1 << BP_CLPCR_LPM; | ||
188 | val &= ~BM_CLPCR_VSTBY; | ||
189 | val &= ~BM_CLPCR_SBYOS; | ||
190 | break; | ||
191 | case STOP_POWER_OFF: | ||
192 | val |= 0x2 << BP_CLPCR_LPM; | ||
193 | val |= 0x3 << BP_CLPCR_STBY_COUNT; | ||
194 | val |= BM_CLPCR_VSTBY; | ||
195 | val |= BM_CLPCR_SBYOS; | ||
196 | val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; | ||
197 | imx6_enable_wb(true); | ||
198 | break; | ||
199 | default: | ||
200 | imx_gpc_irq_mask(&desc->irq_data); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | writel_relaxed(val, ccm_base + CLPCR); | ||
205 | imx_gpc_irq_mask(&desc->irq_data); | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int imx6_suspend_finish(unsigned long val) | ||
211 | { | ||
212 | /* | ||
213 | * call low level suspend function in iram, | ||
214 | * as we need to float DDR IO. | ||
215 | */ | ||
216 | suspend_in_iram_fn(suspend_iram_base, iram_paddr, cpu_type); | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static int imx6_pm_enter(suspend_state_t state) | ||
221 | { | ||
222 | switch (state) { | ||
223 | case PM_SUSPEND_STANDBY: | ||
224 | imx6_set_lpm(STOP_POWER_ON); | ||
225 | imx6_set_cache_lpm_in_wait(true); | ||
226 | imx_gpc_pre_suspend(false); | ||
227 | /* Zzz ... */ | ||
228 | cpu_do_idle(); | ||
229 | imx_gpc_post_resume(); | ||
230 | imx6_set_lpm(WAIT_CLOCKED); | ||
231 | break; | ||
232 | case PM_SUSPEND_MEM: | ||
233 | imx6_set_cache_lpm_in_wait(false); | ||
234 | imx6_set_lpm(STOP_POWER_OFF); | ||
235 | imx_gpc_pre_suspend(true); | ||
236 | imx_anatop_pre_suspend(); | ||
237 | imx_set_cpu_jump(0, v7_cpu_resume); | ||
238 | /* Zzz ... */ | ||
239 | cpu_suspend(0, imx6_suspend_finish); | ||
240 | imx_smp_prepare(); | ||
241 | imx_anatop_post_resume(); | ||
242 | imx_gpc_post_resume(); | ||
243 | imx6_set_cache_lpm_in_wait(true); | ||
244 | imx6_set_lpm(WAIT_CLOCKED); | ||
245 | break; | ||
246 | default: | ||
247 | return -EINVAL; | ||
248 | } | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static struct map_desc imx6_pm_io_desc[] __initdata = { | ||
254 | imx_map_entry(MX6Q, MMDC_P0, MT_DEVICE), | ||
255 | imx_map_entry(MX6Q, MMDC_P1, MT_DEVICE), | ||
256 | imx_map_entry(MX6Q, SRC, MT_DEVICE), | ||
257 | imx_map_entry(MX6Q, IOMUXC, MT_DEVICE), | ||
258 | imx_map_entry(MX6Q, CCM, MT_DEVICE), | ||
259 | imx_map_entry(MX6Q, ANATOP, MT_DEVICE), | ||
260 | imx_map_entry(MX6Q, GPC, MT_DEVICE), | ||
261 | imx_map_entry(MX6Q, L2, MT_DEVICE), | ||
262 | }; | ||
263 | |||
264 | void __init imx6_pm_map_io(void) | ||
265 | { | ||
266 | iotable_init(imx6_pm_io_desc, ARRAY_SIZE(imx6_pm_io_desc)); | ||
267 | } | ||
268 | |||
269 | static int imx6_pm_valid(suspend_state_t state) | ||
270 | { | ||
271 | return (state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM); | ||
272 | } | ||
273 | |||
274 | static const struct platform_suspend_ops imx6_pm_ops = { | ||
275 | .enter = imx6_pm_enter, | ||
276 | .valid = imx6_pm_valid, | ||
277 | }; | ||
278 | |||
279 | void imx6_pm_set_ccm_base(void __iomem *base) | ||
280 | { | ||
281 | if (!base) | ||
282 | pr_warn("ccm base is NULL!\n"); | ||
283 | ccm_base = base; | ||
284 | } | ||
285 | |||
286 | void __init imx6_pm_init(void) | ||
287 | { | ||
288 | struct device_node *node; | ||
289 | unsigned long iram_base; | ||
290 | struct platform_device *pdev; | ||
291 | |||
292 | node = of_find_compatible_node(NULL, NULL, "mmio-sram"); | ||
293 | if (!node) { | ||
294 | pr_err("failed to find ocram node!\n"); | ||
295 | return; | ||
296 | } | ||
297 | |||
298 | pdev = of_find_device_by_node(node); | ||
299 | if (!pdev) { | ||
300 | pr_err("failed to find ocram device!\n"); | ||
301 | return; | ||
302 | } | ||
303 | |||
304 | iram_pool = dev_get_gen_pool(&pdev->dev); | ||
305 | if (!iram_pool) { | ||
306 | pr_err("iram pool unavailable!\n"); | ||
307 | return; | ||
308 | } | ||
309 | |||
310 | iram_size = MX6_SUSPEND_IRAM_SIZE; | ||
311 | |||
312 | iram_base = gen_pool_alloc(iram_pool, iram_size); | ||
313 | if (!iram_base) { | ||
314 | pr_err("unable to alloc iram!\n"); | ||
315 | return; | ||
316 | } | ||
317 | |||
318 | iram_paddr = gen_pool_virt_to_phys(iram_pool, iram_base); | ||
319 | |||
320 | suspend_iram_base = __arm_ioremap(iram_paddr, iram_size, | ||
321 | MT_MEMORY_NONCACHED); | ||
322 | |||
323 | suspend_in_iram_fn = (void *)fncpy(suspend_iram_base, | ||
324 | &imx6_suspend, iram_size); | ||
325 | |||
326 | suspend_set_ops(&imx6_pm_ops); | ||
327 | |||
328 | /* Set cpu_type for DSM */ | ||
329 | if (cpu_is_imx6q()) | ||
330 | cpu_type = MXC_CPU_IMX6Q; | ||
331 | else if (cpu_is_imx6dl()) | ||
332 | cpu_type = MXC_CPU_IMX6DL; | ||
333 | } | ||
diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c deleted file mode 100644 index 637653b81db9..000000000000 --- a/arch/arm/mach-imx/pm-imx6q.c +++ /dev/null | |||
@@ -1,152 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2011-2013 Freescale Semiconductor, Inc. | ||
3 | * Copyright 2011 Linaro Ltd. | ||
4 | * | ||
5 | * The code contained herein is licensed under the GNU General Public | ||
6 | * License. You may obtain a copy of the GNU General Public License | ||
7 | * Version 2 or later at the following locations: | ||
8 | * | ||
9 | * http://www.opensource.org/licenses/gpl-license.html | ||
10 | * http://www.gnu.org/copyleft/gpl.html | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/of_device.h> | ||
17 | #include <linux/suspend.h> | ||
18 | #include <linux/genalloc.h> | ||
19 | #include <asm/cacheflush.h> | ||
20 | #include <asm/fncpy.h> | ||
21 | #include <asm/proc-fns.h> | ||
22 | #include <asm/suspend.h> | ||
23 | #include <asm/hardware/cache-l2x0.h> | ||
24 | #include <asm/mach/map.h> | ||
25 | |||
26 | #include "common.h" | ||
27 | #include "hardware.h" | ||
28 | |||
29 | static struct gen_pool *iram_pool; | ||
30 | static void *suspend_iram_base; | ||
31 | static unsigned long iram_size, iram_paddr; | ||
32 | static int (*suspend_in_iram_fn)(void *iram_vbase, | ||
33 | unsigned long iram_pbase, unsigned int cpu_type); | ||
34 | static unsigned int cpu_type; | ||
35 | |||
36 | static int imx6q_suspend_finish(unsigned long val) | ||
37 | { | ||
38 | /* | ||
39 | * call low level suspend function in iram, | ||
40 | * as we need to float DDR IO. | ||
41 | */ | ||
42 | suspend_in_iram_fn(suspend_iram_base, iram_paddr, cpu_type); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static int imx6q_pm_enter(suspend_state_t state) | ||
47 | { | ||
48 | switch (state) { | ||
49 | case PM_SUSPEND_STANDBY: | ||
50 | imx6q_set_lpm(STOP_POWER_ON); | ||
51 | imx6q_set_cache_lpm_in_wait(true); | ||
52 | imx_gpc_pre_suspend(false); | ||
53 | /* Zzz ... */ | ||
54 | cpu_do_idle(); | ||
55 | imx_gpc_post_resume(); | ||
56 | imx6q_set_lpm(WAIT_CLOCKED); | ||
57 | break; | ||
58 | case PM_SUSPEND_MEM: | ||
59 | imx6q_set_cache_lpm_in_wait(false); | ||
60 | imx6q_set_lpm(STOP_POWER_OFF); | ||
61 | imx_gpc_pre_suspend(true); | ||
62 | imx_anatop_pre_suspend(); | ||
63 | imx_set_cpu_jump(0, v7_cpu_resume); | ||
64 | /* Zzz ... */ | ||
65 | cpu_suspend(0, imx6q_suspend_finish); | ||
66 | imx_smp_prepare(); | ||
67 | imx_anatop_post_resume(); | ||
68 | imx_gpc_post_resume(); | ||
69 | imx6q_set_cache_lpm_in_wait(true); | ||
70 | imx6q_set_lpm(WAIT_CLOCKED); | ||
71 | break; | ||
72 | default: | ||
73 | return -EINVAL; | ||
74 | } | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static struct map_desc imx6_pm_io_desc[] __initdata = { | ||
80 | imx_map_entry(MX6Q, MMDC_P0, MT_DEVICE), | ||
81 | imx_map_entry(MX6Q, MMDC_P1, MT_DEVICE), | ||
82 | imx_map_entry(MX6Q, SRC, MT_DEVICE), | ||
83 | imx_map_entry(MX6Q, IOMUXC, MT_DEVICE), | ||
84 | imx_map_entry(MX6Q, CCM, MT_DEVICE), | ||
85 | imx_map_entry(MX6Q, ANATOP, MT_DEVICE), | ||
86 | imx_map_entry(MX6Q, GPC, MT_DEVICE), | ||
87 | imx_map_entry(MX6Q, L2, MT_DEVICE), | ||
88 | }; | ||
89 | |||
90 | void __init imx6_pm_map_io(void) | ||
91 | { | ||
92 | iotable_init(imx6_pm_io_desc, ARRAY_SIZE(imx6_pm_io_desc)); | ||
93 | } | ||
94 | |||
95 | static int imx6q_pm_valid(suspend_state_t state) | ||
96 | { | ||
97 | return (state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM); | ||
98 | } | ||
99 | |||
100 | static const struct platform_suspend_ops imx6q_pm_ops = { | ||
101 | .enter = imx6q_pm_enter, | ||
102 | .valid = imx6q_pm_valid, | ||
103 | }; | ||
104 | |||
105 | void __init imx6q_pm_init(void) | ||
106 | { | ||
107 | struct device_node *node; | ||
108 | unsigned long iram_base; | ||
109 | struct platform_device *pdev; | ||
110 | |||
111 | node = of_find_compatible_node(NULL, NULL, "mmio-sram"); | ||
112 | if (!node) { | ||
113 | pr_err("failed to find ocram node!\n"); | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | pdev = of_find_device_by_node(node); | ||
118 | if (!pdev) { | ||
119 | pr_err("failed to find ocram device!\n"); | ||
120 | return; | ||
121 | } | ||
122 | |||
123 | iram_pool = dev_get_gen_pool(&pdev->dev); | ||
124 | if (!iram_pool) { | ||
125 | pr_err("iram pool unavailable!\n"); | ||
126 | return; | ||
127 | } | ||
128 | |||
129 | iram_size = MX6_SUSPEND_IRAM_SIZE; | ||
130 | |||
131 | iram_base = gen_pool_alloc(iram_pool, iram_size); | ||
132 | if (!iram_base) { | ||
133 | pr_err("unable to alloc iram!\n"); | ||
134 | return; | ||
135 | } | ||
136 | |||
137 | iram_paddr = gen_pool_virt_to_phys(iram_pool, iram_base); | ||
138 | |||
139 | suspend_iram_base = __arm_ioremap(iram_paddr, iram_size, | ||
140 | MT_MEMORY_NONCACHED); | ||
141 | |||
142 | suspend_in_iram_fn = (void *)fncpy(suspend_iram_base, | ||
143 | &imx6_suspend, iram_size); | ||
144 | |||
145 | suspend_set_ops(&imx6q_pm_ops); | ||
146 | |||
147 | /* Set cpu_type for DSM */ | ||
148 | if (cpu_is_imx6q()) | ||
149 | cpu_type = MXC_CPU_IMX6Q; | ||
150 | else if (cpu_is_imx6dl()) | ||
151 | cpu_type = MXC_CPU_IMX6DL; | ||
152 | } | ||