diff options
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r-- | arch/arm/mach-tegra/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/common.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-tegra/hotplug.c | 110 | ||||
-rw-r--r-- | arch/arm/mach-tegra/sleep-t30.S | 107 | ||||
-rw-r--r-- | arch/arm/mach-tegra/sleep.h | 25 |
5 files changed, 159 insertions, 86 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index f07f99452a98..efb2f90a8f77 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile | |||
@@ -17,6 +17,7 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o | |||
17 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o | 17 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o |
18 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o | 18 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o |
19 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o | 19 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o |
20 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-t30.o | ||
20 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o | 21 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o |
21 | obj-$(CONFIG_SMP) += reset.o | 22 | obj-$(CONFIG_SMP) += reset.o |
22 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | 23 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o |
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index f3654f830991..06520564d815 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "fuse.h" | 34 | #include "fuse.h" |
35 | #include "pmc.h" | 35 | #include "pmc.h" |
36 | #include "apbio.h" | 36 | #include "apbio.h" |
37 | #include "sleep.h" | ||
37 | 38 | ||
38 | /* | 39 | /* |
39 | * Storage for debug-macro.S's state. | 40 | * Storage for debug-macro.S's state. |
@@ -147,6 +148,7 @@ void __init tegra30_init_early(void) | |||
147 | tegra_init_cache(0x441, 0x551); | 148 | tegra_init_cache(0x441, 0x551); |
148 | tegra_pmc_init(); | 149 | tegra_pmc_init(); |
149 | tegra_powergate_init(); | 150 | tegra_powergate_init(); |
151 | tegra30_hotplug_init(); | ||
150 | } | 152 | } |
151 | #endif | 153 | #endif |
152 | 154 | ||
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index d8dc9ddd6d18..be92d4c07606 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c | |||
@@ -1,91 +1,23 @@ | |||
1 | /* | 1 | /* |
2 | * linux/arch/arm/mach-realview/hotplug.c | ||
3 | * | 2 | * |
4 | * Copyright (C) 2002 ARM Ltd. | 3 | * Copyright (C) 2002 ARM Ltd. |
5 | * All Rights Reserved | 4 | * All Rights Reserved |
5 | * Copyright (c) 2010, 2012 NVIDIA Corporation. All rights reserved. | ||
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/errno.h> | ||
13 | #include <linux/smp.h> | 12 | #include <linux/smp.h> |
14 | 13 | ||
15 | #include <asm/cacheflush.h> | 14 | #include <asm/cacheflush.h> |
16 | #include <asm/cp15.h> | 15 | #include <asm/smp_plat.h> |
17 | 16 | ||
18 | static inline void cpu_enter_lowpower(void) | 17 | #include "sleep.h" |
19 | { | 18 | #include "tegra_cpu_car.h" |
20 | unsigned int v; | ||
21 | 19 | ||
22 | flush_cache_all(); | 20 | static void (*tegra_hotplug_shutdown)(void); |
23 | asm volatile( | ||
24 | " mcr p15, 0, %1, c7, c5, 0\n" | ||
25 | " mcr p15, 0, %1, c7, c10, 4\n" | ||
26 | /* | ||
27 | * Turn off coherency | ||
28 | */ | ||
29 | " mrc p15, 0, %0, c1, c0, 1\n" | ||
30 | " bic %0, %0, #0x20\n" | ||
31 | " mcr p15, 0, %0, c1, c0, 1\n" | ||
32 | " mrc p15, 0, %0, c1, c0, 0\n" | ||
33 | " bic %0, %0, %2\n" | ||
34 | " mcr p15, 0, %0, c1, c0, 0\n" | ||
35 | : "=&r" (v) | ||
36 | : "r" (0), "Ir" (CR_C) | ||
37 | : "cc"); | ||
38 | } | ||
39 | |||
40 | static inline void cpu_leave_lowpower(void) | ||
41 | { | ||
42 | unsigned int v; | ||
43 | |||
44 | asm volatile( | ||
45 | "mrc p15, 0, %0, c1, c0, 0\n" | ||
46 | " orr %0, %0, %1\n" | ||
47 | " mcr p15, 0, %0, c1, c0, 0\n" | ||
48 | " mrc p15, 0, %0, c1, c0, 1\n" | ||
49 | " orr %0, %0, #0x20\n" | ||
50 | " mcr p15, 0, %0, c1, c0, 1\n" | ||
51 | : "=&r" (v) | ||
52 | : "Ir" (CR_C) | ||
53 | : "cc"); | ||
54 | } | ||
55 | |||
56 | static inline void platform_do_lowpower(unsigned int cpu, int *spurious) | ||
57 | { | ||
58 | /* | ||
59 | * there is no power-control hardware on this platform, so all | ||
60 | * we can do is put the core into WFI; this is safe as the calling | ||
61 | * code will have already disabled interrupts | ||
62 | */ | ||
63 | for (;;) { | ||
64 | /* | ||
65 | * here's the WFI | ||
66 | */ | ||
67 | asm(".word 0xe320f003\n" | ||
68 | : | ||
69 | : | ||
70 | : "memory", "cc"); | ||
71 | |||
72 | /*if (pen_release == cpu) {*/ | ||
73 | /* | ||
74 | * OK, proper wakeup, we're done | ||
75 | */ | ||
76 | break; | ||
77 | /*}*/ | ||
78 | |||
79 | /* | ||
80 | * Getting here, means that we have come out of WFI without | ||
81 | * having been woken up - this shouldn't happen | ||
82 | * | ||
83 | * Just note it happening - when we're woken, we can report | ||
84 | * its occurrence. | ||
85 | */ | ||
86 | (*spurious)++; | ||
87 | } | ||
88 | } | ||
89 | 21 | ||
90 | int platform_cpu_kill(unsigned int cpu) | 22 | int platform_cpu_kill(unsigned int cpu) |
91 | { | 23 | { |
@@ -99,22 +31,20 @@ int platform_cpu_kill(unsigned int cpu) | |||
99 | */ | 31 | */ |
100 | void platform_cpu_die(unsigned int cpu) | 32 | void platform_cpu_die(unsigned int cpu) |
101 | { | 33 | { |
102 | int spurious = 0; | 34 | cpu = cpu_logical_map(cpu); |
103 | 35 | ||
104 | /* | 36 | /* Flush the L1 data cache. */ |
105 | * we're ready for shutdown now, so do it | 37 | flush_cache_all(); |
106 | */ | ||
107 | cpu_enter_lowpower(); | ||
108 | platform_do_lowpower(cpu, &spurious); | ||
109 | 38 | ||
110 | /* | 39 | /* Shut down the current CPU. */ |
111 | * bring this CPU back into the world of cache | 40 | tegra_hotplug_shutdown(); |
112 | * coherency, and then restore interrupts | 41 | |
113 | */ | 42 | /* Clock gate the CPU */ |
114 | cpu_leave_lowpower(); | 43 | tegra_wait_cpu_in_reset(cpu); |
44 | tegra_disable_cpu_clock(cpu); | ||
115 | 45 | ||
116 | if (spurious) | 46 | /* Should never return here. */ |
117 | pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); | 47 | BUG(); |
118 | } | 48 | } |
119 | 49 | ||
120 | int platform_cpu_disable(unsigned int cpu) | 50 | int platform_cpu_disable(unsigned int cpu) |
@@ -125,3 +55,11 @@ int platform_cpu_disable(unsigned int cpu) | |||
125 | */ | 55 | */ |
126 | return cpu == 0 ? -EPERM : 0; | 56 | return cpu == 0 ? -EPERM : 0; |
127 | } | 57 | } |
58 | |||
59 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | ||
60 | extern void tegra30_hotplug_shutdown(void); | ||
61 | void __init tegra30_hotplug_init(void) | ||
62 | { | ||
63 | tegra_hotplug_shutdown = tegra30_hotplug_shutdown; | ||
64 | } | ||
65 | #endif | ||
diff --git a/arch/arm/mach-tegra/sleep-t30.S b/arch/arm/mach-tegra/sleep-t30.S new file mode 100644 index 000000000000..777d9cee8b90 --- /dev/null +++ b/arch/arm/mach-tegra/sleep-t30.S | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, NVIDIA Corporation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/linkage.h> | ||
18 | |||
19 | #include <asm/assembler.h> | ||
20 | |||
21 | #include <mach/iomap.h> | ||
22 | |||
23 | #include "sleep.h" | ||
24 | #include "flowctrl.h" | ||
25 | |||
26 | #define TEGRA30_POWER_HOTPLUG_SHUTDOWN (1 << 27) /* Hotplug shutdown */ | ||
27 | |||
28 | #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP) | ||
29 | /* | ||
30 | * tegra30_hotplug_shutdown(void) | ||
31 | * | ||
32 | * Powergates the current CPU. | ||
33 | * Should never return. | ||
34 | */ | ||
35 | ENTRY(tegra30_hotplug_shutdown) | ||
36 | /* Turn off SMP coherency */ | ||
37 | exit_smp r4, r5 | ||
38 | |||
39 | /* Powergate this CPU */ | ||
40 | mov r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN | ||
41 | bl tegra30_cpu_shutdown | ||
42 | mov pc, lr @ should never get here | ||
43 | ENDPROC(tegra30_hotplug_shutdown) | ||
44 | |||
45 | /* | ||
46 | * tegra30_cpu_shutdown(unsigned long flags) | ||
47 | * | ||
48 | * Puts the current CPU in wait-for-event mode on the flow controller | ||
49 | * and powergates it -- flags (in R0) indicate the request type. | ||
50 | * Must never be called for CPU 0. | ||
51 | * | ||
52 | * corrupts r0-r4, r12 | ||
53 | */ | ||
54 | ENTRY(tegra30_cpu_shutdown) | ||
55 | cpu_id r3 | ||
56 | cmp r3, #0 | ||
57 | moveq pc, lr @ Must never be called for CPU 0 | ||
58 | |||
59 | ldr r12, =TEGRA_FLOW_CTRL_VIRT | ||
60 | cpu_to_csr_reg r1, r3 | ||
61 | add r1, r1, r12 @ virtual CSR address for this CPU | ||
62 | cpu_to_halt_reg r2, r3 | ||
63 | add r2, r2, r12 @ virtual HALT_EVENTS address for this CPU | ||
64 | |||
65 | /* | ||
66 | * Clear this CPU's "event" and "interrupt" flags and power gate | ||
67 | * it when halting but not before it is in the "WFE" state. | ||
68 | */ | ||
69 | movw r12, \ | ||
70 | FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | \ | ||
71 | FLOW_CTRL_CSR_ENABLE | ||
72 | mov r4, #(1 << 4) | ||
73 | orr r12, r12, r4, lsl r3 | ||
74 | str r12, [r1] | ||
75 | |||
76 | /* Halt this CPU. */ | ||
77 | mov r3, #0x400 | ||
78 | delay_1: | ||
79 | subs r3, r3, #1 @ delay as a part of wfe war. | ||
80 | bge delay_1; | ||
81 | cpsid a @ disable imprecise aborts. | ||
82 | ldr r3, [r1] @ read CSR | ||
83 | str r3, [r1] @ clear CSR | ||
84 | tst r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN | ||
85 | movne r3, #FLOW_CTRL_WAITEVENT @ For hotplug | ||
86 | str r3, [r2] | ||
87 | ldr r0, [r2] | ||
88 | b wfe_war | ||
89 | |||
90 | __cpu_reset_again: | ||
91 | dsb | ||
92 | .align 5 | ||
93 | wfe @ CPU should be power gated here | ||
94 | wfe_war: | ||
95 | b __cpu_reset_again | ||
96 | |||
97 | /* | ||
98 | * 38 nop's, which fills reset of wfe cache line and | ||
99 | * 4 more cachelines with nop | ||
100 | */ | ||
101 | .rept 38 | ||
102 | nop | ||
103 | .endr | ||
104 | b . @ should never get here | ||
105 | |||
106 | ENDPROC(tegra30_cpu_shutdown) | ||
107 | #endif | ||
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h index d0c7a8b1c885..0f047eb3ca2e 100644 --- a/arch/arm/mach-tegra/sleep.h +++ b/arch/arm/mach-tegra/sleep.h | |||
@@ -19,6 +19,8 @@ | |||
19 | 19 | ||
20 | #include <mach/iomap.h> | 20 | #include <mach/iomap.h> |
21 | 21 | ||
22 | #define TEGRA_ARM_PERIF_VIRT (TEGRA_ARM_PERIF_BASE - IO_CPU_PHYS \ | ||
23 | + IO_CPU_VIRT) | ||
22 | #define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \ | 24 | #define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \ |
23 | + IO_PPSB_VIRT) | 25 | + IO_PPSB_VIRT) |
24 | 26 | ||
@@ -52,5 +54,28 @@ | |||
52 | movw \reg, #:lower16:\val | 54 | movw \reg, #:lower16:\val |
53 | movt \reg, #:upper16:\val | 55 | movt \reg, #:upper16:\val |
54 | .endm | 56 | .endm |
57 | |||
58 | /* Macro to exit SMP coherency. */ | ||
59 | .macro exit_smp, tmp1, tmp2 | ||
60 | mrc p15, 0, \tmp1, c1, c0, 1 @ ACTLR | ||
61 | bic \tmp1, \tmp1, #(1<<6) | (1<<0) @ clear ACTLR.SMP | ACTLR.FW | ||
62 | mcr p15, 0, \tmp1, c1, c0, 1 @ ACTLR | ||
63 | isb | ||
64 | cpu_id \tmp1 | ||
65 | mov \tmp1, \tmp1, lsl #2 | ||
66 | mov \tmp2, #0xf | ||
67 | mov \tmp2, \tmp2, lsl \tmp1 | ||
68 | mov32 \tmp1, TEGRA_ARM_PERIF_VIRT + 0xC | ||
69 | str \tmp2, [\tmp1] @ invalidate SCU tags for CPU | ||
70 | dsb | ||
71 | .endm | ||
72 | #else | ||
73 | |||
74 | #ifdef CONFIG_HOTPLUG_CPU | ||
75 | void tegra30_hotplug_init(void); | ||
76 | #else | ||
77 | static inline void tegra30_hotplug_init(void) {} | ||
78 | #endif | ||
79 | |||
55 | #endif | 80 | #endif |
56 | #endif | 81 | #endif |