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