xref: /openbsd-src/sys/arch/macppc/dev/mediabay.c (revision 47d381f7459befb118ddf7dceadd89e8d19c9a0e)
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