aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorGregory CLEMENT <gregory.clement@free-electrons.com>2014-07-23 09:00:52 -0400
committerJason Cooper <jason@lakedaemon.net>2014-07-24 07:47:40 -0400
commite53b1fd432497942a0fdfd0e89c3d30241cb4d2c (patch)
tree5c091ae93b8ca9f2db67f354eed30f4a659f6eb4 /arch/arm
parent3b9e4b1441aedcb26079f690aa11f3f9f93e5182 (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')
-rw-r--r--arch/arm/mach-mvebu/pmsu.c85
-rw-r--r--arch/arm/mach-mvebu/pmsu_ll.S14
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);
74extern void ll_enable_coherency(void); 87extern void ll_enable_coherency(void);
75 88
76extern void armada_370_xp_cpu_resume(void); 89extern void armada_370_xp_cpu_resume(void);
90extern void armada_38x_cpu_resume(void);
91
77static phys_addr_t pmsu_mp_phys_base; 92static phys_addr_t pmsu_mp_phys_base;
78static void __iomem *pmsu_mp_base; 93static 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
305static 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
326static 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 */
291void mvebu_v7_pmsu_idle_exit(void) 332void 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
402static __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
362static __init int armada_xp_cpuidle_init(void) 443static __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
24ENDPROC(armada_370_xp_cpu_resume) 24ENDPROC(armada_370_xp_cpu_resume)
25 25
26ENTRY(armada_38x_cpu_resume)
27 /* do we need it for Armada 38x*/
28ARM_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
38ENDPROC(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