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