> Date: Thu, 3 Jan 2019 12:53:58 +1000 > From: David Gwynne <[email protected]> > > this adds support for the ohci controllers seen on the pine64. > > it is very quick and very dirty, but it works. i'm able to use a usb1 > serial dongle now where it didnt even connect before.
Heh, I thought there would be some ehci to ohci handover issues. USB 2.0 devices still work with this enabled as well? > > i believe it relies on the ehci companion setting up the phy. Yes. The way that happens is a bit of a hack and maybe at some point the code needs to be split out in its own driver. But this should be good enought for now. > ok? Basically, yes, but a few comments/nits below. > Index: files.fdt > =================================================================== > RCS file: /cvs/src/sys/dev/fdt/files.fdt,v > retrieving revision 1.74 > diff -u -p -r1.74 files.fdt > --- files.fdt 27 Aug 2018 21:09:47 -0000 1.74 > +++ files.fdt 3 Jan 2019 02:49:07 -0000 > @@ -109,6 +109,9 @@ file dev/fdt/if_dwge_fdt.c dwge_fdt > attach ehci at fdt with ehci_fdt > file dev/fdt/ehci_fdt.c ehci_fdt > > +attach ohci at fdt with ohci_fdt > +file dev/fdt/ohci_fdt.c ohci_fdt > + > attach sdhc at fdt with sdhc_fdt > file dev/fdt/sdhc_fdt.c sdhc_fdt > > Index: ohci_fdt.c > =================================================================== > RCS file: ohci_fdt.c > diff -N ohci_fdt.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ ohci_fdt.c 3 Jan 2019 02:49:07 -0000 > @@ -0,0 +1,200 @@ > +/* $OpenBSD: ohci_fdt.c,v 1.4 2018/08/06 10:52:30 patrick Exp $ */ > + > +/* > + * Copyright (c) 2005, 2019 David Gwynne <[email protected]> > + * Copyright (c) 2017 Mark Kettenis <[email protected]> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <sys/types.h> > +#include <sys/systm.h> > +#include <sys/device.h> > +#include <sys/malloc.h> > + > +#include <machine/intr.h> > +#include <machine/bus.h> > +#include <machine/fdt.h> > + > +#include <dev/ofw/openfirm.h> > +#include <dev/ofw/ofw_clock.h> > +#include <dev/ofw/ofw_pinctrl.h> > +#include <dev/ofw/ofw_regulator.h> > +#include <dev/ofw/fdt.h> > + > +#include <dev/usb/usb.h> > +#include <dev/usb/usbdi.h> > +#include <dev/usb/usbdivar.h> > +#include <dev/usb/usb_mem.h> > + > +#include <dev/usb/ohcireg.h> > +#include <dev/usb/ohcivar.h> > + > +struct ohci_fdt_softc { > + struct ohci_softc sc; > + int sc_node; > + void *sc_ih; > +}; > + > +int ohci_fdt_match(struct device *, void *, void *); > +void ohci_fdt_attach(struct device *, struct device *, void *); > +int ohci_fdt_detach(struct device *, int); > + > +struct cfattach ohci_fdt_ca = { > + sizeof(struct ohci_fdt_softc), > + ohci_fdt_match, > + ohci_fdt_attach, > + ohci_fdt_detach, > + ohci_activate > +}; I'd format this the same way as was done for ehci at fdt, but shrug. > + > +static void ohci_fdt_attach_deferred(struct device *); Please avoid static. > +int > +ohci_fdt_match(struct device *parent, void *match, void *aux) > +{ > + struct fdt_attach_args *faa = aux; > + > + return OF_is_compatible(faa->fa_node, "generic-ohci"); > +} > + > +void > +ohci_fdt_attach(struct device *parent, struct device *self, void *aux) > +{ > + struct ohci_fdt_softc *sc = (struct ohci_fdt_softc *)self; > + struct fdt_attach_args *faa = aux; > + char *devname = sc->sc.sc_bus.bdev.dv_xname; > + > + if (faa->fa_nreg < 1) { > + printf(": no registers\n"); > + return; > + } > + > + sc->sc_node = faa->fa_node; > + sc->sc.iot = faa->fa_iot; > + sc->sc.sc_bus.dmatag = faa->fa_dmat; > + sc->sc.sc_size = faa->fa_reg[0].size; > + > + if (bus_space_map(sc->sc.iot, faa->fa_reg[0].addr, > + faa->fa_reg[0].size, 0, &sc->sc.ioh)) { > + printf(": can't map registers\n"); > + goto out; > + } > + > + pinctrl_byname(sc->sc_node, "default"); > + > + clock_enable_all(sc->sc_node); > + reset_deassert_all(sc->sc_node); > + > + /* Record what interrupts were enabled by SMM/BIOS. */ > + sc->sc.sc_intre = bus_space_read_4(sc->sc.iot, sc->sc.ioh, > + OHCI_INTERRUPT_ENABLE); > + > + /* Disable interrupts, so we don't get any spurious ones. */ > + bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE, > + OHCI_MIE); > + > + bus_space_barrier(sc->sc.iot, sc->sc.ioh, 0, sc->sc.sc_size, > + BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); > + bus_space_write_4(sc->sc.iot, sc->sc.ioh, > + OHCI_INTERRUPT_DISABLE, OHCI_MIE); > + > + /* Map and establish the interrupt. */ > + splassert(IPL_USB); > + sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_USB, > + ohci_intr, &sc->sc, devname); > + if (sc->sc_ih == NULL) { > + printf(": can't establish interrupt\n"); > + goto disable_clocks; > + } > + printf(": fdt"); Don't really want this. > + > + strlcpy(sc->sc.sc_vendor, "Generic", sizeof(sc->sc.sc_vendor)); > + > + /* Display revision and perform legacy emulation handover. */ > + if (ohci_checkrev(&sc->sc) != USBD_NORMAL_COMPLETION || > + ohci_handover(&sc->sc) != USBD_NORMAL_COMPLETION) { > + goto disestablish_intr; > + } I suspect that calling ohci_handover() here isn't really necessary. Perhaps leave that out (and adjust the comment). > + > + /* Ignore interrupts for now */ > + sc->sc.sc_bus.dying = 1; > + > + config_defer(self, ohci_fdt_attach_deferred); > + > + return; > + > +disestablish_intr: > + fdt_intr_disestablish(sc->sc_ih); > + sc->sc_ih = NULL; > +disable_clocks: > + clock_disable_all(sc->sc_node); > + > + bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); > + sc->sc.sc_size = 0; > +out: > + return; > +} > + > +static void > +ohci_fdt_attach_deferred(struct device *self) > +{ > + struct ohci_fdt_softc *sc = (struct ohci_fdt_softc *)self; > + usbd_status r; > + int s; > + > + s = splusb(); > + > + sc->sc.sc_bus.dying = 0; > + > + r = ohci_init(&sc->sc); > + > + splx(s); > + if (r != USBD_NORMAL_COMPLETION) { > + printf("%s: init failed, error=%d\n", > + sc->sc.sc_bus.bdev.dv_xname, r); > + fdt_intr_disestablish(sc->sc_ih); > + sc->sc_ih = NULL; > + clock_disable_all(sc->sc_node); > + bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); > + sc->sc.sc_size = 0; > + return; > + } > + > + /* Attach usb device. */ > + config_found(self, &sc->sc.sc_bus, usbctlprint); > +} > + > +int > +ohci_fdt_detach(struct device *self, int flags) > +{ > + struct ohci_fdt_softc *sc = (struct ohci_fdt_softc *)self; > + int rv; > + > + rv = ohci_detach(self, flags); > + if (rv) > + return rv; > + > + if (sc->sc_ih != NULL) { > + fdt_intr_disestablish(sc->sc_ih); > + sc->sc_ih = NULL; > + } > + > + if (sc->sc.sc_size) { > + bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); > + sc->sc.sc_size = 0; > + } > + > + clock_disable_all(sc->sc_node); > + return 0; > +} > >
