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