ahb.c revision 1.1
11.1Sjmcneill/* $NetBSD: ahb.c,v 1.1 2026/01/09 22:54:29 jmcneill Exp $ */ 21.1Sjmcneill 31.1Sjmcneill/*- 41.1Sjmcneill * Copyright (c) 2024 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: ahb.c,v 1.1 2026/01/09 22:54:29 jmcneill Exp $"); 311.1Sjmcneill 321.1Sjmcneill#include <sys/param.h> 331.1Sjmcneill#include <sys/bus.h> 341.1Sjmcneill#include <sys/device.h> 351.1Sjmcneill#include <sys/systm.h> 361.1Sjmcneill#include <sys/bitops.h> 371.1Sjmcneill 381.1Sjmcneill#include <machine/intr.h> 391.1Sjmcneill#include <machine/wii.h> 401.1Sjmcneill#include <machine/wiiu.h> 411.1Sjmcneill#include <machine/pio.h> 421.1Sjmcneill#include <powerpc/pic/picvar.h> 431.1Sjmcneill 441.1Sjmcneill#include "locators.h" 451.1Sjmcneill#include "mainbus.h" 461.1Sjmcneill#include "ahb.h" 471.1Sjmcneill 481.1Sjmcneill#define WR4(reg, val) out32(reg, val) 491.1Sjmcneill#define RD4(reg) in32(reg) 501.1Sjmcneill 511.1Sjmcneillstatic struct mainbus_attach_args ahb_maa; 521.1Sjmcneillstatic uint32_t pic_irqmask[2]; 531.1Sjmcneill 541.1Sjmcneillstatic int ahb_match(device_t, cfdata_t, void *); 551.1Sjmcneillstatic void ahb_attach(device_t, device_t, void *); 561.1Sjmcneill 571.1Sjmcneillstatic int ahb_search(device_t, cfdata_t, const int *, void *); 581.1Sjmcneillstatic int ahb_print(void *, const char *); 591.1Sjmcneill 601.1Sjmcneillstatic void ahb_intr_init(int); 611.1Sjmcneill 621.1Sjmcneillstatic void hollywood_enable_irq(struct pic_ops *, int, int); 631.1Sjmcneillstatic void hollywood_disable_irq(struct pic_ops *, int); 641.1Sjmcneillstatic int hollywood_get_irq(struct pic_ops *, int); 651.1Sjmcneillstatic void hollywood_ack_irq(struct pic_ops *, int); 661.1Sjmcneillstatic void hollywood_establish_irq(struct pic_ops *, int, int, int); 671.1Sjmcneill 681.1Sjmcneillstatic struct pic_ops hollywood_pic = { 691.1Sjmcneill .pic_name = "hollywood", 701.1Sjmcneill .pic_numintrs = 32, 711.1Sjmcneill .pic_cookie = NULL, 721.1Sjmcneill .pic_enable_irq = hollywood_enable_irq, 731.1Sjmcneill .pic_reenable_irq = hollywood_enable_irq, 741.1Sjmcneill .pic_disable_irq = hollywood_disable_irq, 751.1Sjmcneill .pic_get_irq = hollywood_get_irq, 761.1Sjmcneill .pic_ack_irq = hollywood_ack_irq, 771.1Sjmcneill .pic_establish_irq = hollywood_establish_irq, 781.1Sjmcneill}; 791.1Sjmcneill 801.1Sjmcneillstatic void latte_enable_irq(struct pic_ops *, int, int); 811.1Sjmcneillstatic void latte_disable_irq(struct pic_ops *, int); 821.1Sjmcneillstatic int latte_get_irq(struct pic_ops *, int); 831.1Sjmcneillstatic void latte_ack_irq(struct pic_ops *, int); 841.1Sjmcneillstatic void latte_establish_irq(struct pic_ops *, int, int, int); 851.1Sjmcneill 861.1Sjmcneillstatic struct pic_ops latte_pic = { 871.1Sjmcneill .pic_name = "latte", 881.1Sjmcneill .pic_numintrs = 64, 891.1Sjmcneill .pic_cookie = NULL, 901.1Sjmcneill .pic_enable_irq = latte_enable_irq, 911.1Sjmcneill .pic_reenable_irq = latte_enable_irq, 921.1Sjmcneill .pic_disable_irq = latte_disable_irq, 931.1Sjmcneill .pic_get_irq = latte_get_irq, 941.1Sjmcneill .pic_ack_irq = latte_ack_irq, 951.1Sjmcneill .pic_establish_irq = latte_establish_irq, 961.1Sjmcneill}; 971.1Sjmcneill 981.1SjmcneillCFATTACH_DECL_NEW(ahb, 0, ahb_match, ahb_attach, NULL, NULL); 991.1Sjmcneill 1001.1Sjmcneillstatic int 1011.1Sjmcneillahb_match(device_t parent, cfdata_t cf, void *aux) 1021.1Sjmcneill{ 1031.1Sjmcneill struct mainbus_attach_args *maa = aux; 1041.1Sjmcneill 1051.1Sjmcneill return strcmp(maa->maa_name, "ahb") == 0; 1061.1Sjmcneill} 1071.1Sjmcneill 1081.1Sjmcneillstatic void 1091.1Sjmcneillahb_attach(device_t parent, device_t self, void *aux) 1101.1Sjmcneill{ 1111.1Sjmcneill uint32_t val; 1121.1Sjmcneill 1131.1Sjmcneill ahb_maa = *(struct mainbus_attach_args *)aux; 1141.1Sjmcneill 1151.1Sjmcneill aprint_naive("\n"); 1161.1Sjmcneill if (wiiu_native) { 1171.1Sjmcneill val = RD4(LT_CHIPREVID); 1181.1Sjmcneill 1191.1Sjmcneill aprint_normal(": Latte 0x%02x\n", 1201.1Sjmcneill (unsigned)(val & (LT_CHIPREVID_VERHI | LT_CHIPREVID_VERLO))); 1211.1Sjmcneill } else { 1221.1Sjmcneill val = RD4(HW_VERSION); 1231.1Sjmcneill 1241.1Sjmcneill aprint_normal(": Hollywood ES%u.%u\n", 1251.1Sjmcneill (unsigned)__SHIFTOUT(val, HWVER_MASK) + 1, 1261.1Sjmcneill (unsigned)__SHIFTOUT(val, HWREV_MASK)); 1271.1Sjmcneill } 1281.1Sjmcneill 1291.1Sjmcneill ahb_intr_init(ahb_maa.maa_irq); 1301.1Sjmcneill 1311.1Sjmcneill config_search(self, NULL, 1321.1Sjmcneill CFARGS(.search = ahb_search)); 1331.1Sjmcneill} 1341.1Sjmcneill 1351.1Sjmcneillstatic int 1361.1Sjmcneillahb_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 1371.1Sjmcneill{ 1381.1Sjmcneill struct ahb_attach_args aaa; 1391.1Sjmcneill 1401.1Sjmcneill aaa.aaa_bst = ahb_maa.maa_bst; 1411.1Sjmcneill aaa.aaa_dmat = ahb_maa.maa_dmat; 1421.1Sjmcneill if (cf->cf_loc[AHBCF_ADDR] != AHBCF_ADDR_DEFAULT) { 1431.1Sjmcneill aaa.aaa_addr = cf->cf_loc[AHBCF_ADDR]; 1441.1Sjmcneill } else { 1451.1Sjmcneill aaa.aaa_addr = 0; 1461.1Sjmcneill } 1471.1Sjmcneill aaa.aaa_irq = cf->cf_loc[AHBCF_IRQ]; 1481.1Sjmcneill 1491.1Sjmcneill if (config_probe(parent, cf, &aaa)) { 1501.1Sjmcneill config_attach(parent, cf, &aaa, ahb_print, CFARGS_NONE); 1511.1Sjmcneill } 1521.1Sjmcneill 1531.1Sjmcneill return 0; 1541.1Sjmcneill} 1551.1Sjmcneill 1561.1Sjmcneillstatic int 1571.1Sjmcneillahb_print(void *aux, const char *pnp) 1581.1Sjmcneill{ 1591.1Sjmcneill struct ahb_attach_args *aaa = aux; 1601.1Sjmcneill 1611.1Sjmcneill if (pnp != NULL) { 1621.1Sjmcneill return QUIET; 1631.1Sjmcneill } 1641.1Sjmcneill 1651.1Sjmcneill if (aaa->aaa_addr != 0) { 1661.1Sjmcneill aprint_normal(" addr 0x%08lx", aaa->aaa_addr); 1671.1Sjmcneill } 1681.1Sjmcneill if (aaa->aaa_irq != AHBCF_IRQ_DEFAULT) { 1691.1Sjmcneill aprint_normal(" irq %d", aaa->aaa_irq); 1701.1Sjmcneill } 1711.1Sjmcneill 1721.1Sjmcneill return UNCONF; 1731.1Sjmcneill} 1741.1Sjmcneill 1751.1Sjmcneillstatic void 1761.1Sjmcneillhollywood_enable_irq(struct pic_ops *pic, int irq, int type) 1771.1Sjmcneill{ 1781.1Sjmcneill pic_irqmask[0] |= __BIT(irq); 1791.1Sjmcneill WR4(HW_PPCIRQMASK, pic_irqmask[0]); 1801.1Sjmcneill} 1811.1Sjmcneill 1821.1Sjmcneillstatic void 1831.1Sjmcneillhollywood_disable_irq(struct pic_ops *pic, int irq) 1841.1Sjmcneill{ 1851.1Sjmcneill pic_irqmask[0] &= ~__BIT(irq); 1861.1Sjmcneill WR4(HW_PPCIRQMASK, pic_irqmask[0]); 1871.1Sjmcneill} 1881.1Sjmcneill 1891.1Sjmcneillstatic int 1901.1Sjmcneillhollywood_get_irq(struct pic_ops *pic, int mode) 1911.1Sjmcneill{ 1921.1Sjmcneill uint32_t raw, pend; 1931.1Sjmcneill int irq; 1941.1Sjmcneill 1951.1Sjmcneill raw = RD4(HW_PPCIRQFLAGS); 1961.1Sjmcneill pend = raw & pic_irqmask[0]; 1971.1Sjmcneill if (pend == 0) { 1981.1Sjmcneill return 255; 1991.1Sjmcneill } 2001.1Sjmcneill irq = ffs32(pend) - 1; 2011.1Sjmcneill 2021.1Sjmcneill return irq; 2031.1Sjmcneill} 2041.1Sjmcneill 2051.1Sjmcneillstatic void 2061.1Sjmcneillhollywood_ack_irq(struct pic_ops *pic, int irq) 2071.1Sjmcneill{ 2081.1Sjmcneill WR4(HW_PPCIRQFLAGS, __BIT(irq)); 2091.1Sjmcneill} 2101.1Sjmcneill 2111.1Sjmcneillstatic void 2121.1Sjmcneillhollywood_establish_irq(struct pic_ops *pic, int irq, int type, int pri) 2131.1Sjmcneill{ 2141.1Sjmcneill uint32_t val; 2151.1Sjmcneill 2161.1Sjmcneill /* Mask and clear Starlet interrupt */ 2171.1Sjmcneill val = RD4(HW_ARMIRQMASK); 2181.1Sjmcneill val &= ~__BIT(irq); 2191.1Sjmcneill WR4(HW_ARMIRQMASK, val); 2201.1Sjmcneill WR4(HW_ARMIRQFLAGS, __BIT(irq)); 2211.1Sjmcneill} 2221.1Sjmcneill 2231.1Sjmcneillstatic void 2241.1Sjmcneilllatte_enable_irq(struct pic_ops *pic, int irq, int type) 2251.1Sjmcneill{ 2261.1Sjmcneill unsigned reg_en = irq < 32 ? LT_PPCnINT1EN(0) : LT_PPCnINT2EN(0); 2271.1Sjmcneill 2281.1Sjmcneill pic_irqmask[irq / 32] |= __BIT(irq % 32); 2291.1Sjmcneill WR4(reg_en, pic_irqmask[irq / 32]); 2301.1Sjmcneill} 2311.1Sjmcneill 2321.1Sjmcneillstatic void 2331.1Sjmcneilllatte_disable_irq(struct pic_ops *pic, int irq) 2341.1Sjmcneill{ 2351.1Sjmcneill unsigned reg_en = irq < 32 ? LT_PPCnINT1EN(0) : LT_PPCnINT2EN(0); 2361.1Sjmcneill 2371.1Sjmcneill pic_irqmask[irq / 32] &= ~__BIT(irq % 32); 2381.1Sjmcneill WR4(reg_en, pic_irqmask[irq / 32]); 2391.1Sjmcneill} 2401.1Sjmcneill 2411.1Sjmcneillstatic int 2421.1Sjmcneilllatte_get_irq(struct pic_ops *pic, int mode) 2431.1Sjmcneill{ 2441.1Sjmcneill uint32_t raw, pend; 2451.1Sjmcneill int irq; 2461.1Sjmcneill 2471.1Sjmcneill raw = RD4(LT_PPCnINT1STS(0)); 2481.1Sjmcneill pend = raw & pic_irqmask[0]; 2491.1Sjmcneill if (pend == 0) { 2501.1Sjmcneill raw = RD4(LT_PPCnINT2STS(0)); 2511.1Sjmcneill pend = raw & pic_irqmask[1]; 2521.1Sjmcneill if (pend == 0) { 2531.1Sjmcneill return 255; 2541.1Sjmcneill } 2551.1Sjmcneill irq = 32 + ffs32(pend) - 1; 2561.1Sjmcneill } else { 2571.1Sjmcneill irq = ffs32(pend) - 1; 2581.1Sjmcneill } 2591.1Sjmcneill 2601.1Sjmcneill return irq; 2611.1Sjmcneill} 2621.1Sjmcneill 2631.1Sjmcneillstatic void 2641.1Sjmcneilllatte_ack_irq(struct pic_ops *pic, int irq) 2651.1Sjmcneill{ 2661.1Sjmcneill unsigned reg_sts = irq < 32 ? LT_PPCnINT1STS(0) : LT_PPCnINT2STS(0); 2671.1Sjmcneill 2681.1Sjmcneill WR4(reg_sts, __BIT(irq % 32)); 2691.1Sjmcneill} 2701.1Sjmcneill 2711.1Sjmcneillstatic void 2721.1Sjmcneilllatte_establish_irq(struct pic_ops *pic, int irq, int type, int pri) 2731.1Sjmcneill{ 2741.1Sjmcneill unsigned reg_en = irq < 32 ? LT_IOPIRQINT1EN : LT_IOPIRQINT2EN; 2751.1Sjmcneill unsigned reg_sts = irq < 32 ? LT_IOPINT1STS : LT_IOPINT2STS; 2761.1Sjmcneill uint32_t val; 2771.1Sjmcneill 2781.1Sjmcneill /* Mask and clear IOP interrupt */ 2791.1Sjmcneill val = RD4(reg_en); 2801.1Sjmcneill val &= ~__BIT(irq % 32); 2811.1Sjmcneill WR4(reg_en, val); 2821.1Sjmcneill WR4(reg_sts, __BIT(irq % 32)); 2831.1Sjmcneill} 2841.1Sjmcneill 2851.1Sjmcneill 2861.1Sjmcneillstatic void 2871.1Sjmcneillahb_intr_init(int irq) 2881.1Sjmcneill{ 2891.1Sjmcneill struct pic_ops *pic_impl; 2901.1Sjmcneill memset(pic_irqmask, 0, sizeof(pic_irqmask)); 2911.1Sjmcneill 2921.1Sjmcneill /* Mask and clear all interrupts. */ 2931.1Sjmcneill if (wiiu_native) { 2941.1Sjmcneill WR4(LT_PPCnINT1EN(0), 0); 2951.1Sjmcneill WR4(LT_PPCnINT2EN(0), 0); 2961.1Sjmcneill WR4(LT_PPCnINT1STS(0), ~0U); 2971.1Sjmcneill WR4(LT_PPCnINT2STS(0), ~0U); 2981.1Sjmcneill 2991.1Sjmcneill pic_impl = &latte_pic; 3001.1Sjmcneill } else { 3011.1Sjmcneill WR4(HW_PPCIRQMASK, 0); 3021.1Sjmcneill WR4(HW_PPCIRQFLAGS, ~0U); 3031.1Sjmcneill 3041.1Sjmcneill pic_impl = &hollywood_pic; 3051.1Sjmcneill } 3061.1Sjmcneill 3071.1Sjmcneill pic_add(pic_impl); 3081.1Sjmcneill intr_establish_xname(irq, IST_LEVEL, IPL_SCHED, pic_handle_intr, 3091.1Sjmcneill pic_impl, pic_impl->pic_name); 3101.1Sjmcneill} 3111.1Sjmcneill 3121.1Sjmcneillvoid * 3131.1Sjmcneillahb_intr_establish(int irq, int ipl, int (*func)(void *), void *arg, 3141.1Sjmcneill const char *name) 3151.1Sjmcneill{ 3161.1Sjmcneill if (wiiu_native) { 3171.1Sjmcneill KASSERT(latte_pic.pic_intrbase != 0); 3181.1Sjmcneill 3191.1Sjmcneill return intr_establish_xname(latte_pic.pic_intrbase + irq, 3201.1Sjmcneill IST_LEVEL, ipl, func, arg, name); 3211.1Sjmcneill } else { 3221.1Sjmcneill KASSERT(hollywood_pic.pic_intrbase != 0); 3231.1Sjmcneill 3241.1Sjmcneill return intr_establish_xname(hollywood_pic.pic_intrbase + irq, 3251.1Sjmcneill IST_LEVEL, ipl, func, arg, name); 3261.1Sjmcneill } 3271.1Sjmcneill} 3281.1Sjmcneill 3291.1Sjmcneillvoid 3301.1Sjmcneillahb_claim_device(device_t dev, uint32_t mask) 3311.1Sjmcneill{ 3321.1Sjmcneill if (!wiiu_native) { 3331.1Sjmcneill /* 3341.1Sjmcneill * Restrict IOP access to a device, giving exclusive access 3351.1Sjmcneill * to PPC. 3361.1Sjmcneill */ 3371.1Sjmcneill WR4(HW_AHBPROT, RD4(HW_AHBPROT) & ~mask); 3381.1Sjmcneill } 3391.1Sjmcneill} 340