diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2019-01-04 23:55:30 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2019-01-04 23:55:30 +0000 |
commit | 69c56c2170128d20d042999275294832377fa4c9 (patch) | |
tree | 561cce0c581ec35023b472b31070f16b1d190f98 /sys/dev | |
parent | 71b09ed0120b994a3630d91005807c8498f86a0c (diff) |
add support for ohci, as found on the pine64
this currently relies on the usbphy code in the ehci fdt glue to
work, but this is a work in progress. there's an extra printf of
fdt in the dmesg to make the ohci checkrev code not look terrible.
ok kettenis@
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/fdt/files.fdt | 5 | ||||
-rw-r--r-- | sys/dev/fdt/ohci_fdt.c | 199 |
2 files changed, 203 insertions, 1 deletions
diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt index 5276439c306..6092bd64396 100644 --- a/sys/dev/fdt/files.fdt +++ b/sys/dev/fdt/files.fdt @@ -1,4 +1,4 @@ -# $OpenBSD: files.fdt,v 1.74 2018/08/27 21:09:47 kettenis Exp $ +# $OpenBSD: files.fdt,v 1.75 2019/01/04 23:55:29 dlg Exp $ # # Config file and device description for machine-independent FDT code. # Included by ports that need it. @@ -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 diff --git a/sys/dev/fdt/ohci_fdt.c b/sys/dev/fdt/ohci_fdt.c new file mode 100644 index 00000000000..12550f199f4 --- /dev/null +++ b/sys/dev/fdt/ohci_fdt.c @@ -0,0 +1,199 @@ +/* $OpenBSD: ohci_fdt.c,v 1.1 2019/01/04 23:55:29 dlg Exp $ */ + +/* + * Copyright (c) 2005, 2019 David Gwynne <dlg@openbsd.org> + * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org> + * + * 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 +}; + +void ohci_fdt_attach_deferred(struct device *); + +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"); + + strlcpy(sc->sc.sc_vendor, "Generic", sizeof(sc->sc.sc_vendor)); + + /* Display revision. Legacy handover isn't needed as there's no smm */ + if (ohci_checkrev(&sc->sc) != USBD_NORMAL_COMPLETION) { + goto disestablish_intr; + } + + /* 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; +} + +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; +} |