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