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