1 1.3 jmcneill /* $NetBSD: hollywood.c,v 1.3 2024/09/22 13:56:25 jmcneill Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2024 Jared McNeill <jmcneill (at) invisible.ca> 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 8 1.1 jmcneill * modification, are permitted provided that the following conditions 9 1.1 jmcneill * are met: 10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 11 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 14 1.1 jmcneill * documentation and/or other materials provided with the distribution. 15 1.1 jmcneill * 16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 jmcneill * SUCH DAMAGE. 27 1.1 jmcneill */ 28 1.1 jmcneill 29 1.1 jmcneill #include <sys/cdefs.h> 30 1.3 jmcneill __KERNEL_RCSID(0, "$NetBSD: hollywood.c,v 1.3 2024/09/22 13:56:25 jmcneill Exp $"); 31 1.1 jmcneill 32 1.1 jmcneill #include <sys/param.h> 33 1.1 jmcneill #include <sys/bus.h> 34 1.1 jmcneill #include <sys/device.h> 35 1.1 jmcneill #include <sys/systm.h> 36 1.1 jmcneill #include <sys/bitops.h> 37 1.1 jmcneill 38 1.1 jmcneill #include <machine/intr.h> 39 1.1 jmcneill #include <machine/wii.h> 40 1.1 jmcneill #include <machine/pio.h> 41 1.1 jmcneill #include <powerpc/pic/picvar.h> 42 1.1 jmcneill 43 1.1 jmcneill #include "locators.h" 44 1.1 jmcneill #include "mainbus.h" 45 1.1 jmcneill #include "hollywood.h" 46 1.1 jmcneill 47 1.1 jmcneill #define WR4(reg, val) out32(reg, val) 48 1.1 jmcneill #define RD4(reg) in32(reg) 49 1.1 jmcneill 50 1.1 jmcneill static struct mainbus_attach_args hollywood_maa; 51 1.1 jmcneill static uint32_t pic_irqmask; 52 1.1 jmcneill 53 1.1 jmcneill static int hollywood_match(device_t, cfdata_t, void *); 54 1.1 jmcneill static void hollywood_attach(device_t, device_t, void *); 55 1.1 jmcneill 56 1.1 jmcneill static int hollywood_search(device_t, cfdata_t, const int *, void *); 57 1.1 jmcneill static int hollywood_print(void *, const char *); 58 1.1 jmcneill 59 1.1 jmcneill static void hollywood_intr_init(int); 60 1.1 jmcneill static void hollywood_enable_irq(struct pic_ops *, int, int); 61 1.1 jmcneill static void hollywood_disable_irq(struct pic_ops *, int); 62 1.1 jmcneill static int hollywood_get_irq(struct pic_ops *, int); 63 1.1 jmcneill static void hollywood_ack_irq(struct pic_ops *, int); 64 1.1 jmcneill static void hollywood_establish_irq(struct pic_ops *, int, int, int); 65 1.1 jmcneill 66 1.1 jmcneill static struct pic_ops hollywood_pic = { 67 1.1 jmcneill .pic_name = "hollywood", 68 1.1 jmcneill .pic_numintrs = 32, 69 1.1 jmcneill .pic_cookie = NULL, 70 1.1 jmcneill .pic_enable_irq = hollywood_enable_irq, 71 1.1 jmcneill .pic_reenable_irq = hollywood_enable_irq, 72 1.1 jmcneill .pic_disable_irq = hollywood_disable_irq, 73 1.1 jmcneill .pic_get_irq = hollywood_get_irq, 74 1.1 jmcneill .pic_ack_irq = hollywood_ack_irq, 75 1.1 jmcneill .pic_establish_irq = hollywood_establish_irq, 76 1.1 jmcneill }; 77 1.1 jmcneill 78 1.1 jmcneill CFATTACH_DECL_NEW(hollywood, 0, 79 1.1 jmcneill hollywood_match, hollywood_attach, NULL, NULL); 80 1.1 jmcneill 81 1.1 jmcneill static int 82 1.1 jmcneill hollywood_match(device_t parent, cfdata_t cf, void *aux) 83 1.1 jmcneill { 84 1.1 jmcneill struct mainbus_attach_args *maa = aux; 85 1.1 jmcneill 86 1.1 jmcneill return strcmp(maa->maa_name, "hollywood") == 0; 87 1.1 jmcneill } 88 1.1 jmcneill 89 1.1 jmcneill static void 90 1.1 jmcneill hollywood_attach(device_t parent, device_t self, void *aux) 91 1.1 jmcneill { 92 1.1 jmcneill uint32_t val; 93 1.1 jmcneill 94 1.1 jmcneill hollywood_maa = *(struct mainbus_attach_args *)aux; 95 1.1 jmcneill 96 1.1 jmcneill val = RD4(HW_VERSION); 97 1.1 jmcneill 98 1.1 jmcneill aprint_naive("\n"); 99 1.1 jmcneill aprint_normal(": Hollywood ES%u.%u\n", 100 1.1 jmcneill (unsigned)__SHIFTOUT(val, HWVER_MASK) + 1, 101 1.1 jmcneill (unsigned)__SHIFTOUT(val, HWREV_MASK)); 102 1.1 jmcneill 103 1.1 jmcneill hollywood_intr_init(hollywood_maa.maa_irq); 104 1.1 jmcneill 105 1.1 jmcneill config_search(self, NULL, 106 1.1 jmcneill CFARGS(.search = hollywood_search)); 107 1.1 jmcneill } 108 1.1 jmcneill 109 1.1 jmcneill static int 110 1.1 jmcneill hollywood_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 111 1.1 jmcneill { 112 1.1 jmcneill struct hollywood_attach_args haa; 113 1.1 jmcneill 114 1.1 jmcneill haa.haa_bst = hollywood_maa.maa_bst; 115 1.1 jmcneill haa.haa_dmat = hollywood_maa.maa_dmat; 116 1.1 jmcneill if (cf->cf_loc[HOLLYWOODCF_ADDR] != HOLLYWOODCF_ADDR_DEFAULT) { 117 1.1 jmcneill haa.haa_addr = cf->cf_loc[HOLLYWOODCF_ADDR]; 118 1.1 jmcneill } else { 119 1.1 jmcneill haa.haa_addr = 0; 120 1.1 jmcneill } 121 1.1 jmcneill haa.haa_irq = cf->cf_loc[HOLLYWOODCF_IRQ]; 122 1.1 jmcneill 123 1.1 jmcneill if (config_probe(parent, cf, &haa)) { 124 1.1 jmcneill config_attach(parent, cf, &haa, hollywood_print, 125 1.1 jmcneill CFARGS_NONE); 126 1.1 jmcneill } 127 1.1 jmcneill 128 1.1 jmcneill return 0; 129 1.1 jmcneill } 130 1.1 jmcneill 131 1.1 jmcneill static int 132 1.1 jmcneill hollywood_print(void *aux, const char *pnp) 133 1.1 jmcneill { 134 1.1 jmcneill struct hollywood_attach_args *haa = aux; 135 1.1 jmcneill 136 1.1 jmcneill if (pnp != NULL) { 137 1.1 jmcneill return QUIET; 138 1.1 jmcneill } 139 1.1 jmcneill 140 1.1 jmcneill if (haa->haa_addr != 0) { 141 1.1 jmcneill aprint_normal(" addr 0x%lx", haa->haa_addr); 142 1.1 jmcneill } 143 1.1 jmcneill if (haa->haa_irq != HOLLYWOODCF_IRQ_DEFAULT) { 144 1.1 jmcneill aprint_normal(" irq %d", haa->haa_irq); 145 1.1 jmcneill } 146 1.1 jmcneill 147 1.1 jmcneill return UNCONF; 148 1.1 jmcneill } 149 1.1 jmcneill 150 1.1 jmcneill static void 151 1.1 jmcneill hollywood_enable_irq(struct pic_ops *pic, int irq, int type) 152 1.1 jmcneill { 153 1.1 jmcneill pic_irqmask |= __BIT(irq); 154 1.1 jmcneill WR4(HW_PPCIRQMASK, pic_irqmask); 155 1.1 jmcneill } 156 1.1 jmcneill 157 1.1 jmcneill static void 158 1.1 jmcneill hollywood_disable_irq(struct pic_ops *pic, int irq) 159 1.1 jmcneill { 160 1.1 jmcneill pic_irqmask &= ~__BIT(irq); 161 1.1 jmcneill WR4(HW_PPCIRQMASK, pic_irqmask); 162 1.1 jmcneill } 163 1.1 jmcneill 164 1.1 jmcneill static int 165 1.1 jmcneill hollywood_get_irq(struct pic_ops *pic, int mode) 166 1.1 jmcneill { 167 1.1 jmcneill uint32_t raw, pend; 168 1.1 jmcneill int irq; 169 1.1 jmcneill 170 1.1 jmcneill raw = RD4(HW_PPCIRQFLAGS); 171 1.1 jmcneill pend = raw & pic_irqmask; 172 1.1 jmcneill if (pend == 0) { 173 1.1 jmcneill return 255; 174 1.1 jmcneill } 175 1.1 jmcneill irq = ffs32(pend) - 1; 176 1.1 jmcneill 177 1.1 jmcneill return irq; 178 1.1 jmcneill } 179 1.1 jmcneill 180 1.1 jmcneill static void 181 1.1 jmcneill hollywood_ack_irq(struct pic_ops *pic, int irq) 182 1.1 jmcneill { 183 1.1 jmcneill WR4(HW_PPCIRQFLAGS, __BIT(irq)); 184 1.1 jmcneill } 185 1.1 jmcneill 186 1.1 jmcneill static void 187 1.1 jmcneill hollywood_establish_irq(struct pic_ops *pic, int irq, int type, int pri) 188 1.1 jmcneill { 189 1.1 jmcneill uint32_t val; 190 1.1 jmcneill 191 1.1 jmcneill /* Mask and clear Starlet interrupt */ 192 1.1 jmcneill val = RD4(HW_ARMIRQMASK); 193 1.1 jmcneill val &= ~__BIT(irq); 194 1.1 jmcneill WR4(HW_ARMIRQMASK, val); 195 1.1 jmcneill WR4(HW_ARMIRQFLAGS, __BIT(irq)); 196 1.1 jmcneill } 197 1.1 jmcneill 198 1.1 jmcneill static void 199 1.1 jmcneill hollywood_intr_init(int irq) 200 1.1 jmcneill { 201 1.1 jmcneill pic_irqmask = 0; 202 1.1 jmcneill 203 1.1 jmcneill /* Mask and clear all interrupts. */ 204 1.1 jmcneill WR4(HW_PPCIRQMASK, 0); 205 1.1 jmcneill WR4(HW_PPCIRQFLAGS, ~0U); 206 1.1 jmcneill 207 1.1 jmcneill pic_add(&hollywood_pic); 208 1.1 jmcneill 209 1.2 jmcneill intr_establish_xname(irq, IST_LEVEL, IPL_SCHED, pic_handle_intr, 210 1.2 jmcneill &hollywood_pic, "hollywood0"); 211 1.1 jmcneill } 212 1.1 jmcneill 213 1.1 jmcneill void * 214 1.2 jmcneill hollywood_intr_establish(int irq, int ipl, int (*func)(void *), void *arg, 215 1.2 jmcneill const char *name) 216 1.1 jmcneill { 217 1.1 jmcneill KASSERT(hollywood_pic.pic_intrbase != 0); 218 1.1 jmcneill 219 1.2 jmcneill return intr_establish_xname(hollywood_pic.pic_intrbase + irq, 220 1.2 jmcneill IST_LEVEL, ipl, func, arg, name); 221 1.1 jmcneill } 222 1.3 jmcneill 223 1.3 jmcneill void 224 1.3 jmcneill hollywood_claim_device(device_t dev, uint32_t mask) 225 1.3 jmcneill { 226 1.3 jmcneill /* Restrict IOP access to a device, giving exclusive access to PPC. */ 227 1.3 jmcneill WR4(HW_AHBPROT, RD4(HW_AHBPROT) & ~mask); 228 1.3 jmcneill } 229