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