1 1.28 riastrad /* $NetBSD: mediabay.c,v 1.28 2022/02/16 23:49:26 riastradh Exp $ */ 2 1.1 tsubai 3 1.1 tsubai /*- 4 1.1 tsubai * Copyright (C) 1999 Tsubai Masanari. All rights reserved. 5 1.1 tsubai * 6 1.1 tsubai * Redistribution and use in source and binary forms, with or without 7 1.1 tsubai * modification, are permitted provided that the following conditions 8 1.1 tsubai * are met: 9 1.1 tsubai * 1. Redistributions of source code must retain the above copyright 10 1.1 tsubai * notice, this list of conditions and the following disclaimer. 11 1.1 tsubai * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 tsubai * notice, this list of conditions and the following disclaimer in the 13 1.1 tsubai * documentation and/or other materials provided with the distribution. 14 1.1 tsubai * 3. The name of the author may not be used to endorse or promote products 15 1.1 tsubai * derived from this software without specific prior written permission. 16 1.1 tsubai * 17 1.1 tsubai * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 1.1 tsubai * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 1.1 tsubai * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 1.1 tsubai * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 1.1 tsubai * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 1.1 tsubai * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 1.1 tsubai * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 1.1 tsubai * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 1.1 tsubai * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 1.1 tsubai * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 1.1 tsubai */ 28 1.9 lukem 29 1.9 lukem #include <sys/cdefs.h> 30 1.28 riastrad __KERNEL_RCSID(0, "$NetBSD: mediabay.c,v 1.28 2022/02/16 23:49:26 riastradh Exp $"); 31 1.1 tsubai 32 1.1 tsubai #include <sys/param.h> 33 1.2 tsubai #include <sys/device.h> 34 1.2 tsubai #include <sys/kernel.h> 35 1.2 tsubai #include <sys/kthread.h> 36 1.1 tsubai #include <sys/systm.h> 37 1.2 tsubai 38 1.2 tsubai #include <dev/ofw/openfirm.h> 39 1.1 tsubai 40 1.1 tsubai #include <machine/autoconf.h> 41 1.1 tsubai #include <machine/pio.h> 42 1.1 tsubai 43 1.15 jmcneill enum mediabay_controller { 44 1.15 jmcneill MB_CONTROLLER_KEYLARGO, 45 1.15 jmcneill MB_CONTROLLER_OTHER 46 1.15 jmcneill }; 47 1.15 jmcneill 48 1.1 tsubai struct mediabay_softc { 49 1.22 macallan device_t sc_dev; 50 1.14 garbled bus_space_tag_t sc_tag; 51 1.1 tsubai int sc_node; 52 1.1 tsubai u_int *sc_addr; 53 1.1 tsubai u_int *sc_fcr; 54 1.2 tsubai u_int sc_baseaddr; 55 1.20 matt device_t sc_content; 56 1.13 ad lwp_t *sc_kthread; 57 1.15 jmcneill enum mediabay_controller sc_type; 58 1.15 jmcneill }; 59 1.15 jmcneill 60 1.15 jmcneill static const char *mediabay_keylargo[] = { 61 1.15 jmcneill "keylargo-media-bay", 62 1.15 jmcneill NULL 63 1.1 tsubai }; 64 1.1 tsubai 65 1.20 matt void mediabay_attach(device_t, device_t, void *); 66 1.20 matt int mediabay_match(device_t, cfdata_t, void *); 67 1.16 dsl int mediabay_print(void *, const char *); 68 1.16 dsl void mediabay_attach_content(struct mediabay_softc *); 69 1.16 dsl int mediabay_intr(void *); 70 1.16 dsl void mediabay_kthread(void *); 71 1.1 tsubai 72 1.22 macallan CFATTACH_DECL_NEW(mediabay, sizeof(struct mediabay_softc), 73 1.6 thorpej mediabay_match, mediabay_attach, NULL, NULL); 74 1.1 tsubai 75 1.2 tsubai #ifdef MEDIABAY_DEBUG 76 1.2 tsubai # define DPRINTF printf 77 1.2 tsubai #else 78 1.2 tsubai # define DPRINTF while (0) printf 79 1.2 tsubai #endif 80 1.1 tsubai 81 1.1 tsubai #define FCR_MEDIABAY_RESET 0x00000002 82 1.1 tsubai #define FCR_MEDIABAY_IDE_ENABLE 0x00000008 83 1.1 tsubai #define FCR_MEDIABAY_FD_ENABLE 0x00000010 84 1.1 tsubai #define FCR_MEDIABAY_ENABLE 0x00000080 85 1.1 tsubai #define FCR_MEDIABAY_CD_POWER 0x00800000 86 1.1 tsubai 87 1.15 jmcneill #define MBCR_MEDIABAY0_ENABLE 0x00000100 88 1.15 jmcneill #define MBCR_MEDIABAY0_RESET 0x00000200 89 1.15 jmcneill #define MBCR_MEDIABAY0_POWER 0x00000400 90 1.15 jmcneill #define MBCR_MEDIABAY0_IDE_ENABLE 0x00001000 91 1.15 jmcneill #define MBCR_MEDIABAY0_DEVMASK 0x00007800 92 1.15 jmcneill 93 1.15 jmcneill #define FCR1_EIDE0_ENABLE 0x00800000 94 1.15 jmcneill #define FCR1_EIDE0_RESET 0x01000000 95 1.15 jmcneill 96 1.15 jmcneill #define MEDIABAY_ID(sc, x) \ 97 1.15 jmcneill ((sc)->sc_type == MB_CONTROLLER_KEYLARGO ? \ 98 1.15 jmcneill (((x) >> 4) & 0xf) : \ 99 1.15 jmcneill (((x) >> 12) & 0xf)) 100 1.1 tsubai #define MEDIABAY_ID_FD 0 101 1.1 tsubai #define MEDIABAY_ID_CD 3 102 1.1 tsubai #define MEDIABAY_ID_NONE 7 103 1.1 tsubai 104 1.1 tsubai int 105 1.20 matt mediabay_match(device_t parent, cfdata_t cf, void *aux) 106 1.1 tsubai { 107 1.1 tsubai struct confargs *ca = aux; 108 1.1 tsubai 109 1.1 tsubai if (strcmp(ca->ca_name, "media-bay") == 0) 110 1.1 tsubai return 1; 111 1.1 tsubai 112 1.1 tsubai return 0; 113 1.1 tsubai } 114 1.1 tsubai 115 1.1 tsubai /* 116 1.1 tsubai * Attach all the sub-devices we can find 117 1.1 tsubai */ 118 1.1 tsubai void 119 1.20 matt mediabay_attach(device_t parent, device_t self, void *aux) 120 1.1 tsubai { 121 1.20 matt struct mediabay_softc *sc = device_private(self); 122 1.2 tsubai struct confargs *ca = aux; 123 1.10 briggs int irq, itype; 124 1.2 tsubai 125 1.22 macallan sc->sc_dev = self; 126 1.2 tsubai ca->ca_reg[0] += ca->ca_baseaddr; 127 1.1 tsubai 128 1.21 matt sc->sc_addr = mapiodev(ca->ca_reg[0], PAGE_SIZE, false); 129 1.2 tsubai sc->sc_node = ca->ca_node; 130 1.2 tsubai sc->sc_baseaddr = ca->ca_baseaddr; 131 1.14 garbled sc->sc_tag = ca->ca_tag; 132 1.2 tsubai irq = ca->ca_intr[0]; 133 1.14 garbled itype = IST_EDGE; 134 1.1 tsubai 135 1.23 thorpej if (of_compatible(ca->ca_node, mediabay_keylargo)) { 136 1.15 jmcneill sc->sc_type = MB_CONTROLLER_KEYLARGO; 137 1.15 jmcneill sc->sc_fcr = sc->sc_addr + 2; 138 1.15 jmcneill } else { 139 1.15 jmcneill sc->sc_type = MB_CONTROLLER_OTHER; 140 1.15 jmcneill sc->sc_fcr = sc->sc_addr + 1; 141 1.15 jmcneill } 142 1.15 jmcneill 143 1.14 garbled if (ca->ca_nintr == 8 && ca->ca_intr[1] != 0) 144 1.14 garbled itype = IST_LEVEL; 145 1.3 tsubai 146 1.10 briggs printf(" irq %d %s\n", irq, intr_typename(itype)); 147 1.10 briggs 148 1.24 rin intr_establish_xname(irq, itype, IPL_BIO, mediabay_intr, sc, 149 1.24 rin device_xname(self)); 150 1.1 tsubai 151 1.2 tsubai sc->sc_content = NULL; 152 1.2 tsubai 153 1.15 jmcneill if (MEDIABAY_ID(sc, in32rb(sc->sc_addr)) != MEDIABAY_ID_NONE) 154 1.2 tsubai mediabay_attach_content(sc); 155 1.13 ad 156 1.13 ad kthread_create(PRI_NONE, 0, NULL, mediabay_kthread, sc, 157 1.13 ad &sc->sc_kthread, "media-bay"); 158 1.2 tsubai } 159 1.2 tsubai 160 1.2 tsubai void 161 1.17 dsl mediabay_attach_content(struct mediabay_softc *sc) 162 1.2 tsubai { 163 1.2 tsubai int child; 164 1.15 jmcneill u_int fcr = 0; 165 1.20 matt device_t content; 166 1.2 tsubai struct confargs ca; 167 1.2 tsubai u_int reg[20], intr[5]; 168 1.2 tsubai char name[32]; 169 1.2 tsubai 170 1.15 jmcneill if (sc->sc_type != MB_CONTROLLER_KEYLARGO) { 171 1.15 jmcneill fcr = in32rb(sc->sc_fcr); 172 1.15 jmcneill 173 1.15 jmcneill /* 174 1.15 jmcneill * if the mediabay isn't powered up we need to wait a few seconds 175 1.15 jmcneill * before probing devices 176 1.15 jmcneill */ 177 1.15 jmcneill if ((fcr & (FCR_MEDIABAY_ENABLE | FCR_MEDIABAY_IDE_ENABLE 178 1.15 jmcneill | FCR_MEDIABAY_CD_POWER)) != (FCR_MEDIABAY_ENABLE 179 1.15 jmcneill | FCR_MEDIABAY_IDE_ENABLE | FCR_MEDIABAY_CD_POWER)) { 180 1.15 jmcneill fcr |= FCR_MEDIABAY_ENABLE | FCR_MEDIABAY_RESET; 181 1.15 jmcneill out32rb(sc->sc_fcr, fcr); 182 1.15 jmcneill delay(50000); 183 1.15 jmcneill 184 1.15 jmcneill fcr &= ~FCR_MEDIABAY_RESET; 185 1.15 jmcneill out32rb(sc->sc_fcr, fcr); 186 1.15 jmcneill delay(50000); 187 1.15 jmcneill 188 1.15 jmcneill fcr |= FCR_MEDIABAY_IDE_ENABLE | FCR_MEDIABAY_CD_POWER; 189 1.15 jmcneill out32rb(sc->sc_fcr, fcr); 190 1.15 jmcneill delay(50000); 191 1.22 macallan printf("%s: powering up...\n", device_xname(sc->sc_dev)); 192 1.15 jmcneill delay(2000000); 193 1.15 jmcneill } 194 1.15 jmcneill } else { 195 1.22 macallan printf("%s: powering up keylargo-media-bay..", device_xname(sc->sc_dev)); 196 1.15 jmcneill 197 1.15 jmcneill out32rb(sc->sc_addr, in32rb(sc->sc_addr) & ~MBCR_MEDIABAY0_RESET); 198 1.15 jmcneill out32rb(sc->sc_addr, in32rb(sc->sc_addr) & ~MBCR_MEDIABAY0_POWER); 199 1.15 jmcneill delay(50000); 200 1.15 jmcneill 201 1.15 jmcneill out32rb(sc->sc_addr, in32rb(sc->sc_addr) & ~MBCR_MEDIABAY0_ENABLE); 202 1.15 jmcneill delay(50000); 203 1.1 tsubai 204 1.15 jmcneill out32rb(sc->sc_addr, 205 1.15 jmcneill in32rb(sc->sc_addr) | MBCR_MEDIABAY0_IDE_ENABLE); 206 1.15 jmcneill delay(50000); 207 1.15 jmcneill 208 1.15 jmcneill out32rb(sc->sc_addr, in32rb(sc->sc_addr) | MBCR_MEDIABAY0_RESET); 209 1.15 jmcneill delay(50000); 210 1.15 jmcneill 211 1.15 jmcneill out32rb(sc->sc_fcr, in32rb(sc->sc_fcr) | FCR1_EIDE0_RESET); 212 1.15 jmcneill out32rb(sc->sc_fcr, in32rb(sc->sc_fcr) | FCR1_EIDE0_ENABLE); 213 1.12 macallan delay(50000); 214 1.12 macallan 215 1.15 jmcneill out32rb(sc->sc_addr, in32rb(sc->sc_addr) | MBCR_MEDIABAY0_ENABLE); 216 1.28 riastrad __asm volatile("eieio" ::: "memory"); 217 1.12 macallan delay(50000); 218 1.12 macallan 219 1.15 jmcneill out32rb(sc->sc_addr, in32rb(sc->sc_addr) & ~0xf); 220 1.28 riastrad __asm volatile("eieio" ::: "memory"); 221 1.12 macallan delay(50000); 222 1.15 jmcneill 223 1.15 jmcneill tsleep(sc, PRI_NONE, "mediabay", hz*1); 224 1.15 jmcneill 225 1.15 jmcneill printf(" done.\n"); 226 1.12 macallan } 227 1.1 tsubai 228 1.27 thorpej devhandle_t selfh = device_handle(sc->sc_dev); 229 1.1 tsubai for (child = OF_child(sc->sc_node); child; child = OF_peer(child)) { 230 1.4 wiz memset(name, 0, sizeof(name)); 231 1.1 tsubai if (OF_getprop(child, "name", name, sizeof(name)) == -1) 232 1.1 tsubai continue; 233 1.1 tsubai ca.ca_name = name; 234 1.1 tsubai ca.ca_node = child; 235 1.2 tsubai ca.ca_baseaddr = sc->sc_baseaddr; 236 1.14 garbled ca.ca_tag = sc->sc_tag; 237 1.1 tsubai 238 1.1 tsubai ca.ca_nreg = OF_getprop(child, "reg", reg, sizeof(reg)); 239 1.1 tsubai ca.ca_nintr = OF_getprop(child, "AAPL,interrupts", intr, 240 1.1 tsubai sizeof(intr)); 241 1.1 tsubai if (ca.ca_nintr == -1) 242 1.1 tsubai ca.ca_nintr = OF_getprop(child, "interrupts", intr, 243 1.1 tsubai sizeof(intr)); 244 1.1 tsubai ca.ca_reg = reg; 245 1.1 tsubai ca.ca_intr = intr; 246 1.1 tsubai 247 1.25 thorpej content = config_found(sc->sc_dev, &ca, mediabay_print, 248 1.27 thorpej CFARGS(.devhandle = devhandle_from_of(selfh, child))); 249 1.2 tsubai if (content) { 250 1.2 tsubai sc->sc_content = content; 251 1.2 tsubai return; 252 1.2 tsubai } 253 1.1 tsubai } 254 1.2 tsubai 255 1.15 jmcneill if (sc->sc_type != MB_CONTROLLER_KEYLARGO) { 256 1.15 jmcneill /* No devices found. Disable media-bay. */ 257 1.15 jmcneill fcr &= ~(FCR_MEDIABAY_ENABLE | FCR_MEDIABAY_IDE_ENABLE | 258 1.15 jmcneill FCR_MEDIABAY_CD_POWER | FCR_MEDIABAY_FD_ENABLE); 259 1.15 jmcneill out32rb(sc->sc_fcr, fcr); 260 1.15 jmcneill } 261 1.1 tsubai } 262 1.1 tsubai 263 1.1 tsubai int 264 1.17 dsl mediabay_print(void *aux, const char *mediabay) 265 1.1 tsubai { 266 1.1 tsubai struct confargs *ca = aux; 267 1.1 tsubai 268 1.2 tsubai if (mediabay == NULL && ca->ca_nreg > 0) 269 1.7 thorpej aprint_normal(" offset 0x%x", ca->ca_reg[0]); 270 1.1 tsubai 271 1.2 tsubai return QUIET; 272 1.1 tsubai } 273 1.1 tsubai 274 1.1 tsubai int 275 1.17 dsl mediabay_intr(void *v) 276 1.1 tsubai { 277 1.1 tsubai struct mediabay_softc *sc = v; 278 1.1 tsubai 279 1.2 tsubai wakeup(&sc->sc_kthread); 280 1.10 briggs 281 1.2 tsubai return 1; 282 1.2 tsubai } 283 1.2 tsubai 284 1.2 tsubai void 285 1.17 dsl mediabay_kthread(void *v) 286 1.2 tsubai { 287 1.2 tsubai struct mediabay_softc *sc = v; 288 1.2 tsubai u_int x, fcr; 289 1.2 tsubai 290 1.10 briggs for (;;) { 291 1.10 briggs tsleep(&sc->sc_kthread, PRIBIO, "mbayev", 0); 292 1.2 tsubai 293 1.10 briggs /* sleep 0.25 sec */ 294 1.10 briggs tsleep(mediabay_kthread, PRIBIO, "mbayev", hz/4); 295 1.2 tsubai 296 1.22 macallan DPRINTF("%s: ", device_xname(sc->sc_dev)); 297 1.10 briggs x = in32rb(sc->sc_addr); 298 1.1 tsubai 299 1.15 jmcneill switch (MEDIABAY_ID(sc, x)) { 300 1.10 briggs case MEDIABAY_ID_NONE: 301 1.10 briggs DPRINTF("removed\n"); 302 1.10 briggs if (sc->sc_content != NULL) { 303 1.10 briggs config_detach(sc->sc_content, DETACH_FORCE); 304 1.10 briggs DPRINTF("%s: detach done\n", 305 1.22 macallan device_xname(sc->sc_dev)); 306 1.10 briggs sc->sc_content = NULL; 307 1.10 briggs 308 1.15 jmcneill if (sc->sc_type != MB_CONTROLLER_KEYLARGO) { 309 1.15 jmcneill /* disable media-bay */ 310 1.15 jmcneill fcr = in32rb(sc->sc_fcr); 311 1.15 jmcneill fcr &= ~(FCR_MEDIABAY_ENABLE | 312 1.15 jmcneill FCR_MEDIABAY_IDE_ENABLE | 313 1.15 jmcneill FCR_MEDIABAY_CD_POWER | 314 1.15 jmcneill FCR_MEDIABAY_FD_ENABLE); 315 1.15 jmcneill out32rb(sc->sc_fcr, fcr); 316 1.15 jmcneill } 317 1.10 briggs } 318 1.10 briggs break; 319 1.10 briggs case MEDIABAY_ID_FD: 320 1.10 briggs DPRINTF("FD inserted\n"); 321 1.10 briggs break; 322 1.10 briggs case MEDIABAY_ID_CD: 323 1.10 briggs DPRINTF("CD inserted\n"); 324 1.10 briggs 325 1.10 briggs if (sc->sc_content == NULL) 326 1.10 briggs mediabay_attach_content(sc); 327 1.10 briggs break; 328 1.10 briggs default: 329 1.10 briggs printf("unknown event (0x%x)\n", x); 330 1.2 tsubai } 331 1.1 tsubai } 332 1.1 tsubai } 333 1.1 tsubai 334 1.1 tsubai /* PBG3: 0x7025X0c0 */ 335 1.10 briggs /* 3400: 0x7070X080 */ 336 1.1 tsubai /* 2400: 0x0070X0a8 */ 337