aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAbhilash Kesavan <a.kesavan@samsung.com>2014-11-06 19:20:16 -0500
committerKukjin Kim <kgene.kim@samsung.com>2014-11-21 08:49:46 -0500
commitadc548d77c22daa371d5217b382a139b593dec47 (patch)
treee8bf2f7eb460e4126053db2f4469aba631bc8ad6
parent0fdf088fd84d87d6fc5d3961cc86feb8bd295398 (diff)
ARM: EXYNOS: Use MCPM call-backs to support S2R on exynos5420
Use the MCPM layer to handle core suspend/resume on Exynos5420. Also, restore the entry address setup code post-resume. Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com> Acked-by: Nicolas Pitre <nico@linaro.org> Reviewed-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
-rw-r--r--arch/arm/mach-exynos/mcpm-exynos.c32
-rw-r--r--arch/arm/mach-exynos/platsmp.c12
-rw-r--r--arch/arm/mach-exynos/suspend.c49
3 files changed, 78 insertions, 15 deletions
diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
index dc9a764a7c37..b0d3c2e876fb 100644
--- a/arch/arm/mach-exynos/mcpm-exynos.c
+++ b/arch/arm/mach-exynos/mcpm-exynos.c
@@ -15,6 +15,7 @@
15#include <linux/delay.h> 15#include <linux/delay.h>
16#include <linux/io.h> 16#include <linux/io.h>
17#include <linux/of_address.h> 17#include <linux/of_address.h>
18#include <linux/syscore_ops.h>
18 19
19#include <asm/cputype.h> 20#include <asm/cputype.h>
20#include <asm/cp15.h> 21#include <asm/cp15.h>
@@ -30,6 +31,8 @@
30#define EXYNOS5420_USE_ARM_CORE_DOWN_STATE BIT(29) 31#define EXYNOS5420_USE_ARM_CORE_DOWN_STATE BIT(29)
31#define EXYNOS5420_USE_L2_COMMON_UP_STATE BIT(30) 32#define EXYNOS5420_USE_L2_COMMON_UP_STATE BIT(30)
32 33
34static void __iomem *ns_sram_base_addr;
35
33/* 36/*
34 * The common v7_exit_coherency_flush API could not be used because of the 37 * The common v7_exit_coherency_flush API could not be used because of the
35 * Erratum 799270 workaround. This macro is the same as the common one (in 38 * Erratum 799270 workaround. This macro is the same as the common one (in
@@ -318,10 +321,26 @@ static const struct of_device_id exynos_dt_mcpm_match[] = {
318 {}, 321 {},
319}; 322};
320 323
324static void exynos_mcpm_setup_entry_point(void)
325{
326 /*
327 * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr
328 * as part of secondary_cpu_start(). Let's redirect it to the
329 * mcpm_entry_point(). This is done during both secondary boot-up as
330 * well as system resume.
331 */
332 __raw_writel(0xe59f0000, ns_sram_base_addr); /* ldr r0, [pc, #0] */
333 __raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx r0 */
334 __raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 8);
335}
336
337static struct syscore_ops exynos_mcpm_syscore_ops = {
338 .resume = exynos_mcpm_setup_entry_point,
339};
340
321static int __init exynos_mcpm_init(void) 341static int __init exynos_mcpm_init(void)
322{ 342{
323 struct device_node *node; 343 struct device_node *node;
324 void __iomem *ns_sram_base_addr;
325 unsigned int value, i; 344 unsigned int value, i;
326 int ret; 345 int ret;
327 346
@@ -387,16 +406,9 @@ static int __init exynos_mcpm_init(void)
387 pmu_raw_writel(value, EXYNOS_COMMON_OPTION(i)); 406 pmu_raw_writel(value, EXYNOS_COMMON_OPTION(i));
388 } 407 }
389 408
390 /* 409 exynos_mcpm_setup_entry_point();
391 * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr
392 * as part of secondary_cpu_start(). Let's redirect it to the
393 * mcpm_entry_point().
394 */
395 __raw_writel(0xe59f0000, ns_sram_base_addr); /* ldr r0, [pc, #0] */
396 __raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx r0 */
397 __raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 8);
398 410
399 iounmap(ns_sram_base_addr); 411 register_syscore_ops(&exynos_mcpm_syscore_ops);
400 412
401 return ret; 413 return ret;
402} 414}
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index adb36a8e8785..7a1ebfeeeeb8 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -126,6 +126,18 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
126 */ 126 */
127void exynos_cpu_power_down(int cpu) 127void exynos_cpu_power_down(int cpu)
128{ 128{
129 if (cpu == 0 && (of_machine_is_compatible("samsung,exynos5420") ||
130 of_machine_is_compatible("samsung,exynos5800"))) {
131 /*
132 * Bypass power down for CPU0 during suspend. Check for
133 * the SYS_PWR_REG value to decide if we are suspending
134 * the system.
135 */
136 int val = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG);
137
138 if (!(val & S5P_CORE_LOCAL_PWR_EN))
139 return;
140 }
129 pmu_raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu)); 141 pmu_raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu));
130} 142}
131 143
diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c
index 8cef6141c408..cc8d2374f1b1 100644
--- a/arch/arm/mach-exynos/suspend.c
+++ b/arch/arm/mach-exynos/suspend.c
@@ -24,6 +24,7 @@
24#include <asm/cacheflush.h> 24#include <asm/cacheflush.h>
25#include <asm/hardware/cache-l2x0.h> 25#include <asm/hardware/cache-l2x0.h>
26#include <asm/firmware.h> 26#include <asm/firmware.h>
27#include <asm/mcpm.h>
27#include <asm/smp_scu.h> 28#include <asm/smp_scu.h>
28#include <asm/suspend.h> 29#include <asm/suspend.h>
29 30
@@ -72,6 +73,7 @@ struct exynos_pm_data {
72 unsigned int *release_ret_regs; 73 unsigned int *release_ret_regs;
73 74
74 void (*pm_prepare)(void); 75 void (*pm_prepare)(void);
76 void (*pm_resume_prepare)(void);
75 void (*pm_resume)(void); 77 void (*pm_resume)(void);
76 int (*pm_suspend)(void); 78 int (*pm_suspend)(void);
77 int (*cpu_suspend)(unsigned long); 79 int (*cpu_suspend)(unsigned long);
@@ -172,9 +174,28 @@ static int exynos_cpu_suspend(unsigned long arg)
172 174
173static int exynos5420_cpu_suspend(unsigned long arg) 175static int exynos5420_cpu_suspend(unsigned long arg)
174{ 176{
175 exynos_flush_cache_all(); 177 /* MCPM works with HW CPU identifiers */
178 unsigned int mpidr = read_cpuid_mpidr();
179 unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
180 unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
181
176 __raw_writel(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE); 182 __raw_writel(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE);
177 return exynos_cpu_do_idle(); 183
184 if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) {
185 mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume);
186
187 /*
188 * Residency value passed to mcpm_cpu_suspend back-end
189 * has to be given clear semantics. Set to 0 as a
190 * temporary value.
191 */
192 mcpm_cpu_suspend(0);
193 }
194
195 pr_info("Failed to suspend the system\n");
196
197 /* return value != 0 means failure */
198 return 1;
178} 199}
179 200
180static void exynos_pm_set_wakeup_mask(void) 201static void exynos_pm_set_wakeup_mask(void)
@@ -189,9 +210,6 @@ static void exynos_pm_enter_sleep_mode(void)
189 /* Set value of power down register for sleep mode */ 210 /* Set value of power down register for sleep mode */
190 exynos_sys_powerdown_conf(SYS_SLEEP); 211 exynos_sys_powerdown_conf(SYS_SLEEP);
191 pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); 212 pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1);
192
193 /* ensure at least INFORM0 has the resume address */
194 pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0);
195} 213}
196 214
197static void exynos_pm_prepare(void) 215static void exynos_pm_prepare(void)
@@ -206,6 +224,9 @@ static void exynos_pm_prepare(void)
206 pm_data->num_extra_save); 224 pm_data->num_extra_save);
207 225
208 exynos_pm_enter_sleep_mode(); 226 exynos_pm_enter_sleep_mode();
227
228 /* ensure at least INFORM0 has the resume address */
229 pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0);
209} 230}
210 231
211static void exynos5420_pm_prepare(void) 232static void exynos5420_pm_prepare(void)
@@ -230,6 +251,10 @@ static void exynos5420_pm_prepare(void)
230 251
231 exynos_pm_enter_sleep_mode(); 252 exynos_pm_enter_sleep_mode();
232 253
254 /* ensure at least INFORM0 has the resume address */
255 if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
256 pmu_raw_writel(virt_to_phys(mcpm_entry_point), S5P_INFORM0);
257
233 tmp = pmu_raw_readl(EXYNOS5_ARM_L2_OPTION); 258 tmp = pmu_raw_readl(EXYNOS5_ARM_L2_OPTION);
234 tmp &= ~EXYNOS5_USE_RETENTION; 259 tmp &= ~EXYNOS5_USE_RETENTION;
235 pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION); 260 pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION);
@@ -318,10 +343,21 @@ early_wakeup:
318 pmu_raw_writel(0x0, S5P_INFORM1); 343 pmu_raw_writel(0x0, S5P_INFORM1);
319} 344}
320 345
346static void exynos5420_prepare_pm_resume(void)
347{
348 if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
349 WARN_ON(mcpm_cpu_powered_up());
350}
351
321static void exynos5420_pm_resume(void) 352static void exynos5420_pm_resume(void)
322{ 353{
323 unsigned long tmp; 354 unsigned long tmp;
324 355
356 /* Restore the CPU0 low power state register */
357 tmp = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG);
358 pmu_raw_writel(tmp | S5P_CORE_LOCAL_PWR_EN,
359 EXYNOS5_ARM_CORE0_SYS_PWR_REG);
360
325 /* Restore the sysram cpu state register */ 361 /* Restore the sysram cpu state register */
326 __raw_writel(exynos5420_cpu_state, 362 __raw_writel(exynos5420_cpu_state,
327 sysram_base_addr + EXYNOS5420_CPU_STATE); 363 sysram_base_addr + EXYNOS5420_CPU_STATE);
@@ -391,6 +427,8 @@ static int exynos_suspend_enter(suspend_state_t state)
391 if (ret) 427 if (ret)
392 return ret; 428 return ret;
393 429
430 if (pm_data->pm_resume_prepare)
431 pm_data->pm_resume_prepare();
394 s3c_pm_restore_uarts(); 432 s3c_pm_restore_uarts();
395 433
396 S3C_PMDBG("%s: wakeup stat: %08x\n", __func__, 434 S3C_PMDBG("%s: wakeup stat: %08x\n", __func__,
@@ -448,6 +486,7 @@ static struct exynos_pm_data exynos5420_pm_data = {
448 .wkup_irq = exynos5250_wkup_irq, 486 .wkup_irq = exynos5250_wkup_irq,
449 .wake_disable_mask = (0x7F << 7) | (0x1F << 1), 487 .wake_disable_mask = (0x7F << 7) | (0x1F << 1),
450 .release_ret_regs = exynos5420_release_ret_regs, 488 .release_ret_regs = exynos5420_release_ret_regs,
489 .pm_resume_prepare = exynos5420_prepare_pm_resume,
451 .pm_resume = exynos5420_pm_resume, 490 .pm_resume = exynos5420_pm_resume,
452 .pm_suspend = exynos5420_pm_suspend, 491 .pm_suspend = exynos5420_pm_suspend,
453 .pm_prepare = exynos5420_pm_prepare, 492 .pm_prepare = exynos5420_pm_prepare,