1*47d381f7Sjsg /* $OpenBSD: mediabay.c,v 1.9 2022/10/15 08:41:18 jsg Exp $ */
23ce2f8e0Sdrahn /* $NetBSD: mediabay.c,v 1.9 2003/07/15 02:43:29 lukem Exp $ */
33ce2f8e0Sdrahn
43ce2f8e0Sdrahn /*-
53ce2f8e0Sdrahn * Copyright (C) 1999 Tsubai Masanari. All rights reserved.
63ce2f8e0Sdrahn *
73ce2f8e0Sdrahn * Redistribution and use in source and binary forms, with or without
83ce2f8e0Sdrahn * modification, are permitted provided that the following conditions
93ce2f8e0Sdrahn * are met:
103ce2f8e0Sdrahn * 1. Redistributions of source code must retain the above copyright
113ce2f8e0Sdrahn * notice, this list of conditions and the following disclaimer.
123ce2f8e0Sdrahn * 2. Redistributions in binary form must reproduce the above copyright
133ce2f8e0Sdrahn * notice, this list of conditions and the following disclaimer in the
143ce2f8e0Sdrahn * documentation and/or other materials provided with the distribution.
153ce2f8e0Sdrahn * 3. The name of the author may not be used to endorse or promote products
163ce2f8e0Sdrahn * derived from this software without specific prior written permission.
173ce2f8e0Sdrahn *
183ce2f8e0Sdrahn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
193ce2f8e0Sdrahn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
203ce2f8e0Sdrahn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
213ce2f8e0Sdrahn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
223ce2f8e0Sdrahn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
233ce2f8e0Sdrahn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
243ce2f8e0Sdrahn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
253ce2f8e0Sdrahn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
263ce2f8e0Sdrahn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
273ce2f8e0Sdrahn * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
283ce2f8e0Sdrahn */
293ce2f8e0Sdrahn
303ce2f8e0Sdrahn #include <sys/param.h>
313ce2f8e0Sdrahn #include <sys/device.h>
323ce2f8e0Sdrahn #include <sys/kernel.h>
333ce2f8e0Sdrahn #include <sys/kthread.h>
343ce2f8e0Sdrahn #include <sys/systm.h>
353ce2f8e0Sdrahn
363ce2f8e0Sdrahn #include <uvm/uvm_extern.h>
373ce2f8e0Sdrahn
383ce2f8e0Sdrahn #include <dev/ofw/openfirm.h>
393ce2f8e0Sdrahn
403ce2f8e0Sdrahn #include <machine/autoconf.h>
413ce2f8e0Sdrahn #include <machine/pio.h>
423ce2f8e0Sdrahn
433ce2f8e0Sdrahn struct mediabay_softc {
443ce2f8e0Sdrahn struct device sc_dev;
453ce2f8e0Sdrahn int sc_node;
463ce2f8e0Sdrahn u_int *sc_addr;
473ce2f8e0Sdrahn u_int *sc_fcr;
483ce2f8e0Sdrahn u_int sc_baseaddr;
493ce2f8e0Sdrahn bus_space_tag_t sc_iot;
503ce2f8e0Sdrahn bus_dma_tag_t sc_dmat;
513ce2f8e0Sdrahn struct device *sc_content;
523ce2f8e0Sdrahn struct proc *sc_kthread;
533ce2f8e0Sdrahn };
543ce2f8e0Sdrahn
55e2b96ebfSderaadt void mediabay_attach(struct device *, struct device *, void *);
56e2b96ebfSderaadt int mediabay_match(struct device *, void *, void *);
57e2b96ebfSderaadt int mediabay_print(void *, const char *);
58e2b96ebfSderaadt void mediabay_attach_content(struct mediabay_softc *);
59e2b96ebfSderaadt int mediabay_intr(void *);
60e2b96ebfSderaadt void mediabay_create_kthread(void *);
61e2b96ebfSderaadt void mediabay_kthread(void *);
623ce2f8e0Sdrahn
6389ed722cSmpi const struct cfattach mediabay_ca = {
643ce2f8e0Sdrahn sizeof(struct mediabay_softc), mediabay_match, mediabay_attach
653ce2f8e0Sdrahn };
663ce2f8e0Sdrahn struct cfdriver mediabay_cd = {
673ce2f8e0Sdrahn NULL, "mediabay", DV_DULL
683ce2f8e0Sdrahn };
693ce2f8e0Sdrahn
703ce2f8e0Sdrahn
713ce2f8e0Sdrahn #ifdef MEDIABAY_DEBUG
723ce2f8e0Sdrahn # define DPRINTF printf
733ce2f8e0Sdrahn #else
743ce2f8e0Sdrahn # define DPRINTF while (0) printf
753ce2f8e0Sdrahn #endif
763ce2f8e0Sdrahn
773ce2f8e0Sdrahn #define FCR_MEDIABAY_RESET 0x00000002
783ce2f8e0Sdrahn #define FCR_MEDIABAY_IDE_ENABLE 0x00000008
793ce2f8e0Sdrahn #define FCR_MEDIABAY_FD_ENABLE 0x00000010
803ce2f8e0Sdrahn #define FCR_MEDIABAY_ENABLE 0x00000080
813ce2f8e0Sdrahn #define FCR_MEDIABAY_CD_POWER 0x00800000
823ce2f8e0Sdrahn
833ce2f8e0Sdrahn #define MEDIABAY_ID(x) (((x) >> 12) & 0xf)
843ce2f8e0Sdrahn #define MEDIABAY_ID_FD 0
853ce2f8e0Sdrahn #define MEDIABAY_ID_CD 3
863ce2f8e0Sdrahn #define MEDIABAY_ID_NONE 7
873ce2f8e0Sdrahn
883ce2f8e0Sdrahn int
mediabay_match(struct device * parent,void * v,void * aux)89*47d381f7Sjsg mediabay_match(struct device *parent, void *v, void *aux)
903ce2f8e0Sdrahn {
913ce2f8e0Sdrahn struct confargs *ca = aux;
923ce2f8e0Sdrahn
9384b94647Smiod if (strcmp(ca->ca_name, "media-bay") == 0 &&
9484b94647Smiod ca->ca_nintr >= 4 && ca->ca_nreg >= 8)
953ce2f8e0Sdrahn return 1;
963ce2f8e0Sdrahn
973ce2f8e0Sdrahn return 0;
983ce2f8e0Sdrahn }
993ce2f8e0Sdrahn
1003ce2f8e0Sdrahn /*
1013ce2f8e0Sdrahn * Attach all the sub-devices we can find
1023ce2f8e0Sdrahn */
1033ce2f8e0Sdrahn void
mediabay_attach(struct device * parent,struct device * self,void * aux)104*47d381f7Sjsg mediabay_attach(struct device *parent, struct device *self, void *aux)
1053ce2f8e0Sdrahn {
1063ce2f8e0Sdrahn struct mediabay_softc *sc = (struct mediabay_softc *)self;
1073ce2f8e0Sdrahn struct confargs *ca = aux;
1083ce2f8e0Sdrahn int irq, type;
1093ce2f8e0Sdrahn
1103ce2f8e0Sdrahn ca->ca_reg[0] += ca->ca_baseaddr;
1113ce2f8e0Sdrahn
1123ce2f8e0Sdrahn sc->sc_addr = mapiodev(ca->ca_reg[0], PAGE_SIZE);
1133ce2f8e0Sdrahn sc->sc_fcr = sc->sc_addr + 1;
1143ce2f8e0Sdrahn sc->sc_node = ca->ca_node;
1153ce2f8e0Sdrahn sc->sc_baseaddr = ca->ca_baseaddr;
1163ce2f8e0Sdrahn sc->sc_iot = ca->ca_iot;
1173ce2f8e0Sdrahn sc->sc_dmat = ca->ca_dmat;
1183ce2f8e0Sdrahn irq = ca->ca_intr[0];
1193ce2f8e0Sdrahn type = IST_LEVEL;
1203ce2f8e0Sdrahn
1213ce2f8e0Sdrahn if (ca->ca_nintr == 8 && ca->ca_intr[1] == 0)
1223ce2f8e0Sdrahn type = IST_EDGE;
1233ce2f8e0Sdrahn
1243ce2f8e0Sdrahn printf(" irq %d\n", irq);
1253ce2f8e0Sdrahn mac_intr_establish(parent, irq, type, IPL_BIO, mediabay_intr, sc,
1263ce2f8e0Sdrahn "mediabay");
1273ce2f8e0Sdrahn
1283ce2f8e0Sdrahn kthread_create_deferred(mediabay_create_kthread, sc);
1293ce2f8e0Sdrahn
1303ce2f8e0Sdrahn sc->sc_content = NULL;
1313ce2f8e0Sdrahn
1323ce2f8e0Sdrahn if (MEDIABAY_ID(in32rb(sc->sc_addr)) != MEDIABAY_ID_NONE)
1333ce2f8e0Sdrahn mediabay_attach_content(sc);
1343ce2f8e0Sdrahn }
1353ce2f8e0Sdrahn
1363ce2f8e0Sdrahn void
mediabay_attach_content(struct mediabay_softc * sc)137*47d381f7Sjsg mediabay_attach_content(struct mediabay_softc *sc)
1383ce2f8e0Sdrahn {
1393ce2f8e0Sdrahn int child;
1403ce2f8e0Sdrahn u_int fcr;
1413ce2f8e0Sdrahn struct device *content;
1423ce2f8e0Sdrahn struct confargs ca;
1433ce2f8e0Sdrahn u_int reg[20], intr[5];
1443ce2f8e0Sdrahn char name[32];
1453ce2f8e0Sdrahn
1463ce2f8e0Sdrahn fcr = in32rb(sc->sc_fcr);
1473ce2f8e0Sdrahn fcr |= FCR_MEDIABAY_ENABLE | FCR_MEDIABAY_RESET;
1483ce2f8e0Sdrahn out32rb(sc->sc_fcr, fcr);
1493ce2f8e0Sdrahn delay(50000);
1503ce2f8e0Sdrahn
1513ce2f8e0Sdrahn fcr &= ~FCR_MEDIABAY_RESET;
1523ce2f8e0Sdrahn out32rb(sc->sc_fcr, fcr);
1533ce2f8e0Sdrahn delay(50000);
1543ce2f8e0Sdrahn
1553ce2f8e0Sdrahn fcr |= FCR_MEDIABAY_IDE_ENABLE | FCR_MEDIABAY_CD_POWER;
1563ce2f8e0Sdrahn out32rb(sc->sc_fcr, fcr);
1573ce2f8e0Sdrahn delay(50000);
1583ce2f8e0Sdrahn
1593ce2f8e0Sdrahn for (child = OF_child(sc->sc_node); child; child = OF_peer(child)) {
160d7949865Sjasper bzero(name, sizeof(name));
1613ce2f8e0Sdrahn if (OF_getprop(child, "name", name, sizeof(name)) == -1)
1623ce2f8e0Sdrahn continue;
1633ce2f8e0Sdrahn ca.ca_name = name;
1643ce2f8e0Sdrahn ca.ca_node = child;
1653ce2f8e0Sdrahn ca.ca_baseaddr = sc->sc_baseaddr;
1663ce2f8e0Sdrahn ca.ca_iot = sc->sc_iot;
1673ce2f8e0Sdrahn ca.ca_dmat = sc->sc_dmat;
1683ce2f8e0Sdrahn
1693ce2f8e0Sdrahn ca.ca_nreg = OF_getprop(child, "reg", reg, sizeof(reg));
1703ce2f8e0Sdrahn ca.ca_nintr = OF_getprop(child, "AAPL,interrupts", intr,
1713ce2f8e0Sdrahn sizeof(intr));
1723ce2f8e0Sdrahn if (ca.ca_nintr == -1)
1733ce2f8e0Sdrahn ca.ca_nintr = OF_getprop(child, "interrupts", intr,
1743ce2f8e0Sdrahn sizeof(intr));
1753ce2f8e0Sdrahn ca.ca_reg = reg;
1763ce2f8e0Sdrahn ca.ca_intr = intr;
1773ce2f8e0Sdrahn
1783ce2f8e0Sdrahn content = config_found(&sc->sc_dev, &ca, mediabay_print);
1793ce2f8e0Sdrahn if (content) {
1803ce2f8e0Sdrahn sc->sc_content = content;
1813ce2f8e0Sdrahn return;
1823ce2f8e0Sdrahn }
1833ce2f8e0Sdrahn }
1843ce2f8e0Sdrahn
1853ce2f8e0Sdrahn /* No devices found. Disable media-bay. */
1863ce2f8e0Sdrahn fcr &= ~(FCR_MEDIABAY_ENABLE | FCR_MEDIABAY_IDE_ENABLE |
1873ce2f8e0Sdrahn FCR_MEDIABAY_CD_POWER | FCR_MEDIABAY_FD_ENABLE);
1883ce2f8e0Sdrahn out32rb(sc->sc_fcr, fcr);
1893ce2f8e0Sdrahn }
1903ce2f8e0Sdrahn
1913ce2f8e0Sdrahn int
mediabay_print(void * aux,const char * mediabay)192*47d381f7Sjsg mediabay_print(void *aux, const char *mediabay)
1933ce2f8e0Sdrahn {
1943ce2f8e0Sdrahn struct confargs *ca = aux;
1953ce2f8e0Sdrahn
1963ce2f8e0Sdrahn if (mediabay == NULL && ca->ca_nreg > 0)
1973ce2f8e0Sdrahn printf(" offset 0x%x", ca->ca_reg[0]);
1983ce2f8e0Sdrahn
1993ce2f8e0Sdrahn return QUIET;
2003ce2f8e0Sdrahn }
2013ce2f8e0Sdrahn
2023ce2f8e0Sdrahn int
mediabay_intr(void * v)203*47d381f7Sjsg mediabay_intr(void *v)
2043ce2f8e0Sdrahn {
2053ce2f8e0Sdrahn struct mediabay_softc *sc = v;
2063ce2f8e0Sdrahn
2073ce2f8e0Sdrahn wakeup(&sc->sc_kthread);
2083ce2f8e0Sdrahn return 1;
2093ce2f8e0Sdrahn }
2103ce2f8e0Sdrahn
2113ce2f8e0Sdrahn void
mediabay_create_kthread(void * v)212*47d381f7Sjsg mediabay_create_kthread(void *v)
2133ce2f8e0Sdrahn {
2143ce2f8e0Sdrahn struct mediabay_softc *sc = v;
2153ce2f8e0Sdrahn
2162d257949Sderaadt kthread_create(mediabay_kthread, sc, &sc->sc_kthread,
2172d257949Sderaadt sc->sc_dev.dv_xname);
2183ce2f8e0Sdrahn }
2193ce2f8e0Sdrahn
2203ce2f8e0Sdrahn void
mediabay_kthread(void * v)221*47d381f7Sjsg mediabay_kthread(void *v)
2223ce2f8e0Sdrahn {
2233ce2f8e0Sdrahn struct mediabay_softc *sc = v;
2243ce2f8e0Sdrahn u_int x, fcr;
2253ce2f8e0Sdrahn
2263ce2f8e0Sdrahn sleep:
2273bf93282Scheloha tsleep_nsec(&sc->sc_kthread, PRIBIO, "mbayev", INFSLP);
2283ce2f8e0Sdrahn
2293ce2f8e0Sdrahn /* sleep 0.25 sec */
2303bf93282Scheloha tsleep_nsec(mediabay_kthread, PRIBIO, "mbayev", MSEC_TO_NSEC(250));
2313ce2f8e0Sdrahn
2323ce2f8e0Sdrahn DPRINTF("%s: ", sc->sc_dev.dv_xname);
2333ce2f8e0Sdrahn x = in32rb(sc->sc_addr);
2343ce2f8e0Sdrahn
2353ce2f8e0Sdrahn switch (MEDIABAY_ID(x)) {
2363ce2f8e0Sdrahn case MEDIABAY_ID_NONE:
2373ce2f8e0Sdrahn DPRINTF("removed\n");
2383ce2f8e0Sdrahn if (sc->sc_content != NULL) {
2393ce2f8e0Sdrahn config_detach(sc->sc_content, DETACH_FORCE);
2403ce2f8e0Sdrahn DPRINTF("%s: detach done\n", sc->sc_dev.dv_xname);
2413ce2f8e0Sdrahn sc->sc_content = NULL;
2423ce2f8e0Sdrahn
2433ce2f8e0Sdrahn /* disable media-bay */
2443ce2f8e0Sdrahn fcr = in32rb(sc->sc_fcr);
2453ce2f8e0Sdrahn fcr &= ~(FCR_MEDIABAY_ENABLE |
2463ce2f8e0Sdrahn FCR_MEDIABAY_IDE_ENABLE |
2473ce2f8e0Sdrahn FCR_MEDIABAY_CD_POWER |
2483ce2f8e0Sdrahn FCR_MEDIABAY_FD_ENABLE);
2493ce2f8e0Sdrahn out32rb(sc->sc_fcr, fcr);
2503ce2f8e0Sdrahn }
2513ce2f8e0Sdrahn break;
2523ce2f8e0Sdrahn case MEDIABAY_ID_FD:
2533ce2f8e0Sdrahn DPRINTF("FD inserted\n");
2543ce2f8e0Sdrahn break;
2553ce2f8e0Sdrahn case MEDIABAY_ID_CD:
2563ce2f8e0Sdrahn DPRINTF("CD inserted\n");
2573ce2f8e0Sdrahn
2583ce2f8e0Sdrahn if (sc->sc_content == NULL)
2593ce2f8e0Sdrahn mediabay_attach_content(sc);
2603ce2f8e0Sdrahn break;
2613ce2f8e0Sdrahn default:
2623ce2f8e0Sdrahn printf("unknown event (0x%x)\n", x);
2633ce2f8e0Sdrahn }
2643ce2f8e0Sdrahn
2653ce2f8e0Sdrahn goto sleep;
2663ce2f8e0Sdrahn }
2673ce2f8e0Sdrahn
2683ce2f8e0Sdrahn /* PBG3: 0x7025X0c0 */
2693ce2f8e0Sdrahn /* 2400: 0x0070X0a8 */
270