cpu.c revision 1.1
1/* $NetBSD: cpu.c,v 1.1 2026/01/09 22:54:28 jmcneill Exp $ */ 2 3/*- 4 * Copyright (c) 2025 Jared McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.1 2026/01/09 22:54:28 jmcneill Exp $"); 31 32#include "opt_multiprocessor.h" 33 34#include <sys/param.h> 35#include <sys/device.h> 36#include <sys/systm.h> 37#include <sys/bus.h> 38#include <sys/cpu.h> 39#include <sys/kprintf.h> 40#include <machine/wii.h> 41#include <machine/wiiu.h> 42#include <powerpc/include/spr.h> 43#include <powerpc/include/oea/spr.h> 44#include <powerpc/include/psl.h> 45#include <arch/evbppc/nintendo/dev/mainbus.h> 46#include <arch/evbppc/nintendo/pic_pi.h> 47 48static int cpu_match(device_t, cfdata_t, void *); 49static void cpu_attach(device_t, device_t, void *); 50 51CFATTACH_DECL_NEW(cpu, 0, cpu_match, cpu_attach, NULL, NULL); 52 53extern struct cfdriver cpu_cd; 54 55#ifdef MULTIPROCESSOR 56static uint32_t cpu_start_code[] = { 57 0x3c600000, // lis r3, 0 /* upper 32-bits of entry pt */ 58 0x60630000, // ori r3, r3, 0 /* lower 32-bits of entry pt */ 59 0x7c7a03a6, // mtsrr0 r3 60 61 0x38600000, // li r3, 0 62 0x7c7b03a6, // mtsrr1 r3 63 64 0x3c600011, // lis r3, 0x0011 65 0x60630024, // ori r3, r3, 0x0024 66 0x7c70fba6, // mtspr 1008, r3 /* HID0 */ 67 68 0x3c60b1b0, // lis r3, 0xb1b0 69 0x7c73fba6, // mtspr 1011, r3 /* HID4 */ 70 0x7c0004ac, // sync 71 72 0x3c60e7fd, // lis r3, 0xe7fd 73 0x6063c000, // ori r3, r3, 0xc000 74 0x7c70eba6, // mtspr 944, r3 /* HID5 */ 75 0x7c0004ac, // sync 76 77 0x4c000064, // rfi 78}; 79#endif 80 81int 82cpu_match(device_t parent, cfdata_t cf, void *aux) 83{ 84 struct mainbus_attach_args *maa = aux; 85 86 if (strcmp(maa->maa_name, cpu_cd.cd_name) != 0) { 87 return 0; 88 } 89 90 return 1; 91} 92 93void 94cpu_attach(device_t parent, device_t self, void *aux) 95{ 96 u_int cpu_num = device_unit(self); 97 struct cpu_info *ci; 98 99 ci = cpu_attach_common(self, cpu_num); 100 if (ci == NULL) { 101 return; 102 } 103 104#ifdef MULTIPROCESSOR 105 if (cpu_num > 0) { 106 cpu_spinup(self, ci); 107 } 108 109 if (wiiu_native) { 110 /* 111 * All cores are the same speed, but cores 1 has a bigger 112 * cache, so let the scheduler know that the other cores 113 * are slower. 114 */ 115 cpu_topology_setspeed(ci, cpu_index(ci) != 1); 116 } 117#endif 118 119 ci->ci_data.cpu_cc_freq = cpu_timebase; 120} 121 122#ifdef MULTIPROCESSOR 123 124int 125md_setup_trampoline(volatile struct cpu_hatch_data *h, struct cpu_info *ci) 126{ 127 extern volatile u_int cpu_spinstart_ack; 128 u_int cpu_num = cpu_index(ci); 129 u_int i; 130 131 if (!wiiu_native) { 132 return -1; 133 } 134 135 /* construct an absolute branch instruction */ 136 /* ba cpu_spinup_trampoline */ 137 cpu_start_code[0] |= ((u_int)cpu_spinup_trampoline >> 16) & 0x7fff; 138 cpu_start_code[1] |= (u_int)cpu_spinup_trampoline & 0xffff; 139 memcpy((void *)WIIU_BOOT_VECTOR, cpu_start_code, sizeof(cpu_start_code)); 140 __syncicache((void *)WIIU_BOOT_VECTOR, sizeof(cpu_start_code)); 141 h->hatch_running = -1; 142 143 /* Start secondary CPU. */ 144 mtspr(SPR_SCR, mfspr(SPR_SCR) | SPR_SCR_WAKE(cpu_num)); 145 146 for (i = 0; i < 100000000; i++) { 147 if (cpu_spinstart_ack == 0) { 148 break; 149 } 150 } 151 152 /* 153 * XXX FIXME 154 * Without this printf, CPU startup takes a lot longer. I haven't 155 * worked out why yet, so leave it for now. 156 */ 157 printf_flags(TOCONS|NOTSTAMP, " \x08"); 158 159 return 1; 160} 161 162void 163md_presync_timebase(volatile struct cpu_hatch_data *h) 164{ 165 uint64_t tb; 166 167 /* Sync timebase. */ 168 tb = mftb(); 169 tb += 100000; /* 3ms @ 33MHz */ 170 171 h->hatch_tbu = tb >> 32; 172 h->hatch_tbl = tb & 0xffffffff; 173 174 while (tb > mftb()) 175 ; 176 177 __asm volatile ("sync; isync" ::: "memory"); 178 h->hatch_running = 0; 179 180 delay(500000); 181} 182 183void 184md_start_timebase(volatile struct cpu_hatch_data *h) 185{ 186 u_int i; 187 188 for (i = 0; i < 1000000; i++) { 189 if (h->hatch_running) { 190 break; 191 } 192 } 193} 194 195void 196md_sync_timebase(volatile struct cpu_hatch_data *h) 197{ 198 /* Sync timebase. */ 199 u_int tbu = h->hatch_tbu; 200 u_int tbl = h->hatch_tbl; 201 202 while (h->hatch_running == -1) 203 ; 204 205 __asm volatile ("sync; isync" ::: "memory"); 206 __asm volatile ("mttbl %0" :: "r"(0)); 207 __asm volatile ("mttbu %0" :: "r"(tbu)); 208 __asm volatile ("mttbl %0" :: "r"(tbl)); 209} 210 211void 212md_setup_interrupts(void) 213{ 214 mtmsr(mfmsr() & ~PSL_IP); 215} 216 217#endif /* !MULTIPROCESSOR */ 218