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