diff options
Diffstat (limited to 'arch/arm/mach-tegra/headsmp.S')
-rw-r--r-- | arch/arm/mach-tegra/headsmp.S | 167 |
1 files changed, 159 insertions, 8 deletions
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S index b5349b2f13d..fef9c2c5137 100644 --- a/arch/arm/mach-tegra/headsmp.S +++ b/arch/arm/mach-tegra/headsmp.S | |||
@@ -1,6 +1,23 @@ | |||
1 | #include <linux/linkage.h> | 1 | #include <linux/linkage.h> |
2 | #include <linux/init.h> | 2 | #include <linux/init.h> |
3 | 3 | ||
4 | #include <asm/cache.h> | ||
5 | |||
6 | #include <mach/iomap.h> | ||
7 | |||
8 | #include "flowctrl.h" | ||
9 | #include "reset.h" | ||
10 | |||
11 | #define APB_MISC_GP_HIDREV 0x804 | ||
12 | #define PMC_SCRATCH41 0x140 | ||
13 | |||
14 | #define RESET_DATA(x) ((TEGRA_RESET_##x)*4) | ||
15 | |||
16 | .macro mov32, reg, val | ||
17 | movw \reg, #:lower16:\val | ||
18 | movt \reg, #:upper16:\val | ||
19 | .endm | ||
20 | |||
4 | .section ".text.head", "ax" | 21 | .section ".text.head", "ax" |
5 | __CPUINIT | 22 | __CPUINIT |
6 | 23 | ||
@@ -47,15 +64,149 @@ ENTRY(v7_invalidate_l1) | |||
47 | mov pc, lr | 64 | mov pc, lr |
48 | ENDPROC(v7_invalidate_l1) | 65 | ENDPROC(v7_invalidate_l1) |
49 | 66 | ||
67 | |||
50 | ENTRY(tegra_secondary_startup) | 68 | ENTRY(tegra_secondary_startup) |
51 | msr cpsr_fsxc, #0xd3 | ||
52 | bl v7_invalidate_l1 | 69 | bl v7_invalidate_l1 |
53 | mrc p15, 0, r0, c0, c0, 5 | 70 | /* Enable coresight */ |
54 | and r0, r0, #15 | 71 | mov32 r0, 0xC5ACCE55 |
55 | ldr r1, =0x6000f100 | 72 | mcr p14, 0, r0, c7, c12, 6 |
56 | str r0, [r1] | ||
57 | 1: ldr r2, [r1] | ||
58 | cmp r0, r2 | ||
59 | beq 1b | ||
60 | b secondary_startup | 73 | b secondary_startup |
61 | ENDPROC(tegra_secondary_startup) | 74 | ENDPROC(tegra_secondary_startup) |
75 | |||
76 | .align L1_CACHE_SHIFT | ||
77 | ENTRY(__tegra_cpu_reset_handler_start) | ||
78 | |||
79 | /* | ||
80 | * __tegra_cpu_reset_handler: | ||
81 | * | ||
82 | * Common handler for all CPU reset events. | ||
83 | * | ||
84 | * Register usage within the reset handler: | ||
85 | * | ||
86 | * R7 = CPU present (to the OS) mask | ||
87 | * R8 = CPU in LP1 state mask | ||
88 | * R9 = CPU in LP2 state mask | ||
89 | * R10 = CPU number | ||
90 | * R11 = CPU mask | ||
91 | * R12 = pointer to reset handler data | ||
92 | * | ||
93 | * NOTE: This code is copied to IRAM. All code and data accesses | ||
94 | * must be position-independent. | ||
95 | */ | ||
96 | |||
97 | .align L1_CACHE_SHIFT | ||
98 | ENTRY(__tegra_cpu_reset_handler) | ||
99 | |||
100 | cpsid aif, 0x13 @ SVC mode, interrupts disabled | ||
101 | mrc p15, 0, r10, c0, c0, 5 @ MPIDR | ||
102 | and r10, r10, #0x3 @ R10 = CPU number | ||
103 | mov r11, #1 | ||
104 | mov r11, r11, lsl r10 @ R11 = CPU mask | ||
105 | adr r12, __tegra_cpu_reset_handler_data | ||
106 | |||
107 | #ifdef CONFIG_SMP | ||
108 | /* Does the OS know about this CPU? */ | ||
109 | ldr r7, [r12, #RESET_DATA(MASK_PRESENT)] | ||
110 | tst r7, r11 @ if !present | ||
111 | bleq __die @ CPU not present (to OS) | ||
112 | #endif | ||
113 | |||
114 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
115 | /* Are we on Tegra20? */ | ||
116 | mov32 r6, TEGRA_APB_MISC_BASE | ||
117 | ldr r0, [r6, #APB_MISC_GP_HIDREV] | ||
118 | and r0, r0, #0xff00 | ||
119 | cmp r0, #(0x20 << 8) | ||
120 | bne 1f | ||
121 | /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */ | ||
122 | mov32 r6, TEGRA_PMC_BASE | ||
123 | mov r0, #0 | ||
124 | cmp r10, #0 | ||
125 | strne r0, [r6, #PMC_SCRATCH41] | ||
126 | 1: | ||
127 | #endif | ||
128 | |||
129 | #ifdef CONFIG_SMP | ||
130 | /* | ||
131 | * Can only be secondary boot (initial or hotplug) but CPU 0 | ||
132 | * cannot be here. | ||
133 | */ | ||
134 | cmp r10, #0 | ||
135 | bleq __die @ CPU0 cannot be here | ||
136 | ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)] | ||
137 | cmp lr, #0 | ||
138 | bleq __die @ no secondary startup handler | ||
139 | bx lr | ||
140 | #endif | ||
141 | |||
142 | /* | ||
143 | * We don't know why the CPU reset. Just kill it. | ||
144 | * The LR register will contain the address we died at + 4. | ||
145 | */ | ||
146 | |||
147 | __die: | ||
148 | sub lr, lr, #4 | ||
149 | mov32 r7, TEGRA_PMC_BASE | ||
150 | str lr, [r7, #PMC_SCRATCH41] | ||
151 | |||
152 | mov32 r7, TEGRA_CLK_RESET_BASE | ||
153 | |||
154 | /* Are we on Tegra20? */ | ||
155 | mov32 r6, TEGRA_APB_MISC_BASE | ||
156 | ldr r0, [r6, #APB_MISC_GP_HIDREV] | ||
157 | and r0, r0, #0xff00 | ||
158 | cmp r0, #(0x20 << 8) | ||
159 | bne 1f | ||
160 | |||
161 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
162 | mov32 r0, 0x1111 | ||
163 | mov r1, r0, lsl r10 | ||
164 | str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET | ||
165 | #endif | ||
166 | 1: | ||
167 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | ||
168 | mov32 r6, TEGRA_FLOW_CTRL_BASE | ||
169 | |||
170 | cmp r10, #0 | ||
171 | moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS | ||
172 | moveq r2, #FLOW_CTRL_CPU0_CSR | ||
173 | movne r1, r10, lsl #3 | ||
174 | addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8) | ||
175 | addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8) | ||
176 | |||
177 | /* Clear CPU "event" and "interrupt" flags and power gate | ||
178 | it when halting but not before it is in the "WFI" state. */ | ||
179 | ldr r0, [r6, +r2] | ||
180 | orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | ||
181 | orr r0, r0, #FLOW_CTRL_CSR_ENABLE | ||
182 | str r0, [r6, +r2] | ||
183 | |||
184 | /* Unconditionally halt this CPU */ | ||
185 | mov r0, #FLOW_CTRL_WAITEVENT | ||
186 | str r0, [r6, +r1] | ||
187 | ldr r0, [r6, +r1] @ memory barrier | ||
188 | |||
189 | dsb | ||
190 | isb | ||
191 | wfi @ CPU should be power gated here | ||
192 | |||
193 | /* If the CPU didn't power gate above just kill it's clock. */ | ||
194 | |||
195 | mov r0, r11, lsl #8 | ||
196 | str r0, [r7, #348] @ CLK_CPU_CMPLX_SET | ||
197 | #endif | ||
198 | |||
199 | /* If the CPU still isn't dead, just spin here. */ | ||
200 | b . | ||
201 | ENDPROC(__tegra_cpu_reset_handler) | ||
202 | |||
203 | .align L1_CACHE_SHIFT | ||
204 | .type __tegra_cpu_reset_handler_data, %object | ||
205 | .globl __tegra_cpu_reset_handler_data | ||
206 | __tegra_cpu_reset_handler_data: | ||
207 | .rept TEGRA_RESET_DATA_SIZE | ||
208 | .long 0 | ||
209 | .endr | ||
210 | .align L1_CACHE_SHIFT | ||
211 | |||
212 | ENTRY(__tegra_cpu_reset_handler_end) | ||