xref: /netbsd-src/sys/arch/mips/rmi/rmixl_usbi.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1*c7fb772bSthorpej /*	$NetBSD: rmixl_usbi.c,v 1.7 2021/08/07 16:18:59 thorpej Exp $	*/
23e67b512Smatt 
33e67b512Smatt /*-
43e67b512Smatt  * Copyright (c) 1998, 1999, 2000, 2002, 2003 The NetBSD Foundation, Inc.
53e67b512Smatt  * All rights reserved.
63e67b512Smatt  *
73e67b512Smatt  * This code is derived from software contributed to The NetBSD Foundation
83e67b512Smatt  * by Cliff Neighbors
93e67b512Smatt  *
103e67b512Smatt  * Redistribution and use in source and binary forms, with or without
113e67b512Smatt  * modification, are permitted provided that the following conditions
123e67b512Smatt  * are met:
133e67b512Smatt  * 1. Redistributions of source code must retain the above copyright
143e67b512Smatt  *    notice, this list of conditions and the following disclaimer.
153e67b512Smatt  * 2. Redistributions in binary form must reproduce the above copyright
163e67b512Smatt  *    notice, this list of conditions and the following disclaimer in the
173e67b512Smatt  *    documentation and/or other materials provided with the distribution.
183e67b512Smatt  *
193e67b512Smatt  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
203e67b512Smatt  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
213e67b512Smatt  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
223e67b512Smatt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
233e67b512Smatt  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
243e67b512Smatt  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
253e67b512Smatt  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
263e67b512Smatt  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
273e67b512Smatt  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
283e67b512Smatt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
293e67b512Smatt  * POSSIBILITY OF SUCH DAMAGE.
303e67b512Smatt  */
313e67b512Smatt 
323e67b512Smatt #include <sys/cdefs.h>
33*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: rmixl_usbi.c,v 1.7 2021/08/07 16:18:59 thorpej Exp $");
343e67b512Smatt 
353e67b512Smatt #include "locators.h"
363e67b512Smatt 
373e67b512Smatt #include <sys/param.h>
383e67b512Smatt #include <sys/systm.h>
393e67b512Smatt #include <sys/device.h>
403e67b512Smatt 
41cf10107dSdyoung #include <sys/bus.h>
423e67b512Smatt 
433e67b512Smatt #include <mips/rmi/rmixlreg.h>
443e67b512Smatt #include <mips/rmi/rmixlvar.h>
453e67b512Smatt #include <mips/rmi/rmixl_intr.h>
463e67b512Smatt #include <mips/rmi/rmixl_obiovar.h>
473e67b512Smatt #include <mips/rmi/rmixl_usbivar.h>
483e67b512Smatt 
493e67b512Smatt #include <dev/usb/usb.h>
503e67b512Smatt #include <dev/usb/usbdi.h>
513e67b512Smatt #include <dev/usb/usbdivar.h>
523e67b512Smatt #include <dev/usb/usb_mem.h>
533e67b512Smatt 
543e67b512Smatt /*
553e67b512Smatt  * USB I/O register byte order is
563e67b512Smatt  * LITTLE ENDIAN regardless of code model
573e67b512Smatt  */
583e67b512Smatt #define RMIXL_USBI_GEN_VADDR(o)	\
593e67b512Smatt 	(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(	\
603e67b512Smatt 		rmixl_configuration.rc_io_pbase + RMIXL_IO_DEV_USB_B + (o))
613e67b512Smatt #define RMIXL_USBI_GEN_READ(o)     le32toh(*RMIXL_USBI_GEN_VADDR(o))
623e67b512Smatt #define RMIXL_USBI_GEN_WRITE(o,v)  *RMIXL_USBI_GEN_VADDR(o) = htole32(v)
633e67b512Smatt 
64294e5e26Smatt static const char rmixl_usbi_intrnames[RMIXL_UB_INTERRUPT_MAX+1][16] = {
653e67b512Smatt 	"int 0 (ohci0)",
663e67b512Smatt 	"int 1 (ohci1)",
673e67b512Smatt 	"int 2 (ehci)",
683e67b512Smatt 	"int 3 (device)",
693e67b512Smatt 	"int 4 (phy)",
703e67b512Smatt 	"int 5 (force)"
713e67b512Smatt };
723e67b512Smatt 
733e67b512Smatt static int	rmixl_usbi_match(device_t, cfdata_t, void *);
743e67b512Smatt static void	rmixl_usbi_attach(device_t, device_t, void *);
753e67b512Smatt static int  	rmixl_usbi_print(void *, const char *);
763e67b512Smatt static int  	rmixl_usbi_search(device_t, cfdata_t, const int *, void *);
773e67b512Smatt static int      rmixl_usbi_intr(void *);
783e67b512Smatt 
793e67b512Smatt #ifdef RMIXL_USBI_DEBUG
803e67b512Smatt int	rmixl_usbi_rdump(void);
813e67b512Smatt rmixl_usbi_softc_t *rmixl_usbi_sc;
823e67b512Smatt #endif
833e67b512Smatt 
843e67b512Smatt 
853e67b512Smatt CFATTACH_DECL_NEW(rmixl_usbi, sizeof (rmixl_usbi_softc_t),
863e67b512Smatt     rmixl_usbi_match, rmixl_usbi_attach, NULL, NULL);
873e67b512Smatt 
883e67b512Smatt int
rmixl_usbi_match(device_t parent,cfdata_t match,void * aux)893e67b512Smatt rmixl_usbi_match(device_t parent, cfdata_t match, void *aux)
903e67b512Smatt {
913e67b512Smatt 	struct obio_attach_args *obio = aux;
923e67b512Smatt 
933e67b512Smatt         if (obio->obio_addr == RMIXL_IO_DEV_USB_B)
943e67b512Smatt 		return rmixl_probe_4((volatile uint32_t *)RMIXL_IOREG_VADDR(obio->obio_addr));
953e67b512Smatt 
963e67b512Smatt         return 0;
973e67b512Smatt }
983e67b512Smatt 
993e67b512Smatt void
rmixl_usbi_attach(device_t parent,device_t self,void * aux)1003e67b512Smatt rmixl_usbi_attach(device_t parent, device_t self, void *aux)
1013e67b512Smatt {
1023e67b512Smatt 	rmixl_usbi_softc_t *sc = device_private(self);
1033e67b512Smatt 	struct obio_attach_args *obio = aux;
1043e67b512Smatt 	uint32_t r;
1053e67b512Smatt 	void *ih;
1063e67b512Smatt 
1073e67b512Smatt #ifdef RMIXL_USBI_DEBUG
1083e67b512Smatt 	rmixl_usbi_sc = sc;
1093e67b512Smatt #endif
1103e67b512Smatt 	sc->sc_dev = self;
1113e67b512Smatt 	sc->sc_eb_bst = obio->obio_eb_bst;
1123e67b512Smatt 	sc->sc_el_bst = obio->obio_el_bst;
1133e67b512Smatt 	sc->sc_addr = obio->obio_addr;
1143e67b512Smatt 	sc->sc_size = obio->obio_size;
1153e67b512Smatt 	sc->sc_dmat = obio->obio_32bit_dmat;
1163e67b512Smatt 
1173e67b512Smatt 	aprint_normal("\n%s", device_xname(self));
1183e67b512Smatt 
1193e67b512Smatt 	/*
1203e67b512Smatt 	 * fail attach if USB interface is disabled GPIO LOW_PWR_DIS reg
1213e67b512Smatt 	 */
1223e67b512Smatt 	r = RMIXL_IOREG_READ(RMIXL_IO_DEV_GPIO + RMIXL_GPIO_LOW_PWR_DIS);
1233e67b512Smatt 	if ((r & RMIXL_GPIO_LOW_PWR_DIS_USB) != 0) {
1243e67b512Smatt 		aprint_error(": USB_DIS set in LOW_PWR_DIS, abort attach\n");
1253e67b512Smatt 		return;
1263e67b512Smatt 	}
1273e67b512Smatt 
1283e67b512Smatt 	/*
1293e67b512Smatt 	 * fail attach if USB interface BIST failed
1303e67b512Smatt 	 */
1313e67b512Smatt         r = RMIXL_IOREG_READ(RMIXL_IO_DEV_GPIO + RMIXL_GPIO_BIST_EACH_STS);
132294e5e26Smatt 	aprint_normal(": BIST status=%s,",
133294e5e26Smatt 	    (r & __BIT(18)) ? "OK" : "FAIL");		/* XXX USB_BIST */
1343e67b512Smatt 
1353e67b512Smatt 	/*
1363e67b512Smatt 	 * set BYTESWAP_EN register nonzero when software is little endian
1373e67b512Smatt 	 */
1383e67b512Smatt #if BYTE_ORDER == BIG_ENDIAN
1393e67b512Smatt 	r = 0;
1403e67b512Smatt #else
1413e67b512Smatt 	r = 1;
1423e67b512Smatt #endif
1433e67b512Smatt 	RMIXL_USBI_GEN_WRITE(RMIXL_USB_BYTESWAP_EN, r);
1443e67b512Smatt 	aprint_normal(" byteswap enable=%d", r);
1453e67b512Smatt 	for (int intr=0; intr <= RMIXL_UB_INTERRUPT_MAX; intr++) {
1463e67b512Smatt 		evcnt_attach_dynamic(&sc->sc_dispatch[intr].count,
1473e67b512Smatt 			EVCNT_TYPE_INTR, NULL, "rmixl_usbi",
1483e67b512Smatt 				rmixl_usbi_intrnames[intr]);
1493e67b512Smatt 	}
1503e67b512Smatt 
1513e67b512Smatt 	/* Disable all usb interface interrupts */
1523e67b512Smatt 	RMIXL_USBI_GEN_WRITE(RMIXL_USB_INTERRUPT_ENABLE, 0);
1533e67b512Smatt 
1543e67b512Smatt 	/* establish interrupt */
1553e67b512Smatt 	if (obio->obio_intr != OBIOCF_INTR_DEFAULT) {
1563e67b512Smatt 		ih = rmixl_intr_establish(obio->obio_intr, obio->obio_tmsk,
1573e67b512Smatt 			IPL_USB, RMIXL_TRIG_LEVEL, RMIXL_POLR_HIGH,
1583e67b512Smatt 			rmixl_usbi_intr, sc, false);
1593e67b512Smatt 		if (ih == NULL)
1603e67b512Smatt 			panic("%s: couldn't establish interrupt",
1613e67b512Smatt 				device_xname(self));
1623e67b512Smatt 	}
1633e67b512Smatt 
1643e67b512Smatt 	aprint_normal("\n");
1653e67b512Smatt 
1663e67b512Smatt 	/* attach any children */
1672685996bSthorpej 	config_search(self, NULL,
168*c7fb772bSthorpej 	    CFARGS(.search = rmixl_usbi_search));
1693e67b512Smatt }
1703e67b512Smatt 
1713e67b512Smatt static int
rmixl_usbi_print(void * aux,const char * pnp)1723e67b512Smatt rmixl_usbi_print(void *aux, const char *pnp)
1733e67b512Smatt {
1743e67b512Smatt 	struct rmixl_usbi_attach_args *usbi = aux;
1753e67b512Smatt 
1763e67b512Smatt 	if (usbi->usbi_addr != RMIXL_USBICF_ADDR_DEFAULT) {
1773e67b512Smatt 		aprint_normal(" addr %#"PRIxBUSADDR, usbi->usbi_addr);
1783e67b512Smatt 		if (usbi->usbi_size != RMIXL_USBICF_SIZE_DEFAULT)
1793e67b512Smatt 			aprint_normal("-%#"PRIxBUSADDR,
1803e67b512Smatt 				usbi->usbi_addr + (usbi->usbi_size - 1));
1813e67b512Smatt 	}
1823e67b512Smatt 	if (usbi->usbi_intr != RMIXL_USBICF_INTR_DEFAULT)
1833e67b512Smatt 		aprint_normal(" intr %d", usbi->usbi_intr);
1843e67b512Smatt 
1853e67b512Smatt 	aprint_normal("\n");
1863e67b512Smatt 
1873e67b512Smatt 	return (UNCONF);
1883e67b512Smatt }
1893e67b512Smatt 
1903e67b512Smatt static int
rmixl_usbi_search(device_t parent,cfdata_t cf,const int * ldesc,void * aux)1913e67b512Smatt rmixl_usbi_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
1923e67b512Smatt {
1933e67b512Smatt 	struct rmixl_usbi_softc *sc = device_private(parent);
1943e67b512Smatt 	struct rmixl_usbi_attach_args usbi;
1953e67b512Smatt 
1963e67b512Smatt 	usbi.usbi_eb_bst = sc->sc_eb_bst;
1973e67b512Smatt 	usbi.usbi_el_bst = sc->sc_el_bst;
1983e67b512Smatt 	usbi.usbi_addr = cf->cf_loc[RMIXL_USBICF_ADDR];
1993e67b512Smatt 	usbi.usbi_size = cf->cf_loc[RMIXL_USBICF_SIZE];
2003e67b512Smatt 	usbi.usbi_intr = cf->cf_loc[RMIXL_USBICF_INTR];
2013e67b512Smatt 	usbi.usbi_dmat = sc->sc_dmat;
2023e67b512Smatt 
2032685996bSthorpej 	if (config_probe(parent, cf, &usbi))
204*c7fb772bSthorpej 		config_attach(parent, cf, &usbi, rmixl_usbi_print, CFARGS_NONE);
2053e67b512Smatt 
2063e67b512Smatt 	return 0;
2073e67b512Smatt }
2083e67b512Smatt 
2093e67b512Smatt 
2103e67b512Smatt void
rmixl_usbi_intr_disestablish(void * uh,void * ih)2113e67b512Smatt rmixl_usbi_intr_disestablish(void *uh, void *ih)
2123e67b512Smatt {
2133e67b512Smatt 	rmixl_usbi_softc_t *sc = uh;
2143e67b512Smatt 	u_int intr;
2153e67b512Smatt 
2163e67b512Smatt 	for (intr=0; intr <= RMIXL_UB_INTERRUPT_MAX; intr++) {
2173e67b512Smatt 		if (ih == &sc->sc_dispatch[intr]) {
2183e67b512Smatt 			uint32_t r;
2193e67b512Smatt 
2203e67b512Smatt 			/* disable this interrupt in the usb interface */
2213e67b512Smatt 			r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_ENABLE);
2223e67b512Smatt 			r &= 1 << intr;
2233e67b512Smatt 			RMIXL_USBI_GEN_WRITE(RMIXL_USB_INTERRUPT_ENABLE, r);
2243e67b512Smatt 
2253e67b512Smatt 			/* free the dispatch slot */
2263e67b512Smatt 			sc->sc_dispatch[intr].func = NULL;
2273e67b512Smatt 			sc->sc_dispatch[intr].arg = NULL;
2283e67b512Smatt 
2293e67b512Smatt 			break;
2303e67b512Smatt 		}
2313e67b512Smatt 	}
2323e67b512Smatt }
2333e67b512Smatt 
2343e67b512Smatt void *
rmixl_usbi_intr_establish(void * uh,u_int intr,int (func)(void *),void * arg)2353e67b512Smatt rmixl_usbi_intr_establish(void *uh, u_int intr, int (func)(void *), void *arg)
2363e67b512Smatt {
2373e67b512Smatt 	rmixl_usbi_softc_t *sc = uh;
2383e67b512Smatt 	uint32_t r;
2393e67b512Smatt 	void *ih = NULL;
2403e67b512Smatt 	int s;
2413e67b512Smatt 
2423e67b512Smatt 	s = splusb();
2433e67b512Smatt 
2443e67b512Smatt 	if (intr > RMIXL_UB_INTERRUPT_MAX) {
2453e67b512Smatt 		aprint_error_dev(sc->sc_dev, "invalid intr %d\n", intr);
2463e67b512Smatt 		goto out;
2473e67b512Smatt 	}
2483e67b512Smatt 
2493e67b512Smatt 	if (sc->sc_dispatch[intr].func != NULL) {
2503e67b512Smatt 		aprint_error_dev(sc->sc_dev, "intr %dq busy\n", intr);
2513e67b512Smatt 		goto out;
2523e67b512Smatt 	}
2533e67b512Smatt 
2543e67b512Smatt 	sc->sc_dispatch[intr].func = func;
2553e67b512Smatt 	sc->sc_dispatch[intr].arg = arg;
2563e67b512Smatt 	ih = &sc->sc_dispatch[intr];
2573e67b512Smatt 
2583e67b512Smatt 	/* enable this interrupt in the usb interface */
2593e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_ENABLE);
2603e67b512Smatt 	r |= 1 << intr;
2613e67b512Smatt 	RMIXL_USBI_GEN_WRITE(RMIXL_USB_INTERRUPT_ENABLE, r);
2623e67b512Smatt 
2633e67b512Smatt  out:
2643e67b512Smatt 	splx(s);
2653e67b512Smatt 	return ih;
2663e67b512Smatt }
2673e67b512Smatt 
2683e67b512Smatt static int
rmixl_usbi_intr(void * arg)2693e67b512Smatt rmixl_usbi_intr(void *arg)
2703e67b512Smatt {
2713e67b512Smatt 	rmixl_usbi_softc_t *sc = arg;
2723e67b512Smatt 	uint32_t r;
2733e67b512Smatt 	int intr;
2743e67b512Smatt 	int rv = 0;
2753e67b512Smatt 
2763e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_STATUS);
2773e67b512Smatt 	if (r != 0) {
2783e67b512Smatt 		for (intr=0; intr <= RMIXL_UB_INTERRUPT_MAX; intr++) {
2793e67b512Smatt 			uint32_t bit = 1 << intr;
2803e67b512Smatt 			if ((r & bit) != 0) {
2813e67b512Smatt 				int (*f)(void *) = sc->sc_dispatch[intr].func;
2823e67b512Smatt 				void *a = sc->sc_dispatch[intr].arg;
2833e67b512Smatt 				if (f != NULL) {
2843e67b512Smatt 					(void)(*f)(a);
2853e67b512Smatt 					sc->sc_dispatch[intr].count.ev_count++;
2863e67b512Smatt 					rv = 1;
2873e67b512Smatt 				}
2883e67b512Smatt 			}
2893e67b512Smatt 		}
2903e67b512Smatt 	}
2913e67b512Smatt 
2923e67b512Smatt 	return rv;
2933e67b512Smatt }
2943e67b512Smatt 
2953e67b512Smatt #ifdef RMIXL_USBI_DEBUG
2963e67b512Smatt int
rmixl_usbi_rdump(void)2973e67b512Smatt rmixl_usbi_rdump(void)
2983e67b512Smatt {
2993e67b512Smatt 	rmixl_usbi_softc_t *sc = rmixl_usbi_sc;
3003e67b512Smatt 	uint32_t r;
3013e67b512Smatt 
3023e67b512Smatt 	if (sc == NULL)
3033e67b512Smatt 		return -1;
3043e67b512Smatt 
3053e67b512Smatt 	printf("\n%s:\n", __func__);
3063e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_GEN_CTRL1);
3073e67b512Smatt 	printf(" USB_GEN_CTRL1 %#x\n", r);
3083e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_GEN_CTRL2);
3093e67b512Smatt 	printf(" USB_GEN_CTRL2 %#x\n", r);
3103e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_GEN_CTRL3);
3113e67b512Smatt 	printf(" USB_GEN_CTRL3 %#x\n", r);
3123e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_IOBM_TIMER);
3133e67b512Smatt 	printf(" USB_IOBM_TIMER %#x\n", r);
3143e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_VBUS_TIMER);
3153e67b512Smatt 	printf(" USB_VBUS_TIMER %#x\n", r);
3163e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_BYTESWAP_EN);
3173e67b512Smatt 	printf(" USB_BYTESWAP_EN %#x\n", r);
3183e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_COHERENT_MEM_BASE);
3193e67b512Smatt 	printf(" USB_COHERENT_MEM_BASE %#x\n", r);
3203e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_COHERENT_MEM_LIMIT);
3213e67b512Smatt 	printf(" USB_COHERENT_MEM_LIMIT %#x\n", r);
3223e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_L2ALLOC_MEM_BASE);
3233e67b512Smatt 	printf(" USB_L2ALLOC_MEM_BASE %#x\n", r);
3243e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_L2ALLOC_MEM_LIMIT);
3253e67b512Smatt 	printf(" USB_L2ALLOC_MEM_LIMIT %#x\n", r);
3263e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_READEX_MEM_BASE);
3273e67b512Smatt 	printf(" USB_READEX_MEM_BASE %#x\n", r);
3283e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_READEX_MEM_LIMIT);
3293e67b512Smatt 	printf(" USB_READEX_MEM_LIMIT %#x\n", r);
3303e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_PHY_STATUS);
3313e67b512Smatt 	printf(" USB_PHY_STATUS %#x\n", r);
3323e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_STATUS);
3333e67b512Smatt 	printf(" USB_INTERRUPT_STATUS %#x\n", r);
3343e67b512Smatt 	r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_ENABLE);
3353e67b512Smatt 	printf(" USB_INTERRUPT_ENABLE %#x\n", r);
3363e67b512Smatt 
3373e67b512Smatt 	return 0;
3383e67b512Smatt }
3393e67b512Smatt #endif
340