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