1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * Copyright (c) 2012, NVIDIA Corporation. All rights reserved. |
4 | */ |
5 | |
6 | #include <linux/init.h> |
7 | #include <linux/linkage.h> |
8 | |
9 | #include <soc/tegra/flowctrl.h> |
10 | #include <soc/tegra/fuse.h> |
11 | |
12 | #include <asm/assembler.h> |
13 | #include <asm/asm-offsets.h> |
14 | #include <asm/cache.h> |
15 | |
16 | #include "iomap.h" |
17 | #include "reset.h" |
18 | #include "sleep.h" |
19 | |
20 | #define PMC_SCRATCH41 0x140 |
21 | |
22 | .arch armv7-a |
23 | |
24 | #ifdef CONFIG_PM_SLEEP |
25 | /* |
26 | * tegra_resume |
27 | * |
28 | * CPU boot vector when restarting the a CPU following |
29 | * an LP2 transition. Also branched to by LP0 and LP1 resume after |
30 | * re-enabling sdram. |
31 | * |
32 | * r6: SoC ID |
33 | * r8: CPU part number |
34 | */ |
35 | ENTRY(tegra_resume) |
36 | check_cpu_part_num 0xc09, r8, r9 |
37 | bleq v7_invalidate_l1 |
38 | |
39 | cpu_id r0 |
40 | cmp r0, #0 @ CPU0? |
41 | THUMB( it ne ) |
42 | bne cpu_resume @ no |
43 | |
44 | tegra_get_soc_id TEGRA_APB_MISC_BASE, r6 |
45 | /* Are we on Tegra20? */ |
46 | cmp r6, #TEGRA20 |
47 | beq 1f @ Yes |
48 | /* Clear the flow controller flags for this CPU. */ |
49 | cpu_to_csr_reg r3, r0 |
50 | mov32 r2, TEGRA_FLOW_CTRL_BASE |
51 | ldr r1, [r2, r3] |
52 | /* Clear event & intr flag */ |
53 | orr r1, r1, \ |
54 | #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG |
55 | movw r0, #0x3FFD @ enable, cluster_switch, immed, bitmaps |
56 | @ & ext flags for CPU power mgnt |
57 | bic r1, r1, r0 |
58 | str r1, [r2, r3] |
59 | 1: |
60 | |
61 | mov32 r9, 0xc09 |
62 | cmp r8, r9 |
63 | bne end_ca9_scu_l2_resume |
64 | #ifdef CONFIG_HAVE_ARM_SCU |
65 | /* enable SCU */ |
66 | mov32 r0, TEGRA_ARM_PERIF_BASE |
67 | ldr r1, [r0] |
68 | orr r1, r1, #1 |
69 | str r1, [r0] |
70 | #endif |
71 | bl tegra_resume_trusted_foundations |
72 | |
73 | #ifdef CONFIG_CACHE_L2X0 |
74 | /* L2 cache resume & re-enable */ |
75 | bl l2c310_early_resume |
76 | #endif |
77 | end_ca9_scu_l2_resume: |
78 | mov32 r9, 0xc0f |
79 | cmp r8, r9 |
80 | bleq tegra_init_l2_for_a15 |
81 | |
82 | b cpu_resume |
83 | ENDPROC(tegra_resume) |
84 | |
85 | /* |
86 | * tegra_resume_trusted_foundations |
87 | * |
88 | * Trusted Foundations firmware initialization. |
89 | * |
90 | * Doesn't return if firmware presents. |
91 | * Corrupted registers: r1, r2 |
92 | */ |
93 | ENTRY(tegra_resume_trusted_foundations) |
94 | /* Check whether Trusted Foundations firmware presents. */ |
95 | mov32 r2, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET |
96 | ldr r1, =__tegra_cpu_reset_handler_data_offset + \ |
97 | RESET_DATA(TF_PRESENT) |
98 | ldr r1, [r2, r1] |
99 | cmp r1, #0 |
100 | reteq lr |
101 | |
102 | .arch_extension sec |
103 | /* |
104 | * First call after suspend wakes firmware. No arguments required |
105 | * for some firmware versions. Downstream kernel of ASUS TF300T uses |
106 | * r0=3 for the wake-up notification. |
107 | */ |
108 | mov r0, #3 |
109 | smc #0 |
110 | |
111 | b cpu_resume |
112 | ENDPROC(tegra_resume_trusted_foundations) |
113 | #endif |
114 | |
115 | .align L1_CACHE_SHIFT |
116 | ENTRY(__tegra_cpu_reset_handler_start) |
117 | |
118 | /* |
119 | * __tegra_cpu_reset_handler: |
120 | * |
121 | * Common handler for all CPU reset events. |
122 | * |
123 | * Register usage within the reset handler: |
124 | * |
125 | * Others: scratch |
126 | * R6 = SoC ID |
127 | * R7 = CPU present (to the OS) mask |
128 | * R8 = CPU in LP1 state mask |
129 | * R9 = CPU in LP2 state mask |
130 | * R10 = CPU number |
131 | * R11 = CPU mask |
132 | * R12 = pointer to reset handler data |
133 | * |
134 | * NOTE: This code is copied to IRAM. All code and data accesses |
135 | * must be position-independent. |
136 | */ |
137 | |
138 | .arm |
139 | .align L1_CACHE_SHIFT |
140 | ENTRY(__tegra_cpu_reset_handler) |
141 | |
142 | cpsid aif, 0x13 @ SVC mode, interrupts disabled |
143 | |
144 | tegra_get_soc_id TEGRA_APB_MISC_BASE, r6 |
145 | |
146 | adr r12, __tegra_cpu_reset_handler_data |
147 | ldr r5, [r12, #RESET_DATA(TF_PRESENT)] |
148 | cmp r5, #0 |
149 | bne after_errata |
150 | |
151 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC |
152 | t20_check: |
153 | cmp r6, #TEGRA20 |
154 | bne after_t20_check |
155 | t20_errata: |
156 | # Tegra20 is a Cortex-A9 r1p1 |
157 | mrc p15, 0, r0, c1, c0, 0 @ read system control register |
158 | orr r0, r0, #1 << 14 @ erratum 716044 |
159 | mcr p15, 0, r0, c1, c0, 0 @ write system control register |
160 | mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register |
161 | orr r0, r0, #1 << 4 @ erratum 742230 |
162 | orr r0, r0, #1 << 11 @ erratum 751472 |
163 | mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register |
164 | b after_errata |
165 | after_t20_check: |
166 | #endif |
167 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC |
168 | t30_check: |
169 | cmp r6, #TEGRA30 |
170 | bne after_t30_check |
171 | t30_errata: |
172 | # Tegra30 is a Cortex-A9 r2p9 |
173 | mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register |
174 | orr r0, r0, #1 << 6 @ erratum 743622 |
175 | orr r0, r0, #1 << 11 @ erratum 751472 |
176 | mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register |
177 | b after_errata |
178 | after_t30_check: |
179 | #endif |
180 | after_errata: |
181 | mrc p15, 0, r10, c0, c0, 5 @ MPIDR |
182 | and r10, r10, #0x3 @ R10 = CPU number |
183 | mov r11, #1 |
184 | mov r11, r11, lsl r10 @ R11 = CPU mask |
185 | |
186 | #ifdef CONFIG_SMP |
187 | /* Does the OS know about this CPU? */ |
188 | ldr r7, [r12, #RESET_DATA(MASK_PRESENT)] |
189 | tst r7, r11 @ if !present |
190 | bleq __die @ CPU not present (to OS) |
191 | #endif |
192 | |
193 | /* Waking up from LP1? */ |
194 | ldr r8, [r12, #RESET_DATA(MASK_LP1)] |
195 | tst r8, r11 @ if in_lp1 |
196 | beq __is_not_lp1 |
197 | cmp r10, #0 |
198 | bne __die @ only CPU0 can be here |
199 | ldr lr, [r12, #RESET_DATA(STARTUP_LP1)] |
200 | cmp lr, #0 |
201 | bleq __die @ no LP1 startup handler |
202 | THUMB( add lr, lr, #1 ) @ switch to Thumb mode |
203 | bx lr |
204 | __is_not_lp1: |
205 | |
206 | /* Waking up from LP2? */ |
207 | ldr r9, [r12, #RESET_DATA(MASK_LP2)] |
208 | tst r9, r11 @ if in_lp2 |
209 | beq __is_not_lp2 |
210 | ldr lr, [r12, #RESET_DATA(STARTUP_LP2)] |
211 | cmp lr, #0 |
212 | bleq __die @ no LP2 startup handler |
213 | bx lr |
214 | |
215 | __is_not_lp2: |
216 | |
217 | #ifdef CONFIG_SMP |
218 | /* |
219 | * Can only be secondary boot (initial or hotplug) |
220 | * CPU0 can't be here for Tegra20/30 |
221 | */ |
222 | cmp r6, #TEGRA114 |
223 | beq __no_cpu0_chk |
224 | cmp r10, #0 |
225 | bleq __die @ CPU0 cannot be here |
226 | __no_cpu0_chk: |
227 | ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)] |
228 | cmp lr, #0 |
229 | bleq __die @ no secondary startup handler |
230 | bx lr |
231 | #endif |
232 | |
233 | /* |
234 | * We don't know why the CPU reset. Just kill it. |
235 | * The LR register will contain the address we died at + 4. |
236 | */ |
237 | |
238 | __die: |
239 | sub lr, lr, #4 |
240 | mov32 r7, TEGRA_PMC_BASE |
241 | str lr, [r7, #PMC_SCRATCH41] |
242 | |
243 | mov32 r7, TEGRA_CLK_RESET_BASE |
244 | |
245 | /* Are we on Tegra20? */ |
246 | cmp r6, #TEGRA20 |
247 | bne 1f |
248 | |
249 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC |
250 | mov32 r0, 0x1111 |
251 | mov r1, r0, lsl r10 |
252 | str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET |
253 | #endif |
254 | 1: |
255 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC |
256 | mov32 r6, TEGRA_FLOW_CTRL_BASE |
257 | |
258 | cmp r10, #0 |
259 | moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS |
260 | moveq r2, #FLOW_CTRL_CPU0_CSR |
261 | movne r1, r10, lsl #3 |
262 | addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8) |
263 | addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8) |
264 | |
265 | /* Clear CPU "event" and "interrupt" flags and power gate |
266 | it when halting but not before it is in the "WFI" state. */ |
267 | ldr r0, [r6, +r2] |
268 | orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG |
269 | orr r0, r0, #FLOW_CTRL_CSR_ENABLE |
270 | str r0, [r6, +r2] |
271 | |
272 | /* Unconditionally halt this CPU */ |
273 | mov r0, #FLOW_CTRL_WAITEVENT |
274 | str r0, [r6, +r1] |
275 | ldr r0, [r6, +r1] @ memory barrier |
276 | |
277 | dsb |
278 | isb |
279 | wfi @ CPU should be power gated here |
280 | |
281 | /* If the CPU didn't power gate above just kill it's clock. */ |
282 | |
283 | mov r0, r11, lsl #8 |
284 | str r0, [r7, #348] @ CLK_CPU_CMPLX_SET |
285 | #endif |
286 | |
287 | /* If the CPU still isn't dead, just spin here. */ |
288 | b . |
289 | ENDPROC(__tegra_cpu_reset_handler) |
290 | |
291 | .align L1_CACHE_SHIFT |
292 | .type __tegra_cpu_reset_handler_data, %object |
293 | .globl __tegra_cpu_reset_handler_data |
294 | .globl __tegra_cpu_reset_handler_data_offset |
295 | .equ __tegra_cpu_reset_handler_data_offset, \ |
296 | . - __tegra_cpu_reset_handler_start |
297 | __tegra_cpu_reset_handler_data: |
298 | .rept TEGRA_RESET_DATA_SIZE |
299 | .long 0 |
300 | .endr |
301 | .align L1_CACHE_SHIFT |
302 | |
303 | ENTRY(__tegra_cpu_reset_handler_end) |
304 | |