1 /* $NetBSD: cpu.c,v 1.73 2023/08/03 08:16:31 mrg Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 Tsubai Masanari. 5 * Copyright (c) 1998, 1999, 2001 Internet Research Institute, Inc. 6 * All rights reserved. 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 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by 19 * Internet Research Institute, Inc. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.73 2023/08/03 08:16:31 mrg Exp $"); 37 38 #include "opt_ppcparam.h" 39 #include "opt_multiprocessor.h" 40 #include "opt_interrupt.h" 41 #include "opt_altivec.h" 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/device.h> 46 #include <sys/types.h> 47 #include <sys/lwp.h> 48 #include <sys/cpu.h> 49 50 #include <dev/ofw/openfirm.h> 51 #include <powerpc/oea/hid.h> 52 #include <powerpc/oea/bat.h> 53 #include <powerpc/openpic.h> 54 #include <powerpc/spr.h> 55 #include <powerpc/oea/spr.h> 56 #ifdef ALTIVEC 57 #include <powerpc/altivec.h> 58 #endif 59 60 #ifdef MULTIPROCESSOR 61 #include <arch/powerpc/pic/picvar.h> 62 #include <arch/powerpc/pic/ipivar.h> 63 #endif 64 65 #include <machine/autoconf.h> 66 #include <machine/fpu.h> 67 #include <machine/pcb.h> 68 #include <machine/pio.h> 69 #include <machine/trap.h> 70 71 #include "pic_openpic.h" 72 #include "pic_u3_ht.h" 73 74 #ifndef OPENPIC 75 #if NPIC_OPENPIC > 0 76 #define OPENPIC 77 #endif /* NOPENPIC > 0 */ 78 #endif /* OPENPIC */ 79 80 int cpumatch(device_t, cfdata_t, void *); 81 void cpuattach(device_t, device_t, void *); 82 83 void identifycpu(char *); 84 static void ohare_init(void); 85 86 CFATTACH_DECL_NEW(cpu, 0, 87 cpumatch, cpuattach, NULL, NULL); 88 89 extern struct cfdriver cpu_cd; 90 91 #define HH_INTR_SECONDARY 0xf80000c0 92 #define HH_ARBCONF 0xf8000090 93 94 extern uint32_t ticks_per_intr; 95 96 #ifdef OPENPIC 97 extern void openpic_set_priority(int, int); 98 #endif 99 100 int 101 cpumatch(device_t parent, cfdata_t cf, void *aux) 102 { 103 struct confargs *ca = aux; 104 int *reg = ca->ca_reg; 105 int node; 106 107 if (strcmp(ca->ca_name, cpu_cd.cd_name) != 0) 108 return 0; 109 110 node = OF_finddevice("/cpus"); 111 if (node != -1) { 112 for (node = OF_child(node); node != 0; node = OF_peer(node)) { 113 uint32_t cpunum; 114 int l; 115 l = OF_getprop(node, "reg", &cpunum, sizeof(cpunum)); 116 if (l == 4 && reg[0] == cpunum) 117 return 1; 118 } 119 } 120 switch (reg[0]) { 121 case 0: /* primary CPU */ 122 return 1; 123 case 1: /* secondary CPU */ 124 if (OF_finddevice("/hammerhead") != -1) 125 if (in32rb(HH_ARBCONF) & 0x02) 126 return 1; 127 break; 128 } 129 130 return 0; 131 } 132 133 void cpu_OFgetspeed(device_t, struct cpu_info *); 134 135 void 136 cpu_OFgetspeed(device_t self, struct cpu_info *ci) 137 { 138 int node; 139 140 node = OF_finddevice("/cpus"); 141 if (node != -1) { 142 for (node = OF_child(node); node; node = OF_peer(node)) { 143 uint32_t cpunum; 144 int l; 145 l = OF_getprop(node, "reg", &cpunum, sizeof(cpunum)); 146 if (l == 4 && ci->ci_cpuid == cpunum) { 147 uint32_t cf; 148 l = OF_getprop(node, "clock-frequency", 149 &cf, sizeof(cf)); 150 if (l == 4) 151 ci->ci_khz = cf / 1000; 152 break; 153 } 154 } 155 } 156 } 157 158 void 159 cpuattach(device_t parent, device_t self, void *aux) 160 { 161 struct cpu_info *ci; 162 struct confargs *ca = aux; 163 int id = ca->ca_reg[0], vers, package, core; 164 165 ci = cpu_attach_common(self, id); 166 if (ci == NULL) 167 return; 168 169 package = id; 170 core = 0; 171 172 vers = (mfpvr() >> 16) & 0xffff; 173 174 if (vers == IBM970MP) { 175 core = package & 1; 176 package >>= 1; 177 } 178 cpu_topology_set(ci, package, core, 0, 0); 179 180 if (ci->ci_khz == 0) { 181 cpu_OFgetspeed(self, ci); 182 } 183 184 if (id > 0) { 185 #ifdef MULTIPROCESSOR 186 cpu_spinup(self, ci); 187 #endif 188 return; 189 } 190 191 if (OF_finddevice("/bandit/ohare") != -1) { 192 printf("%s", device_xname(self)); 193 ohare_init(); 194 } 195 } 196 197 #define CACHE_REG 0xf8000000 198 199 void 200 ohare_init(void) 201 { 202 volatile uint32_t *cache_reg, x; 203 204 /* enable L2 cache */ 205 cache_reg = mapiodev(CACHE_REG, PAGE_SIZE, false); 206 if (((cache_reg[2] >> 24) & 0x0f) >= 3) { 207 x = cache_reg[4]; 208 if ((x & 0x10) == 0) 209 x |= 0x04000000; 210 else 211 x |= 0x04000020; 212 213 cache_reg[4] = x; 214 printf(": ohare L2 cache enabled\n"); 215 } 216 } 217 218 #ifdef MULTIPROCESSOR 219 220 #if NPIC_U3_HT > 0 221 extern int have_u3_ht(void); 222 extern void __u3_ht_set_priority(int, int); 223 #else 224 #define have_u3_ht() 0 225 #define __u3_ht_set_priority(a, b) 226 #endif 227 228 int 229 md_setup_trampoline(volatile struct cpu_hatch_data *h, struct cpu_info *ci) 230 { 231 #ifdef OPENPIC 232 if ((openpic_base != NULL) || have_u3_ht()) { 233 uint32_t kl_base = (uint32_t)oea_mapiodev(0x80000000, 0x1000); 234 uint32_t gpio = kl_base + 0x5c; /* XXX */ 235 u_int node, off; 236 char cpupath[32]; 237 238 /* 239 * XXXGCC12 has: 240 * macppc/cpu.c:239:17: error: array subscript 0 is outside array bounds 241 * of 'u_int[0]' {aka 'unsigned int[]'} [-Werror=array-bounds] 242 */ 243 #pragma GCC push_options 244 #pragma GCC diagnostic ignored "-Warray-bounds" 245 /* construct an absolute branch instruction */ 246 *(u_int *)EXC_RST = /* ba cpu_spinup_trampoline */ 247 0x48000002 | (u_int)cpu_spinup_trampoline; 248 #pragma GCC pop_options 249 __syncicache((void *)EXC_RST, 0x100); 250 h->hatch_running = -1; 251 252 /* see if there's an OF property for the reset register */ 253 snprintf(cpupath, sizeof(cpupath), "/cpus/@%x", ci->ci_cpuid); 254 node = OF_finddevice(cpupath); 255 if (node == -1) { 256 printf(": no OF node for CPU %d?\n", ci->ci_cpuid); 257 return -1; 258 } 259 if (OF_getprop(node, "soft-reset", &off, 4) == 4) { 260 gpio = kl_base + off; 261 } 262 263 /* Start secondary CPU. */ 264 #if 1 265 out8(gpio, 4); 266 out8(gpio, 0); 267 #else 268 openpic_write(OPENPIC_PROC_INIT, (1 << 1)); 269 #endif 270 } else { 271 #endif /* OPENPIC */ 272 /* Start secondary CPU and stop timebase. */ 273 out32(0xf2800000, (int)cpu_spinup_trampoline); 274 cpu_send_ipi(1, IPI_NOMESG); 275 #ifdef OPENPIC 276 } 277 #endif 278 return 1; 279 } 280 281 void 282 md_presync_timebase(volatile struct cpu_hatch_data *h) 283 { 284 #ifdef OPENPIC 285 if ((openpic_base != NULL) || have_u3_ht()) { 286 uint64_t tb; 287 288 /* Sync timebase. */ 289 tb = mftb(); 290 tb += 100000; /* 3ms @ 33MHz */ 291 292 h->hatch_tbu = tb >> 32; 293 h->hatch_tbl = tb & 0xffffffff; 294 295 while (tb > mftb()) 296 ; 297 298 __asm volatile ("sync; isync"); 299 h->hatch_running = 0; 300 301 delay(500000); 302 } else 303 #endif /* OPENPIC */ 304 { 305 /* sync timebase (XXX shouldn't be zero'ed) */ 306 __asm volatile ("mttbl %0; mttbu %0; mttbl %0" :: "r"(0)); 307 } 308 } 309 310 void 311 md_start_timebase(volatile struct cpu_hatch_data *h) 312 { 313 int i; 314 #ifdef OPENPIC 315 if (!((openpic_base != NULL) || have_u3_ht())) { 316 #endif 317 /* 318 * wait for secondary spin up (1.5ms @ 604/200MHz) 319 * XXX we cannot use delay() here because timebase is not 320 * running. 321 */ 322 for (i = 0; i < 100000; i++) 323 if (h->hatch_running) 324 break; 325 326 /* Start timebase. */ 327 out32(0xf2800000, 0x100); 328 cpu_send_ipi(1, IPI_NOMESG); 329 #ifdef OPENPIC 330 } 331 #endif 332 } 333 334 void 335 md_sync_timebase(volatile struct cpu_hatch_data *h) 336 { 337 #ifdef OPENPIC 338 if ((openpic_base != NULL) || have_u3_ht()) { 339 /* Sync timebase. */ 340 u_int tbu = h->hatch_tbu; 341 u_int tbl = h->hatch_tbl; 342 while (h->hatch_running == -1) 343 ; 344 __asm volatile ("sync; isync"); 345 __asm volatile ("mttbl %0" :: "r"(0)); 346 __asm volatile ("mttbu %0" :: "r"(tbu)); 347 __asm volatile ("mttbl %0" :: "r"(tbl)); 348 } 349 #endif 350 } 351 352 void 353 md_setup_interrupts(void) 354 { 355 #ifdef OPENPIC 356 if (openpic_base) { 357 openpic_set_priority(cpu_number(), 0); 358 } else if (have_u3_ht()) { 359 __u3_ht_set_priority(cpu_number(), 0); 360 } else 361 #endif /* OPENPIC */ 362 out32(HH_INTR_SECONDARY, ~0); /* Reset interrupt. */ 363 } 364 #endif /* MULTIPROCESSOR */ 365