xref: /netbsd-src/sys/arch/powerpc/booke/e500_mpsubr.S (revision 5e72dd2c82dd61f5c8120e1d85a4bd682e2fa214)
1/*-
2 * Copyright (c) 2011, 2012 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Matt Thomas of 3am Software Foundry.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/*
31 * r3 = fdt pointer (ignored)
32 * r4 = 0
33 * r5 = 0
34 * r6 = EPAPR magic (0x45505150)
35 * r7 = TLB1[0] entry size (64MB)
36 * r8 = 0
37 * r9 = 0
38 */
39	.p2align 5
40ENTRY_NOPROFILE(e500_spinup_trampoline)
41
42	lis	%r31, 0xdeadbeef@h
43	ori	%r31, %r31, 0xdeadbeef@l
44	mr	%r30, %r31
45	mr	%r29, %r31
46	mr	%r28, %r31
47	mr	%r27, %r31
48	mr	%r26, %r31
49	mr	%r25, %r31
50	mr	%r24, %r31
51	mr	%r23, %r31
52	mr	%r22, %r31
53	mr	%r21, %r31
54	mr	%r20, %r31
55	mr	%r19, %r31
56	mr	%r18, %r31
57	mr	%r17, %r31
58	mr	%r16, %r31
59	mr	%r15, %r31
60	mr	%r14, %r31
61	mr	%r13, %r31
62	mr	%r12, %r31
63	mr	%r11, %r31
64	mr	%r10, %r31
65	mr	%r2, %r31
66
67	/*
68	 * First thing we need to do is to set SPRG0 with our cpu_info
69	 * and get our initial stack pointer (this must be within the
70	 * bounds of the TLB1[0] entry U-boot setup for us).
71	 *
72	 * cpu_hatch will return a new SP to use.
73	 *
74	 * All the caller-saved register are ours to use.  So we will.
75	 */
76	lis	%r20, _C_LABEL(cpu_hatch_data)@h
77	ori	%r20, %r20, _C_LABEL(cpu_hatch_data)@l
78	sync
79
80	/*
81	 * Ensure that the TLB entry we are using is memory coherent.
82	 */
83	lis	%r0, (MASX_TLBSEL_MAKE(1)|MAS0_ESEL_MAKE(0))@h
84	mtspr	SPR_MAS0, %r0 			/* setup MAS0 */
85	lis	%r3, (MAS1_V|MAS1_IPROT)@h	/* V | IPROT */
86	ori	%r3, %r3, MASX_TSIZE_64MB	/* and 64MB */
87	mtspr	SPR_MAS1, %r3 			/* save MAS1 */
88	li	%r3, MAS2_M			/* set M bit */
89	mtspr	SPR_MAS2, %r3 			/* save MAS2 */
90	li	%r3, MAS3_SX|MAS3_SR|MAS3_SW	/* set kernel RWX */
91	mtspr	SPR_MAS3, %r3 			/* save MAS3 */
92	tlbwe					/* update entry */
93	isync					/* flush i-stream */
94	sync					/* sync memory. */
95
96	li	%r0, 0
97	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
98	sync
99#if 0
100	dcbf	0, %r20
101#endif
102
103	lwz	%r1, HATCH_SP(%r20)		/* get hatch SP */
104	lwz	%r21, HATCH_CI(%r20)		/* get cpu_info */
105	mtsprg0	%r21				/* save cpu_info */
106	lwz	%r13, CI_CURLWP(%r21)		/* load r13 with curlwp */
107	mtsprg2	%r13				/* save it in sprg2 */
108	addi    %r0,%r21,CI_SAVELIFO		/* get SAVE area start */
109	mtsprg3 %r0				/* save it in sprg3 */
110
111	/*
112	 * Now to synchronize timebase values.  First to make sure HID0 is
113	 * set correctly, except with the timebase disabled.
114	 */
115	lwz	%r22, HATCH_HID0(%r20)		/* get HID0 */
116	li	%r28, HID0_TBEN			/* HID0_TBEN */
117	andc	%r0,%r22,%r28			/* clear TBEN from HID0 */
118	mtspr	SPR_HID0, %r0			/* set HID0 (timebase off) */
119	isync
120	lwz	%r24, HATCH_TBL(%r20)		/* get lower timebase value */
121	lwz	%r23, HATCH_TBU(%r20)		/* get upper timebase value */
122
123	/*
124	 * Figure out how much we are adjusting the timebase
125	 */
126	mftbl	%r4				/* get lower timebase */
127	subfc	%r0, %r4, %r24			/* subtract from new value */
128	stw	%r0, HATCH_TBL(%r20)		/* save it */
129	mftbu	%r3				/* get upper timebase */
130	subfe	%r0, %r3, %r23			/* subtract from new value */
131	stw	%r0, HATCH_TBU(%r20)		/* save it */
132
133	/*
134	 * Since we've disabled timebase, we can set the timebase registers
135	 * without fear of them changing.  Have to do this after we read the
136	 * previous values.
137	 */
138	mttbu	%r23				/* set upper timebase */
139	mttbl	%r24				/* set lower timebase */
140
141	/*
142	 * Now we loop until the boot cpu tells us to enable timebase
143	 */
1441:	lwz	%r0, HATCH_RUNNING(%r20)	/* is it time? */
145	cmplwi	%r0, 0
146	beq+	1b
147
148	mtspr	SPR_HID0, %r22			/* start timebase running */
149	isync
150
151	li	%r0, 2
152	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
153	sync
154
155	/*
156	 * We have to setup the IVOR SPRs since the ones u-boot setup
157	 * don't work for us.
158	 */
159	bl	_C_LABEL(exception_init)	/* setup IVORs */
160
161	li	%r0, 3
162	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
163
164	/*
165	 * U-boot has mapped the bottom 64MB in TLB1[0].  We are going to need
166	 * to change this entry and it's not safe to do so while running out
167	 * of it.  So we copy TLB1[0] to TLB1[1] but set it for AS1.  We then
168	 * switch to AS1 and reload TLB1[0] with its correct value, and then we
169	 * switch back to AS0.  After that, we can load the rest of the TLB1
170	 * entries.
171	 */
172
173	/*
174	 * Fetch TLB1[0]
175	 */
176	lis	%r16, (MASX_TLBSEL_MAKE(1)|MAS0_ESEL_MAKE(0))@h
177	mtspr	SPR_MAS0, %r16
178	tlbre
179
180	li	%r0, 4
181	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
182
183	/*
184	 * Copy TLB1[0] to TLB[1] and set it to use AS1
185	 */
186	mfspr	%r3, SPR_MAS0
187	addis	%r3, %r3, MAS0_ESEL@h		/* advance to next TLB entry */
188	mtspr	SPR_MAS0, %r3			/* place into SPR */
189	mfspr	%r4, SPR_MAS1
190	ori	%r4, %r4, MAS1_TS@l		/* Make it use AS1 */
191	mtspr	SPR_MAS1, %r4
192	tlbwe					/* write the TLB entry */
193
194	li	%r0, 5
195	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
196
197	/*
198	 * Let's find out what TLB1 entry we are supposed to use.
199	 */
200	lwz	%r3, HATCH_TLBIDX(%r20)
201	bl	_C_LABEL(e500_tlb1_fetch)
202	lmw	%r28, 0(%r3)			/* load the saved TLB1 entry */
203
204	li	%r0, 6
205	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
206
207	/*
208	 * Now to switch to running in AS1
209	 */
210	mfmsr	%r3
211	ori	%r4,%r3,(PSL_DS|PSL_IS)@l
212	mtsrr1	%r4
213
214	bl	1f
2151:	mflr	%r11
216	addi	%r4,%r11,.Las1start-1b
217	addi	%r5,%r11,.Las1end-1b
218	mtsrr0	%r4
219	li	%r0, 7
220	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
221	rfi			/* switch to AS1, context synchronizing */
222
223.Las1start:
224	/*
225	 * We are now running in AS1, update TLB1[0]
226	 */
227	li	%r0, 8
228	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
229
230	/*
231	 * Let's clear TBL1[0] and TBL1[1]
232	 */
233	li	%r8, 0
234	mtspr	SPR_MAS1, %r8
235	mtspr	SPR_MAS2, %r8
236	mtspr	SPR_MAS3, %r8
237	mtspr	SPR_MAS7, %r8
238
239	lis	%r8, (MASX_TLBSEL_MAKE(1)|MAS0_ESEL_MAKE(0))@h
240	mtspr	SPR_MAS0, %r8
241	tlbwe
242
243	lis	%r8, (MASX_TLBSEL_MAKE(1)|MAS0_ESEL_MAKE(1))@h
244	mtspr	SPR_MAS0, %r8
245	tlbwe
246
247	/*
248	 * Now load the new TLB data into the MAS registers.
249	 */
250	mtspr	SPR_MAS0, %r28			/* place into SPRs */
251	mtspr	SPR_MAS1, %r29
252	mtspr	SPR_MAS2, %r30
253	mtspr	SPR_MAS3, %r31
254	tlbwe
255
256	mtsrr0	%r5
257	mtsrr1	%r3
258
259	li	%r0, 9
260	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
261
262	rfi			/* switch back to AS0, context synchronizing */
263
264.Las1end:
265	li	%r0, 10
266	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
267
268	/*
269	 * We now have our TLB1[0] in place.  Now we need to load the rest of
270	 * TLB1 with our entries.  After this is done, we should have access
271	 * to everything.
272	 */
273	bl	_C_LABEL(e500_tlb1_sync)
274
275	li	%r0, 11
276	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
277
278	/*
279	 * Now we can use our stack...
280	 */
281	lwz	%r3, CI_CURPCB(%r21)
282	lwz	%r1, PCB_SP(%r3)
283
284	li	%r0, 12
285	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
286
287	/*
288	 * Tell spinup code we are done with the hatch stack.
289	 */
290	li	%r0, 0
291	stw	%r0, HATCH_SP(%r20)
292
293	li	%r0, 13
294	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
295
296	/*
297	 * We've gotten the low level stuff done.
298	 * Now to do more advanced stuff.
299	 */
300	mr	%r3, %r21
301	bl	_C_LABEL(e500_cpu_hatch)
302
303	li	%r0, 14
304	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
305
306	/*
307	 * Now wait to become runnable
308	 */
309	bl	_C_LABEL(cpu_hatch)
310
311	wrteei	1				/* allow interrupts */
312	bl	_C_LABEL(spl0)			/* unblock interrupts */
313
314	b	_C_LABEL(idle_loop)
315