xref: /openbsd/sys/arch/loongson/dev/ohci_voyager.c (revision 471aeecf)
1*471aeecfSnaddy /*	$OpenBSD: ohci_voyager.c,v 1.8 2022/04/06 18:59:26 naddy Exp $	*/
24117f5ccSmiod /*	OpenBSD: ohci_pci.c,v 1.33 2008/06/26 05:42:17 ray Exp 	*/
34117f5ccSmiod /*	$NetBSD: ohci_pci.c,v 1.23 2002/10/02 16:51:47 thorpej Exp $	*/
44117f5ccSmiod 
54117f5ccSmiod /*
64117f5ccSmiod  * Copyright (c) 1998 The NetBSD Foundation, Inc.
74117f5ccSmiod  * All rights reserved.
84117f5ccSmiod  *
94117f5ccSmiod  * This code is derived from software contributed to The NetBSD Foundation
104117f5ccSmiod  * by Lennart Augustsson (lennart@augustsson.net) at
114117f5ccSmiod  * Carlstedt Research & Technology.
124117f5ccSmiod  *
134117f5ccSmiod  * Redistribution and use in source and binary forms, with or without
144117f5ccSmiod  * modification, are permitted provided that the following conditions
154117f5ccSmiod  * are met:
164117f5ccSmiod  * 1. Redistributions of source code must retain the above copyright
174117f5ccSmiod  *    notice, this list of conditions and the following disclaimer.
184117f5ccSmiod  * 2. Redistributions in binary form must reproduce the above copyright
194117f5ccSmiod  *    notice, this list of conditions and the following disclaimer in the
204117f5ccSmiod  *    documentation and/or other materials provided with the distribution.
214117f5ccSmiod  *
224117f5ccSmiod  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
234117f5ccSmiod  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
244117f5ccSmiod  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
254117f5ccSmiod  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
264117f5ccSmiod  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
274117f5ccSmiod  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
284117f5ccSmiod  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
294117f5ccSmiod  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
304117f5ccSmiod  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
314117f5ccSmiod  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
324117f5ccSmiod  * POSSIBILITY OF SUCH DAMAGE.
334117f5ccSmiod  */
344117f5ccSmiod 
354117f5ccSmiod /*
364117f5ccSmiod  * USB Open Host Controller driver.
374117f5ccSmiod  *
384117f5ccSmiod  * OHCI spec: http://www.intel.com/design/usb/ohci11d.pdf
394117f5ccSmiod  * USB spec: http://www.teleport.com/cgi-bin/mailmerge.cgi/~usb/cgiform.tpl
404117f5ccSmiod  */
414117f5ccSmiod 
424117f5ccSmiod #include <sys/param.h>
434117f5ccSmiod #include <sys/systm.h>
444117f5ccSmiod #include <sys/kernel.h>
454117f5ccSmiod #include <sys/device.h>
464117f5ccSmiod #include <sys/proc.h>
474117f5ccSmiod #include <sys/queue.h>
484117f5ccSmiod 
494117f5ccSmiod #include <machine/bus.h>
504117f5ccSmiod 
514117f5ccSmiod #include <dev/pci/pcivar.h>
524117f5ccSmiod 
534117f5ccSmiod #include <loongson/dev/voyagerreg.h>
544117f5ccSmiod #include <loongson/dev/voyagervar.h>
554117f5ccSmiod 
564117f5ccSmiod #include <dev/usb/usb.h>
574117f5ccSmiod #include <dev/usb/usbdi.h>
584117f5ccSmiod #include <dev/usb/usbdivar.h>
594117f5ccSmiod #include <dev/usb/usb_mem.h>
604117f5ccSmiod 
614117f5ccSmiod #include <dev/usb/ohcireg.h>
624117f5ccSmiod #include <dev/usb/ohcivar.h>
634117f5ccSmiod 
644117f5ccSmiod extern int gdium_revision;
654117f5ccSmiod 
664117f5ccSmiod int	ohci_voyager_match(struct device *, void *, void *);
674117f5ccSmiod void	ohci_voyager_attach(struct device *, struct device *, void *);
684117f5ccSmiod void	ohci_voyager_attach_deferred(struct device *);
694117f5ccSmiod 
704117f5ccSmiod struct ohci_voyager_softc {
7172c2a234Sderaadt 	struct ohci_softc	sc;
724117f5ccSmiod 	void 			*sc_ih;
734117f5ccSmiod };
744117f5ccSmiod 
75*471aeecfSnaddy const struct cfattach ohci_voyager_ca = {
764117f5ccSmiod 	sizeof(struct ohci_voyager_softc),
774117f5ccSmiod 	ohci_voyager_match, ohci_voyager_attach, NULL, ohci_activate
784117f5ccSmiod };
794117f5ccSmiod 
804117f5ccSmiod int
ohci_voyager_match(struct device * parent,void * vcf,void * aux)814117f5ccSmiod ohci_voyager_match(struct device *parent, void *vcf, void *aux)
824117f5ccSmiod {
834117f5ccSmiod 	struct voyager_attach_args *vaa = (struct voyager_attach_args *)aux;
844117f5ccSmiod 	struct cfdata *cf = (struct cfdata *)vcf;
854117f5ccSmiod 
864117f5ccSmiod 	return gdium_revision == 0 &&
874117f5ccSmiod 	    strcmp(vaa->vaa_name, cf->cf_driver->cd_name) == 0;
884117f5ccSmiod }
894117f5ccSmiod 
904117f5ccSmiod void
ohci_voyager_attach(struct device * parent,struct device * self,void * aux)914117f5ccSmiod ohci_voyager_attach(struct device *parent, struct device *self, void *aux)
924117f5ccSmiod {
934117f5ccSmiod 	struct ohci_voyager_softc *sc = (struct ohci_voyager_softc *)self;
944117f5ccSmiod 	struct voyager_attach_args *vaa = (struct voyager_attach_args *)aux;
954117f5ccSmiod 	struct pci_attach_args *pa = vaa->vaa_pa;
964117f5ccSmiod 	int s;
974117f5ccSmiod 	const char *vendor;
984117f5ccSmiod 	char *devname = sc->sc.sc_bus.bdev.dv_xname;
994117f5ccSmiod 
1004117f5ccSmiod 	/* Map I/O registers */
1014117f5ccSmiod 	sc->sc.sc_size = VOYAGER_OHCI_SIZE;
1024117f5ccSmiod 	sc->sc.iot = vaa->vaa_mmiot;
1034117f5ccSmiod 	if (bus_space_subregion(vaa->vaa_mmiot, vaa->vaa_mmioh,
1044117f5ccSmiod 	    VOYAGER_OHCI_BASE, VOYAGER_OHCI_SIZE, &sc->sc.ioh) != 0) {
1054117f5ccSmiod 		printf(": can't map mem space\n");
1064117f5ccSmiod 		return;
1074117f5ccSmiod 	}
1084117f5ccSmiod 
1094117f5ccSmiod 	/* Record what interrupts were enabled by SMM/BIOS. */
1104117f5ccSmiod 	sc->sc.sc_intre = bus_space_read_4(sc->sc.iot, sc->sc.ioh,
1114117f5ccSmiod 	    OHCI_INTERRUPT_ENABLE);
1124117f5ccSmiod 
1134117f5ccSmiod 	/* Disable interrupts, so we don't get any spurious ones. */
1144117f5ccSmiod 	bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE,
1154117f5ccSmiod 	    OHCI_MIE);
1164117f5ccSmiod 
1174117f5ccSmiod 	sc->sc.sc_bus.dmatag = pa->pa_dmat;
1184117f5ccSmiod 
1194117f5ccSmiod 	bus_space_barrier(sc->sc.iot, sc->sc.ioh, 0, sc->sc.sc_size,
1204117f5ccSmiod 	    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
1214117f5ccSmiod 	bus_space_write_4(sc->sc.iot, sc->sc.ioh,
1224117f5ccSmiod 	    OHCI_INTERRUPT_DISABLE, OHCI_MIE);
1234117f5ccSmiod 
1244117f5ccSmiod 	s = splusb();
1254117f5ccSmiod 	/* establish the interrupt. */
1264117f5ccSmiod 	sc->sc_ih = voyager_intr_establish(parent, VOYAGER_INTR_USB_HOST,
1274117f5ccSmiod 	    IPL_USB, ohci_intr, sc, devname);
1284117f5ccSmiod 	if (sc->sc_ih == NULL) {
1294117f5ccSmiod 		printf(": couldn't establish interrupt\n");
1304117f5ccSmiod 		splx(s);
1314117f5ccSmiod 		return;
1324117f5ccSmiod 	}
13371696a07Sdlg 	printf(": %s, ", voyager_intr_string(sc->sc_ih));
1344117f5ccSmiod 
1354117f5ccSmiod 	/* Figure out vendor for root hub descriptor. */
1364117f5ccSmiod 	vendor = pci_findvendor(pa->pa_id);
1374117f5ccSmiod 	sc->sc.sc_id_vendor = PCI_VENDOR(pa->pa_id);
1384117f5ccSmiod 	if (vendor)
1394117f5ccSmiod 		strlcpy(sc->sc.sc_vendor, vendor, sizeof (sc->sc.sc_vendor));
1404117f5ccSmiod 	else
1414117f5ccSmiod 		snprintf(sc->sc.sc_vendor, sizeof (sc->sc.sc_vendor),
1424117f5ccSmiod 		    "vendor 0x%04x", PCI_VENDOR(pa->pa_id));
1434117f5ccSmiod 
1444117f5ccSmiod 	/* Display revision and perform legacy emulation handover. */
1454117f5ccSmiod 	if (ohci_checkrev(&sc->sc) != USBD_NORMAL_COMPLETION ||
1464117f5ccSmiod 	    ohci_handover(&sc->sc) != USBD_NORMAL_COMPLETION) {
1474117f5ccSmiod 		splx(s);
1484117f5ccSmiod 		return;
1494117f5ccSmiod 	}
1504117f5ccSmiod 
1514117f5ccSmiod 	/* Ignore interrupts for now */
1525f332719Smiod 	sc->sc.sc_bus.dying = 1;
1534117f5ccSmiod 
1544117f5ccSmiod 	config_defer(self, ohci_voyager_attach_deferred);
1554117f5ccSmiod 
1564117f5ccSmiod 	splx(s);
1574117f5ccSmiod }
1584117f5ccSmiod 
1594117f5ccSmiod void
ohci_voyager_attach_deferred(struct device * self)1604117f5ccSmiod ohci_voyager_attach_deferred(struct device *self)
1614117f5ccSmiod {
1624117f5ccSmiod 	struct ohci_voyager_softc *sc = (struct ohci_voyager_softc *)self;
1634117f5ccSmiod 	usbd_status r;
1644117f5ccSmiod 	int s;
1654117f5ccSmiod 
1664117f5ccSmiod 	s = splusb();
1674117f5ccSmiod 
1685f332719Smiod 	sc->sc.sc_bus.dying = 0;
1694117f5ccSmiod 
1704117f5ccSmiod 	r = ohci_init(&sc->sc);
1714117f5ccSmiod 	if (r != USBD_NORMAL_COMPLETION) {
1724117f5ccSmiod 		printf("%s: init failed, error=%d\n",
1734117f5ccSmiod 		    sc->sc.sc_bus.bdev.dv_xname, r);
1744117f5ccSmiod 		bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
1754117f5ccSmiod 		splx(s);
1764117f5ccSmiod 		return;
1774117f5ccSmiod 	}
1784117f5ccSmiod 
1794117f5ccSmiod 	splx(s);
1804117f5ccSmiod 
1814117f5ccSmiod 	/* Attach usb device. */
182ad21ef77Smpi 	config_found(self, &sc->sc.sc_bus, usbctlprint);
1834117f5ccSmiod }
184