diff options
author | Gregory CLEMENT <gregory.clement@free-electrons.com> | 2014-07-23 09:00:52 -0400 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2014-07-24 07:47:40 -0400 |
commit | e53b1fd432497942a0fdfd0e89c3d30241cb4d2c (patch) | |
tree | 5c091ae93b8ca9f2db67f354eed30f4a659f6eb4 /arch/arm/mach-mvebu | |
parent | 3b9e4b1441aedcb26079f690aa11f3f9f93e5182 (diff) |
ARM: mvebu: add cpuidle support for Armada 38x
Unlike the Armada XP and the Armada 370, this SoC uses a Cortex A9
core. Consequently, the procedure to enter the idle state is
different: interaction with the SCU, not disabling snooping, etc.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Link: https://lkml.kernel.org/r/1406120453-29291-16-git-send-email-thomas.petazzoni@free-electrons.com
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Diffstat (limited to 'arch/arm/mach-mvebu')
-rw-r--r-- | arch/arm/mach-mvebu/pmsu.c | 85 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/pmsu_ll.S | 14 |
2 files changed, 98 insertions, 1 deletions
diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 9190ae8626cf..bd7c66a28826 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/smp.h> | 29 | #include <linux/smp.h> |
30 | #include <asm/cacheflush.h> | 30 | #include <asm/cacheflush.h> |
31 | #include <asm/cp15.h> | 31 | #include <asm/cp15.h> |
32 | #include <asm/smp_scu.h> | ||
32 | #include <asm/smp_plat.h> | 33 | #include <asm/smp_plat.h> |
33 | #include <asm/suspend.h> | 34 | #include <asm/suspend.h> |
34 | #include <asm/tlbflush.h> | 35 | #include <asm/tlbflush.h> |
@@ -63,6 +64,18 @@ | |||
63 | #define L2C_NFABRIC_PM_CTL 0x4 | 64 | #define L2C_NFABRIC_PM_CTL 0x4 |
64 | #define L2C_NFABRIC_PM_CTL_PWR_DOWN BIT(20) | 65 | #define L2C_NFABRIC_PM_CTL_PWR_DOWN BIT(20) |
65 | 66 | ||
67 | /* PMSU delay registers */ | ||
68 | #define PMSU_POWERDOWN_DELAY 0xF04 | ||
69 | #define PMSU_POWERDOWN_DELAY_PMU BIT(1) | ||
70 | #define PMSU_POWERDOWN_DELAY_MASK 0xFFFE | ||
71 | #define PMSU_DFLT_ARMADA38X_DELAY 0x64 | ||
72 | |||
73 | /* CA9 MPcore SoC Control registers */ | ||
74 | |||
75 | #define MPCORE_RESET_CTL 0x64 | ||
76 | #define MPCORE_RESET_CTL_L2 BIT(0) | ||
77 | #define MPCORE_RESET_CTL_DEBUG BIT(16) | ||
78 | |||
66 | #define SRAM_PHYS_BASE 0xFFFF0000 | 79 | #define SRAM_PHYS_BASE 0xFFFF0000 |
67 | #define BOOTROM_BASE 0xFFF00000 | 80 | #define BOOTROM_BASE 0xFFF00000 |
68 | #define BOOTROM_SIZE 0x100000 | 81 | #define BOOTROM_SIZE 0x100000 |
@@ -74,6 +87,8 @@ extern void ll_disable_coherency(void); | |||
74 | extern void ll_enable_coherency(void); | 87 | extern void ll_enable_coherency(void); |
75 | 88 | ||
76 | extern void armada_370_xp_cpu_resume(void); | 89 | extern void armada_370_xp_cpu_resume(void); |
90 | extern void armada_38x_cpu_resume(void); | ||
91 | |||
77 | static phys_addr_t pmsu_mp_phys_base; | 92 | static phys_addr_t pmsu_mp_phys_base; |
78 | static void __iomem *pmsu_mp_base; | 93 | static void __iomem *pmsu_mp_base; |
79 | 94 | ||
@@ -287,6 +302,32 @@ static int armada_370_xp_cpu_suspend(unsigned long deepidle) | |||
287 | return cpu_suspend(deepidle, armada_370_xp_pmsu_idle_enter); | 302 | return cpu_suspend(deepidle, armada_370_xp_pmsu_idle_enter); |
288 | } | 303 | } |
289 | 304 | ||
305 | static int armada_38x_do_cpu_suspend(unsigned long deepidle) | ||
306 | { | ||
307 | unsigned long flags = 0; | ||
308 | |||
309 | if (deepidle) | ||
310 | flags |= PMSU_PREPARE_DEEP_IDLE; | ||
311 | |||
312 | mvebu_v7_pmsu_idle_prepare(flags); | ||
313 | /* | ||
314 | * Already flushed cache, but do it again as the outer cache | ||
315 | * functions dirty the cache with spinlocks | ||
316 | */ | ||
317 | v7_exit_coherency_flush(louis); | ||
318 | |||
319 | scu_power_mode(mvebu_get_scu_base(), SCU_PM_POWEROFF); | ||
320 | |||
321 | cpu_do_idle(); | ||
322 | |||
323 | return 1; | ||
324 | } | ||
325 | |||
326 | static int armada_38x_cpu_suspend(unsigned long deepidle) | ||
327 | { | ||
328 | return cpu_suspend(false, armada_38x_do_cpu_suspend); | ||
329 | } | ||
330 | |||
290 | /* No locking is needed because we only access per-CPU registers */ | 331 | /* No locking is needed because we only access per-CPU registers */ |
291 | void mvebu_v7_pmsu_idle_exit(void) | 332 | void mvebu_v7_pmsu_idle_exit(void) |
292 | { | 333 | { |
@@ -295,7 +336,6 @@ void mvebu_v7_pmsu_idle_exit(void) | |||
295 | 336 | ||
296 | if (pmsu_mp_base == NULL) | 337 | if (pmsu_mp_base == NULL) |
297 | return; | 338 | return; |
298 | |||
299 | /* cancel ask HW to power down the L2 Cache if possible */ | 339 | /* cancel ask HW to power down the L2 Cache if possible */ |
300 | reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); | 340 | reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); |
301 | reg &= ~PMSU_CONTROL_AND_CONFIG_L2_PWDDN; | 341 | reg &= ~PMSU_CONTROL_AND_CONFIG_L2_PWDDN; |
@@ -359,6 +399,47 @@ static __init int armada_370_cpuidle_init(void) | |||
359 | return 0; | 399 | return 0; |
360 | } | 400 | } |
361 | 401 | ||
402 | static __init int armada_38x_cpuidle_init(void) | ||
403 | { | ||
404 | struct device_node *np; | ||
405 | void __iomem *mpsoc_base; | ||
406 | u32 reg; | ||
407 | |||
408 | np = of_find_compatible_node(NULL, NULL, | ||
409 | "marvell,armada-380-coherency-fabric"); | ||
410 | if (!np) | ||
411 | return -ENODEV; | ||
412 | of_node_put(np); | ||
413 | |||
414 | np = of_find_compatible_node(NULL, NULL, | ||
415 | "marvell,armada-380-mpcore-soc-ctrl"); | ||
416 | if (!np) | ||
417 | return -ENODEV; | ||
418 | mpsoc_base = of_iomap(np, 0); | ||
419 | BUG_ON(!mpsoc_base); | ||
420 | of_node_put(np); | ||
421 | |||
422 | /* Set up reset mask when powering down the cpus */ | ||
423 | reg = readl(mpsoc_base + MPCORE_RESET_CTL); | ||
424 | reg |= MPCORE_RESET_CTL_L2; | ||
425 | reg |= MPCORE_RESET_CTL_DEBUG; | ||
426 | writel(reg, mpsoc_base + MPCORE_RESET_CTL); | ||
427 | iounmap(mpsoc_base); | ||
428 | |||
429 | /* Set up delay */ | ||
430 | reg = readl(pmsu_mp_base + PMSU_POWERDOWN_DELAY); | ||
431 | reg &= ~PMSU_POWERDOWN_DELAY_MASK; | ||
432 | reg |= PMSU_DFLT_ARMADA38X_DELAY; | ||
433 | reg |= PMSU_POWERDOWN_DELAY_PMU; | ||
434 | writel(reg, pmsu_mp_base + PMSU_POWERDOWN_DELAY); | ||
435 | |||
436 | mvebu_cpu_resume = armada_38x_cpu_resume; | ||
437 | mvebu_v7_cpuidle_device.dev.platform_data = armada_38x_cpu_suspend; | ||
438 | mvebu_v7_cpuidle_device.name = "cpuidle-armada-38x"; | ||
439 | |||
440 | return 0; | ||
441 | } | ||
442 | |||
362 | static __init int armada_xp_cpuidle_init(void) | 443 | static __init int armada_xp_cpuidle_init(void) |
363 | { | 444 | { |
364 | struct device_node *np; | 445 | struct device_node *np; |
@@ -389,6 +470,8 @@ static int __init mvebu_v7_cpu_pm_init(void) | |||
389 | ret = armada_xp_cpuidle_init(); | 470 | ret = armada_xp_cpuidle_init(); |
390 | else if (of_machine_is_compatible("marvell,armada370")) | 471 | else if (of_machine_is_compatible("marvell,armada370")) |
391 | ret = armada_370_cpuidle_init(); | 472 | ret = armada_370_cpuidle_init(); |
473 | else if (of_machine_is_compatible("marvell,armada380")) | ||
474 | ret = armada_38x_cpuidle_init(); | ||
392 | else | 475 | else |
393 | return 0; | 476 | return 0; |
394 | 477 | ||
diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S index 17d7f3b3976d..a945756cfb45 100644 --- a/arch/arm/mach-mvebu/pmsu_ll.S +++ b/arch/arm/mach-mvebu/pmsu_ll.S | |||
@@ -23,6 +23,20 @@ ARM_BE8(setend be ) @ go BE8 if entered LE | |||
23 | b cpu_resume | 23 | b cpu_resume |
24 | ENDPROC(armada_370_xp_cpu_resume) | 24 | ENDPROC(armada_370_xp_cpu_resume) |
25 | 25 | ||
26 | ENTRY(armada_38x_cpu_resume) | ||
27 | /* do we need it for Armada 38x*/ | ||
28 | ARM_BE8(setend be ) @ go BE8 if entered LE | ||
29 | bl v7_invalidate_l1 | ||
30 | mrc p15, 4, r1, c15, c0 @ get SCU base address | ||
31 | orr r1, r1, #0x8 @ SCU CPU Power Status Register | ||
32 | mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID | ||
33 | and r0, r0, #15 | ||
34 | add r1, r1, r0 | ||
35 | mov r0, #0x0 | ||
36 | strb r0, [r1] @ switch SCU power state to Normal mode | ||
37 | b cpu_resume | ||
38 | ENDPROC(armada_38x_cpu_resume) | ||
39 | |||
26 | .global mvebu_boot_wa_start | 40 | .global mvebu_boot_wa_start |
27 | .global mvebu_boot_wa_end | 41 | .global mvebu_boot_wa_end |
28 | 42 | ||