11.1Sjmcneill/* $NetBSD: cpu.c,v 1.1 2026/01/09 22:54:28 jmcneill Exp $ */ 21.1Sjmcneill 31.1Sjmcneill/*- 41.1Sjmcneill * Copyright (c) 2025 Jared McNeill <jmcneill@invisible.ca> 51.1Sjmcneill * All rights reserved. 61.1Sjmcneill * 71.1Sjmcneill * Redistribution and use in source and binary forms, with or without 81.1Sjmcneill * modification, are permitted provided that the following conditions 91.1Sjmcneill * are met: 101.1Sjmcneill * 1. Redistributions of source code must retain the above copyright 111.1Sjmcneill * notice, this list of conditions and the following disclaimer. 121.1Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright 131.1Sjmcneill * notice, this list of conditions and the following disclaimer in the 141.1Sjmcneill * documentation and/or other materials provided with the distribution. 151.1Sjmcneill * 161.1Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 171.1Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 181.1Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 191.1Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 201.1Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211.1Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 221.1Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231.1Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241.1Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251.1Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261.1Sjmcneill * SUCH DAMAGE. 271.1Sjmcneill */ 281.1Sjmcneill 291.1Sjmcneill#include <sys/cdefs.h> 301.1Sjmcneill__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.1 2026/01/09 22:54:28 jmcneill Exp $"); 311.1Sjmcneill 321.1Sjmcneill#include "opt_multiprocessor.h" 331.1Sjmcneill 341.1Sjmcneill#include <sys/param.h> 351.1Sjmcneill#include <sys/device.h> 361.1Sjmcneill#include <sys/systm.h> 371.1Sjmcneill#include <sys/bus.h> 381.1Sjmcneill#include <sys/cpu.h> 391.1Sjmcneill#include <sys/kprintf.h> 401.1Sjmcneill#include <machine/wii.h> 411.1Sjmcneill#include <machine/wiiu.h> 421.1Sjmcneill#include <powerpc/include/spr.h> 431.1Sjmcneill#include <powerpc/include/oea/spr.h> 441.1Sjmcneill#include <powerpc/include/psl.h> 451.1Sjmcneill#include <arch/evbppc/nintendo/dev/mainbus.h> 461.1Sjmcneill#include <arch/evbppc/nintendo/pic_pi.h> 471.1Sjmcneill 481.1Sjmcneillstatic int cpu_match(device_t, cfdata_t, void *); 491.1Sjmcneillstatic void cpu_attach(device_t, device_t, void *); 501.1Sjmcneill 511.1SjmcneillCFATTACH_DECL_NEW(cpu, 0, cpu_match, cpu_attach, NULL, NULL); 521.1Sjmcneill 531.1Sjmcneillextern struct cfdriver cpu_cd; 541.1Sjmcneill 551.1Sjmcneill#ifdef MULTIPROCESSOR 561.1Sjmcneillstatic uint32_t cpu_start_code[] = { 571.1Sjmcneill 0x3c600000, // lis r3, 0 /* upper 32-bits of entry pt */ 581.1Sjmcneill 0x60630000, // ori r3, r3, 0 /* lower 32-bits of entry pt */ 591.1Sjmcneill 0x7c7a03a6, // mtsrr0 r3 601.1Sjmcneill 611.1Sjmcneill 0x38600000, // li r3, 0 621.1Sjmcneill 0x7c7b03a6, // mtsrr1 r3 631.1Sjmcneill 641.1Sjmcneill 0x3c600011, // lis r3, 0x0011 651.1Sjmcneill 0x60630024, // ori r3, r3, 0x0024 661.1Sjmcneill 0x7c70fba6, // mtspr 1008, r3 /* HID0 */ 671.1Sjmcneill 681.1Sjmcneill 0x3c60b1b0, // lis r3, 0xb1b0 691.1Sjmcneill 0x7c73fba6, // mtspr 1011, r3 /* HID4 */ 701.1Sjmcneill 0x7c0004ac, // sync 711.1Sjmcneill 721.1Sjmcneill 0x3c60e7fd, // lis r3, 0xe7fd 731.1Sjmcneill 0x6063c000, // ori r3, r3, 0xc000 741.1Sjmcneill 0x7c70eba6, // mtspr 944, r3 /* HID5 */ 751.1Sjmcneill 0x7c0004ac, // sync 761.1Sjmcneill 771.1Sjmcneill 0x4c000064, // rfi 781.1Sjmcneill}; 791.1Sjmcneill#endif 801.1Sjmcneill 811.1Sjmcneillint 821.1Sjmcneillcpu_match(device_t parent, cfdata_t cf, void *aux) 831.1Sjmcneill{ 841.1Sjmcneill struct mainbus_attach_args *maa = aux; 851.1Sjmcneill 861.1Sjmcneill if (strcmp(maa->maa_name, cpu_cd.cd_name) != 0) { 871.1Sjmcneill return 0; 881.1Sjmcneill } 891.1Sjmcneill 901.1Sjmcneill return 1; 911.1Sjmcneill} 921.1Sjmcneill 931.1Sjmcneillvoid 941.1Sjmcneillcpu_attach(device_t parent, device_t self, void *aux) 951.1Sjmcneill{ 961.1Sjmcneill u_int cpu_num = device_unit(self); 971.1Sjmcneill struct cpu_info *ci; 981.1Sjmcneill 991.1Sjmcneill ci = cpu_attach_common(self, cpu_num); 1001.1Sjmcneill if (ci == NULL) { 1011.1Sjmcneill return; 1021.1Sjmcneill } 1031.1Sjmcneill 1041.1Sjmcneill#ifdef MULTIPROCESSOR 1051.1Sjmcneill if (cpu_num > 0) { 1061.1Sjmcneill cpu_spinup(self, ci); 1071.1Sjmcneill } 1081.1Sjmcneill 1091.1Sjmcneill if (wiiu_native) { 1101.1Sjmcneill /* 1111.1Sjmcneill * All cores are the same speed, but cores 1 has a bigger 1121.1Sjmcneill * cache, so let the scheduler know that the other cores 1131.1Sjmcneill * are slower. 1141.1Sjmcneill */ 1151.1Sjmcneill cpu_topology_setspeed(ci, cpu_index(ci) != 1); 1161.1Sjmcneill } 1171.1Sjmcneill#endif 1181.1Sjmcneill 1191.1Sjmcneill ci->ci_data.cpu_cc_freq = cpu_timebase; 1201.1Sjmcneill} 1211.1Sjmcneill 1221.1Sjmcneill#ifdef MULTIPROCESSOR 1231.1Sjmcneill 1241.1Sjmcneillint 1251.1Sjmcneillmd_setup_trampoline(volatile struct cpu_hatch_data *h, struct cpu_info *ci) 1261.1Sjmcneill{ 1271.1Sjmcneill extern volatile u_int cpu_spinstart_ack; 1281.1Sjmcneill u_int cpu_num = cpu_index(ci); 1291.1Sjmcneill u_int i; 1301.1Sjmcneill 1311.1Sjmcneill if (!wiiu_native) { 1321.1Sjmcneill return -1; 1331.1Sjmcneill } 1341.1Sjmcneill 1351.1Sjmcneill /* construct an absolute branch instruction */ 1361.1Sjmcneill /* ba cpu_spinup_trampoline */ 1371.1Sjmcneill cpu_start_code[0] |= ((u_int)cpu_spinup_trampoline >> 16) & 0x7fff; 1381.1Sjmcneill cpu_start_code[1] |= (u_int)cpu_spinup_trampoline & 0xffff; 1391.1Sjmcneill memcpy((void *)WIIU_BOOT_VECTOR, cpu_start_code, sizeof(cpu_start_code)); 1401.1Sjmcneill __syncicache((void *)WIIU_BOOT_VECTOR, sizeof(cpu_start_code)); 1411.1Sjmcneill h->hatch_running = -1; 1421.1Sjmcneill 1431.1Sjmcneill /* Start secondary CPU. */ 1441.1Sjmcneill mtspr(SPR_SCR, mfspr(SPR_SCR) | SPR_SCR_WAKE(cpu_num)); 1451.1Sjmcneill 1461.1Sjmcneill for (i = 0; i < 100000000; i++) { 1471.1Sjmcneill if (cpu_spinstart_ack == 0) { 1481.1Sjmcneill break; 1491.1Sjmcneill } 1501.1Sjmcneill } 1511.1Sjmcneill 1521.1Sjmcneill /* 1531.1Sjmcneill * XXX FIXME 1541.1Sjmcneill * Without this printf, CPU startup takes a lot longer. I haven't 1551.1Sjmcneill * worked out why yet, so leave it for now. 1561.1Sjmcneill */ 1571.1Sjmcneill printf_flags(TOCONS|NOTSTAMP, " \x08"); 1581.1Sjmcneill 1591.1Sjmcneill return 1; 1601.1Sjmcneill} 1611.1Sjmcneill 1621.1Sjmcneillvoid 1631.1Sjmcneillmd_presync_timebase(volatile struct cpu_hatch_data *h) 1641.1Sjmcneill{ 1651.1Sjmcneill uint64_t tb; 1661.1Sjmcneill 1671.1Sjmcneill /* Sync timebase. */ 1681.1Sjmcneill tb = mftb(); 1691.1Sjmcneill tb += 100000; /* 3ms @ 33MHz */ 1701.1Sjmcneill 1711.1Sjmcneill h->hatch_tbu = tb >> 32; 1721.1Sjmcneill h->hatch_tbl = tb & 0xffffffff; 1731.1Sjmcneill 1741.1Sjmcneill while (tb > mftb()) 1751.1Sjmcneill ; 1761.1Sjmcneill 1771.1Sjmcneill __asm volatile ("sync; isync" ::: "memory"); 1781.1Sjmcneill h->hatch_running = 0; 1791.1Sjmcneill 1801.1Sjmcneill delay(500000); 1811.1Sjmcneill} 1821.1Sjmcneill 1831.1Sjmcneillvoid 1841.1Sjmcneillmd_start_timebase(volatile struct cpu_hatch_data *h) 1851.1Sjmcneill{ 1861.1Sjmcneill u_int i; 1871.1Sjmcneill 1881.1Sjmcneill for (i = 0; i < 1000000; i++) { 1891.1Sjmcneill if (h->hatch_running) { 1901.1Sjmcneill break; 1911.1Sjmcneill } 1921.1Sjmcneill } 1931.1Sjmcneill} 1941.1Sjmcneill 1951.1Sjmcneillvoid 1961.1Sjmcneillmd_sync_timebase(volatile struct cpu_hatch_data *h) 1971.1Sjmcneill{ 1981.1Sjmcneill /* Sync timebase. */ 1991.1Sjmcneill u_int tbu = h->hatch_tbu; 2001.1Sjmcneill u_int tbl = h->hatch_tbl; 2011.1Sjmcneill 2021.1Sjmcneill while (h->hatch_running == -1) 2031.1Sjmcneill ; 2041.1Sjmcneill 2051.1Sjmcneill __asm volatile ("sync; isync" ::: "memory"); 2061.1Sjmcneill __asm volatile ("mttbl %0" :: "r"(0)); 2071.1Sjmcneill __asm volatile ("mttbu %0" :: "r"(tbu)); 2081.1Sjmcneill __asm volatile ("mttbl %0" :: "r"(tbl)); 2091.1Sjmcneill} 2101.1Sjmcneill 2111.1Sjmcneillvoid 2121.1Sjmcneillmd_setup_interrupts(void) 2131.1Sjmcneill{ 2141.1Sjmcneill mtmsr(mfmsr() & ~PSL_IP); 2151.1Sjmcneill} 2161.1Sjmcneill 2171.1Sjmcneill#endif /* !MULTIPROCESSOR */ 218