diff options
author | Vikas Sajjan <vikas.sajjan@samsung.com> | 2014-11-06 19:17:36 -0500 |
---|---|---|
committer | Kukjin Kim <kgene.kim@samsung.com> | 2014-11-21 08:49:46 -0500 |
commit | 0fdf088fd84d87d6fc5d3961cc86feb8bd295398 (patch) | |
tree | 639e11f91a5065f1c402e626bbc974611f4cb619 | |
parent | af2e0a0754accf2276d58d6dfaa15563133130aa (diff) |
ARM: EXYNOS: Add Suspend-to-RAM support for exynos5420
Adds Suspend-to-RAM support for EXYNOS5420
Signed-off-by: Vikas Sajjan <vikas.sajjan@samsung.com>
Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
-rw-r--r-- | arch/arm/mach-exynos/suspend.c | 151 |
1 files changed, 149 insertions, 2 deletions
diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index 079d999b8b23..8cef6141c408 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c | |||
@@ -39,6 +39,8 @@ | |||
39 | 39 | ||
40 | #define REG_TABLE_END (-1U) | 40 | #define REG_TABLE_END (-1U) |
41 | 41 | ||
42 | #define EXYNOS5420_CPU_STATE 0x28 | ||
43 | |||
42 | /** | 44 | /** |
43 | * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping | 45 | * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping |
44 | * @hwirq: Hardware IRQ signal of the GIC | 46 | * @hwirq: Hardware IRQ signal of the GIC |
@@ -77,6 +79,9 @@ struct exynos_pm_data { | |||
77 | 79 | ||
78 | struct exynos_pm_data *pm_data; | 80 | struct exynos_pm_data *pm_data; |
79 | 81 | ||
82 | static int exynos5420_cpu_state; | ||
83 | static unsigned int exynos_pmu_spare3; | ||
84 | |||
80 | /* | 85 | /* |
81 | * GIC wake-up support | 86 | * GIC wake-up support |
82 | */ | 87 | */ |
@@ -106,6 +111,23 @@ unsigned int exynos_release_ret_regs[] = { | |||
106 | REG_TABLE_END, | 111 | REG_TABLE_END, |
107 | }; | 112 | }; |
108 | 113 | ||
114 | unsigned int exynos5420_release_ret_regs[] = { | ||
115 | EXYNOS_PAD_RET_DRAM_OPTION, | ||
116 | EXYNOS_PAD_RET_MAUDIO_OPTION, | ||
117 | EXYNOS_PAD_RET_JTAG_OPTION, | ||
118 | EXYNOS5420_PAD_RET_GPIO_OPTION, | ||
119 | EXYNOS5420_PAD_RET_UART_OPTION, | ||
120 | EXYNOS5420_PAD_RET_MMCA_OPTION, | ||
121 | EXYNOS5420_PAD_RET_MMCB_OPTION, | ||
122 | EXYNOS5420_PAD_RET_MMCC_OPTION, | ||
123 | EXYNOS5420_PAD_RET_HSI_OPTION, | ||
124 | EXYNOS_PAD_RET_EBIA_OPTION, | ||
125 | EXYNOS_PAD_RET_EBIB_OPTION, | ||
126 | EXYNOS5420_PAD_RET_SPI_OPTION, | ||
127 | EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION, | ||
128 | REG_TABLE_END, | ||
129 | }; | ||
130 | |||
109 | static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) | 131 | static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) |
110 | { | 132 | { |
111 | const struct exynos_wkup_irq *wkup_irq; | 133 | const struct exynos_wkup_irq *wkup_irq; |
@@ -136,11 +158,22 @@ static int exynos_cpu_do_idle(void) | |||
136 | pr_info("Failed to suspend the system\n"); | 158 | pr_info("Failed to suspend the system\n"); |
137 | return 1; /* Aborting suspend */ | 159 | return 1; /* Aborting suspend */ |
138 | } | 160 | } |
139 | 161 | static void exynos_flush_cache_all(void) | |
140 | static int exynos_cpu_suspend(unsigned long arg) | ||
141 | { | 162 | { |
142 | flush_cache_all(); | 163 | flush_cache_all(); |
143 | outer_flush_all(); | 164 | outer_flush_all(); |
165 | } | ||
166 | |||
167 | static int exynos_cpu_suspend(unsigned long arg) | ||
168 | { | ||
169 | exynos_flush_cache_all(); | ||
170 | return exynos_cpu_do_idle(); | ||
171 | } | ||
172 | |||
173 | static int exynos5420_cpu_suspend(unsigned long arg) | ||
174 | { | ||
175 | exynos_flush_cache_all(); | ||
176 | __raw_writel(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE); | ||
144 | return exynos_cpu_do_idle(); | 177 | return exynos_cpu_do_idle(); |
145 | } | 178 | } |
146 | 179 | ||
@@ -175,6 +208,50 @@ static void exynos_pm_prepare(void) | |||
175 | exynos_pm_enter_sleep_mode(); | 208 | exynos_pm_enter_sleep_mode(); |
176 | } | 209 | } |
177 | 210 | ||
211 | static void exynos5420_pm_prepare(void) | ||
212 | { | ||
213 | unsigned int tmp; | ||
214 | |||
215 | /* Set wake-up mask registers */ | ||
216 | exynos_pm_set_wakeup_mask(); | ||
217 | |||
218 | s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | ||
219 | |||
220 | exynos_pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3); | ||
221 | /* | ||
222 | * The cpu state needs to be saved and restored so that the | ||
223 | * secondary CPUs will enter low power start. Though the U-Boot | ||
224 | * is setting the cpu state with low power flag, the kernel | ||
225 | * needs to restore it back in case, the primary cpu fails to | ||
226 | * suspend for any reason. | ||
227 | */ | ||
228 | exynos5420_cpu_state = __raw_readl(sysram_base_addr + | ||
229 | EXYNOS5420_CPU_STATE); | ||
230 | |||
231 | exynos_pm_enter_sleep_mode(); | ||
232 | |||
233 | tmp = pmu_raw_readl(EXYNOS5_ARM_L2_OPTION); | ||
234 | tmp &= ~EXYNOS5_USE_RETENTION; | ||
235 | pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION); | ||
236 | |||
237 | tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); | ||
238 | tmp |= EXYNOS5420_UFS; | ||
239 | pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1); | ||
240 | |||
241 | tmp = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION); | ||
242 | tmp &= ~EXYNOS5420_L2RSTDISABLE_VALUE; | ||
243 | pmu_raw_writel(tmp, EXYNOS5420_ARM_COMMON_OPTION); | ||
244 | |||
245 | tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION); | ||
246 | tmp |= EXYNOS5420_EMULATION; | ||
247 | pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION); | ||
248 | |||
249 | tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION); | ||
250 | tmp |= EXYNOS5420_EMULATION; | ||
251 | pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION); | ||
252 | } | ||
253 | |||
254 | |||
178 | static int exynos_pm_suspend(void) | 255 | static int exynos_pm_suspend(void) |
179 | { | 256 | { |
180 | exynos_pm_central_suspend(); | 257 | exynos_pm_central_suspend(); |
@@ -185,6 +262,24 @@ static int exynos_pm_suspend(void) | |||
185 | return 0; | 262 | return 0; |
186 | } | 263 | } |
187 | 264 | ||
265 | static int exynos5420_pm_suspend(void) | ||
266 | { | ||
267 | u32 this_cluster; | ||
268 | |||
269 | exynos_pm_central_suspend(); | ||
270 | |||
271 | /* Setting SEQ_OPTION register */ | ||
272 | |||
273 | this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1); | ||
274 | if (!this_cluster) | ||
275 | pmu_raw_writel(EXYNOS5420_ARM_USE_STANDBY_WFI0, | ||
276 | S5P_CENTRAL_SEQ_OPTION); | ||
277 | else | ||
278 | pmu_raw_writel(EXYNOS5420_KFC_USE_STANDBY_WFI0, | ||
279 | S5P_CENTRAL_SEQ_OPTION); | ||
280 | return 0; | ||
281 | } | ||
282 | |||
188 | static void exynos_pm_release_retention(void) | 283 | static void exynos_pm_release_retention(void) |
189 | { | 284 | { |
190 | unsigned int i; | 285 | unsigned int i; |
@@ -223,6 +318,45 @@ early_wakeup: | |||
223 | pmu_raw_writel(0x0, S5P_INFORM1); | 318 | pmu_raw_writel(0x0, S5P_INFORM1); |
224 | } | 319 | } |
225 | 320 | ||
321 | static void exynos5420_pm_resume(void) | ||
322 | { | ||
323 | unsigned long tmp; | ||
324 | |||
325 | /* Restore the sysram cpu state register */ | ||
326 | __raw_writel(exynos5420_cpu_state, | ||
327 | sysram_base_addr + EXYNOS5420_CPU_STATE); | ||
328 | |||
329 | pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL, | ||
330 | S5P_CENTRAL_SEQ_OPTION); | ||
331 | |||
332 | if (exynos_pm_central_resume()) | ||
333 | goto early_wakeup; | ||
334 | |||
335 | /* For release retention */ | ||
336 | exynos_pm_release_retention(); | ||
337 | |||
338 | pmu_raw_writel(exynos_pmu_spare3, S5P_PMU_SPARE3); | ||
339 | |||
340 | s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | ||
341 | |||
342 | early_wakeup: | ||
343 | |||
344 | tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); | ||
345 | tmp &= ~EXYNOS5420_UFS; | ||
346 | pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1); | ||
347 | |||
348 | tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION); | ||
349 | tmp &= ~EXYNOS5420_EMULATION; | ||
350 | pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION); | ||
351 | |||
352 | tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION); | ||
353 | tmp &= ~EXYNOS5420_EMULATION; | ||
354 | pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION); | ||
355 | |||
356 | /* Clear SLEEP mode set in INFORM1 */ | ||
357 | pmu_raw_writel(0x0, S5P_INFORM1); | ||
358 | } | ||
359 | |||
226 | /* | 360 | /* |
227 | * Suspend Ops | 361 | * Suspend Ops |
228 | */ | 362 | */ |
@@ -310,6 +444,16 @@ static const struct exynos_pm_data exynos5250_pm_data = { | |||
310 | .cpu_suspend = exynos_cpu_suspend, | 444 | .cpu_suspend = exynos_cpu_suspend, |
311 | }; | 445 | }; |
312 | 446 | ||
447 | static struct exynos_pm_data exynos5420_pm_data = { | ||
448 | .wkup_irq = exynos5250_wkup_irq, | ||
449 | .wake_disable_mask = (0x7F << 7) | (0x1F << 1), | ||
450 | .release_ret_regs = exynos5420_release_ret_regs, | ||
451 | .pm_resume = exynos5420_pm_resume, | ||
452 | .pm_suspend = exynos5420_pm_suspend, | ||
453 | .pm_prepare = exynos5420_pm_prepare, | ||
454 | .cpu_suspend = exynos5420_cpu_suspend, | ||
455 | }; | ||
456 | |||
313 | static struct of_device_id exynos_pmu_of_device_ids[] = { | 457 | static struct of_device_id exynos_pmu_of_device_ids[] = { |
314 | { | 458 | { |
315 | .compatible = "samsung,exynos4210-pmu", | 459 | .compatible = "samsung,exynos4210-pmu", |
@@ -323,6 +467,9 @@ static struct of_device_id exynos_pmu_of_device_ids[] = { | |||
323 | }, { | 467 | }, { |
324 | .compatible = "samsung,exynos5250-pmu", | 468 | .compatible = "samsung,exynos5250-pmu", |
325 | .data = &exynos5250_pm_data, | 469 | .data = &exynos5250_pm_data, |
470 | }, { | ||
471 | .compatible = "samsung,exynos5420-pmu", | ||
472 | .data = &exynos5420_pm_data, | ||
326 | }, | 473 | }, |
327 | { /*sentinel*/ }, | 474 | { /*sentinel*/ }, |
328 | }; | 475 | }; |