1#include <linux/linkage.h>
2#include <linux/init.h>
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
21        .section ".text.head", "ax"
22	__CPUINIT
23
24/*
25 * Tegra specific entry point for secondary CPUs.
26 *   The secondary kernel init calls v7_flush_dcache_all before it enables
27 *   the L1; however, the L1 comes out of reset in an undefined state, so
28 *   the clean + invalidate performed by v7_flush_dcache_all causes a bunch
29 *   of cache lines with uninitialized data and uninitialized tags to get
30 *   written out to memory, which does really unpleasant things to the main
31 *   processor.  We fix this by performing an invalidate, rather than a
32 *   clean + invalidate, before jumping into the kernel.
33 */
34ENTRY(v7_invalidate_l1)
35        mov     r0, #0
36        mcr     p15, 2, r0, c0, c0, 0
37        mrc     p15, 1, r0, c0, c0, 0
38
39        ldr     r1, =0x7fff
40        and     r2, r1, r0, lsr #13
41
42        ldr     r1, =0x3ff
43
44        and     r3, r1, r0, lsr #3  @ NumWays - 1
45        add     r2, r2, #1          @ NumSets
46
47        and     r0, r0, #0x7
48        add     r0, r0, #4          @ SetShift
49
50        clz     r1, r3              @ WayShift
51        add     r4, r3, #1          @ NumWays
521:      sub     r2, r2, #1          @ NumSets--
53        mov     r3, r4              @ Temp = NumWays
542:      subs    r3, r3, #1          @ Temp--
55        mov     r5, r3, lsl r1
56        mov     r6, r2, lsl r0
57        orr     r5, r5, r6          @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
58        mcr     p15, 0, r5, c7, c6, 2
59        bgt     2b
60        cmp     r2, #0
61        bgt     1b
62        dsb
63        isb
64        mov     pc, lr
65ENDPROC(v7_invalidate_l1)
66
67
68ENTRY(tegra_secondary_startup)
69        bl      v7_invalidate_l1
70	/* Enable coresight */
71	mov32	r0, 0xC5ACCE55
72	mcr	p14, 0, r0, c7, c12, 6
73        b       secondary_startup
74ENDPROC(tegra_secondary_startup)
75
76	.align L1_CACHE_SHIFT
77ENTRY(__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
98ENTRY(__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]
1261:
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
1661:
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	.
201ENDPROC(__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
212ENTRY(__tegra_cpu_reset_handler_end)
213