e500_mpsubr.S revision 1.2 1 1.1 matt
2 1.1 matt /*
3 1.1 matt * r3 = fdt pointer (ignored)
4 1.1 matt * r4 = 0
5 1.1 matt * r5 = 0
6 1.1 matt * r6 = EPAPR magic (0x45505150)
7 1.1 matt * r7 = TLB1[0] entry size (64MB)
8 1.1 matt * r8 = 0
9 1.1 matt * r9 = 0
10 1.1 matt */
11 1.2 matt .p2align 5
12 1.2 matt ENTRY_NOPROFILE(e500_spinup_trampoline)
13 1.2 matt
14 1.2 matt stw %r7, 4(%r0) /* r7 to 4 */
15 1.2 matt
16 1.2 matt lis %r31, 0xdeadbeef@h
17 1.2 matt ori %r31, %r31, 0xdeadbeef@l
18 1.2 matt mr %r30, %r31
19 1.2 matt mr %r29, %r31
20 1.2 matt mr %r28, %r31
21 1.2 matt mr %r27, %r31
22 1.2 matt mr %r26, %r31
23 1.2 matt mr %r25, %r31
24 1.2 matt mr %r24, %r31
25 1.2 matt mr %r23, %r31
26 1.2 matt mr %r22, %r31
27 1.2 matt mr %r21, %r31
28 1.2 matt mr %r20, %r31
29 1.2 matt mr %r19, %r31
30 1.2 matt mr %r18, %r31
31 1.2 matt mr %r17, %r31
32 1.2 matt mr %r16, %r31
33 1.2 matt mr %r15, %r31
34 1.2 matt mr %r14, %r31
35 1.2 matt mr %r13, %r31
36 1.2 matt mr %r12, %r31
37 1.2 matt mr %r11, %r31
38 1.2 matt mr %r10, %r31
39 1.2 matt mr %r2, %r31
40 1.1 matt
41 1.1 matt /*
42 1.1 matt * First thing we need to do is to set SPRG0 with our cpu_info
43 1.1 matt * and get our initial stack pointer (this must be within the
44 1.1 matt * bounds of the TLB1[0] entry U-boot setup for us).
45 1.1 matt *
46 1.1 matt * cpu_hatch will return a new SP to use.
47 1.1 matt *
48 1.1 matt * All the caller-saved register are ours to use. So we will.
49 1.1 matt */
50 1.2 matt lis %r20, _C_LABEL(cpu_hatch_data)@h
51 1.2 matt ori %r20, %r20, _C_LABEL(cpu_hatch_data)@l
52 1.2 matt
53 1.2 matt li %r0, 0
54 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
55 1.2 matt eieio
56 1.1 matt
57 1.2 matt lwz %r1, HATCH_SP(%r20) /* get hatch SP */
58 1.1 matt lwz %r21, HATCH_CI(%r20) /* get cpu_info */
59 1.1 matt mtsprg0 %r21 /* save cpu_info */
60 1.2 matt lwz %r13, CI_CURLWP(%r21) /* load r13 with curlwp */
61 1.2 matt mtsprg2 %r13 /* save it in sprg2 */
62 1.2 matt
63 1.2 matt /*
64 1.2 matt * Now to synchronize timebase values. First to make sure HID0 is
65 1.2 matt * set correctly, except with the timebase disabled.
66 1.2 matt */
67 1.2 matt lwz %r22, HATCH_HID0(%r20) /* get HID0 */
68 1.2 matt li %r28, HID0_TBEN /* HID0_TBEN */
69 1.2 matt andc %r0,%r22,%r28 /* clear TBEN from HID0 */
70 1.2 matt mtspr SPR_HID0, %r0 /* set HID0 (timebase off) */
71 1.2 matt isync
72 1.2 matt lwz %r24, HATCH_TBL(%r20) /* get lower timebase value */
73 1.2 matt lwz %r23, HATCH_TBU(%r20) /* get upper timebase value */
74 1.2 matt
75 1.2 matt /*
76 1.2 matt * Figure out how much we are adjusting the timebase
77 1.2 matt */
78 1.2 matt mftbl %r4 /* get lower timebase */
79 1.2 matt subfc %r0, %r4, %r24 /* subtract from new value */
80 1.2 matt stw %r0, HATCH_TBL(%r20) /* save it */
81 1.2 matt mftbu %r3 /* get upper timebase */
82 1.2 matt subfe %r0, %r3, %r23 /* subtract from new value */
83 1.2 matt stw %r0, HATCH_TBU(%r20) /* save it */
84 1.2 matt
85 1.2 matt /*
86 1.2 matt * Since we've disabled timebase, we can set the timebase registers
87 1.2 matt * without fear of them changing. Have to do this after we read the
88 1.2 matt * previous values.
89 1.2 matt */
90 1.2 matt mttbu %r23 /* set upper timebase */
91 1.2 matt mttbl %r24 /* set lower timebase */
92 1.2 matt
93 1.2 matt /*
94 1.2 matt * Now we loop until the boot cpu tells us to enable timebase
95 1.2 matt */
96 1.2 matt 1: lwz %r0, HATCH_RUNNING(%r20) /* is it time? */
97 1.2 matt cmplwi %r0, 0
98 1.2 matt beq+ 1b
99 1.2 matt
100 1.2 matt mtspr SPR_HID0, %r22 /* start timebase running */
101 1.2 matt isync
102 1.2 matt
103 1.2 matt li %r0, 2
104 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
105 1.2 matt
106 1.1 matt /*
107 1.1 matt * We have to setup the IVOR SPRs since the ones u-boot setup
108 1.1 matt * don't work for us.
109 1.1 matt */
110 1.1 matt bl _C_LABEL(exception_init) /* setup IVORs */
111 1.1 matt
112 1.2 matt li %r0, 3
113 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
114 1.2 matt
115 1.1 matt /*
116 1.1 matt * U-boot has mapped the bottom 64MB in TLB1[0]. We are going to need
117 1.2 matt * to change this entry and it's not safe to do so while running out
118 1.2 matt * of it. So we copy TLB1[0] to TLB1[1] but set it for AS1. We then
119 1.2 matt * switch to AS1 and reload TLB1[0] with its correct value, and then we
120 1.2 matt * switch back to AS0. After that, we can load the rest of the TLB1
121 1.2 matt * entries.
122 1.1 matt */
123 1.1 matt
124 1.1 matt /*
125 1.1 matt * Fetch TLB1[0]
126 1.1 matt */
127 1.1 matt lis %r16, (MASX_TLBSEL_MAKE(1)|MAS0_ESEL_MAKE(0))@h
128 1.1 matt mtspr SPR_MAS0, %r16
129 1.1 matt tlbre
130 1.1 matt
131 1.2 matt li %r0, 4
132 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
133 1.2 matt
134 1.1 matt /*
135 1.1 matt * Copy TLB1[0] to TLB[1] and set it to use AS1
136 1.1 matt */
137 1.1 matt mfspr %r3, SPR_MAS0
138 1.1 matt addis %r3, %r3, MAS0_ESEL@h /* advance to next TLB entry */
139 1.1 matt mtspr SPR_MAS0, %r3 /* place into SPR */
140 1.1 matt mfspr %r4, SPR_MAS1
141 1.1 matt ori %r4, %r4, MAS1_TS@l /* Make it use AS1 */
142 1.1 matt mtspr SPR_MAS1, %r4
143 1.1 matt tlbwe /* write the TLB entry */
144 1.1 matt
145 1.2 matt li %r0, 5
146 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
147 1.2 matt
148 1.1 matt /*
149 1.1 matt * Let's find out what TLB1[0] entry we are supposed to use.
150 1.1 matt */
151 1.1 matt li %r3, 0
152 1.1 matt bl _C_LABEL(e500_tlb1_fetch)
153 1.1 matt lwz %r28, 0(%r3) /* load the saved TLB1 entry */
154 1.1 matt mtspr SPR_MAS0, %r28 /* place into SPRs */
155 1.1 matt mtspr SPR_MAS1, %r29
156 1.1 matt mtspr SPR_MAS2, %r30
157 1.1 matt mtspr SPR_MAS3, %r31
158 1.1 matt
159 1.2 matt li %r0, 6
160 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
161 1.2 matt
162 1.1 matt /*
163 1.1 matt * Now to switch to running in AS1
164 1.1 matt */
165 1.1 matt mfmsr %r3
166 1.1 matt ori %r4,%r3,(PSL_DS|PSL_IS)@l
167 1.1 matt mtsrr1 %r4
168 1.1 matt
169 1.1 matt bl 1f
170 1.1 matt 1: mflr %r11
171 1.1 matt addi %r4,%r11,.Las1start-1b
172 1.1 matt addi %r5,%r11,.Las1end-1b
173 1.1 matt mtsrr0 %r4
174 1.2 matt li %r0, 7
175 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
176 1.1 matt rfi /* switch to AS1, context synchronizing */
177 1.1 matt
178 1.1 matt .Las1start:
179 1.1 matt /*
180 1.1 matt * We are now running in AS1, update TLB1[0]
181 1.1 matt */
182 1.2 matt li %r0, 8
183 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
184 1.2 matt
185 1.1 matt tlbwe
186 1.1 matt
187 1.1 matt mtsrr0 %r5
188 1.1 matt mtsrr1 %r3
189 1.2 matt
190 1.2 matt li %r0, 9
191 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
192 1.2 matt
193 1.1 matt rfi /* switch back to AS0, context synchronizing */
194 1.1 matt
195 1.1 matt .Las1end:
196 1.2 matt li %r0, 10
197 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
198 1.2 matt
199 1.2 matt /*
200 1.2 matt * Now we can use our stack...
201 1.2 matt */
202 1.2 matt lwz %r0, CI_CURPCB(%r21)
203 1.2 matt lwz %r1, PCB_SP(%r0)
204 1.2 matt
205 1.2 matt li %r0, 11
206 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
207 1.2 matt
208 1.2 matt /*
209 1.2 matt * Tell spinup code we are done with the hatch stack.
210 1.2 matt */
211 1.2 matt li %r0, 0
212 1.2 matt stw %r0, HATCH_SP(%r20)
213 1.2 matt
214 1.2 matt li %r0, 12
215 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
216 1.2 matt
217 1.1 matt /*
218 1.1 matt * We now have our TLB1[0] in place. Now we need to load the rest of
219 1.1 matt * TLB1 with our entries. After this is done, we should have access
220 1.1 matt * to everything.
221 1.1 matt */
222 1.1 matt bl _C_LABEL(e500_tlb1_sync)
223 1.1 matt
224 1.2 matt li %r0, 13
225 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
226 1.2 matt
227 1.1 matt /*
228 1.1 matt * We've gotten the low level stuff done.
229 1.1 matt * Now to do more advanced stuff.
230 1.1 matt */
231 1.2 matt mr %r3, %r21
232 1.2 matt bl _C_LABEL(e500_cpu_hatch)
233 1.2 matt
234 1.2 matt li %r0, 14
235 1.2 matt stw %r0, HATCH_RUNNING(%r20) /* progress */
236 1.2 matt
237 1.2 matt /*
238 1.2 matt * Now wait to become runnable
239 1.2 matt */
240 1.2 matt bl _C_LABEL(cpu_hatch)
241 1.1 matt
242 1.1 matt wrteei 1 /* allow interrupts */
243 1.2 matt bl _C_LABEL(spl0) /* unblock interrupts */
244 1.1 matt
245 1.1 matt b _C_LABEL(idle_loop)
246