1*70320951SEmmanuel Vadot /*- 2*70320951SEmmanuel Vadot * Copyright (c) 2015 Semihalf. 3*70320951SEmmanuel Vadot * Copyright (c) 2015 Stormshield. 4*70320951SEmmanuel Vadot * All rights reserved. 5*70320951SEmmanuel Vadot * 6*70320951SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 7*70320951SEmmanuel Vadot * modification, are permitted provided that the following conditions 8*70320951SEmmanuel Vadot * are met: 9*70320951SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 10*70320951SEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 11*70320951SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 12*70320951SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 13*70320951SEmmanuel Vadot * documentation and/or other materials provided with the distribution. 14*70320951SEmmanuel Vadot * 15*70320951SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*70320951SEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*70320951SEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*70320951SEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*70320951SEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*70320951SEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*70320951SEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*70320951SEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*70320951SEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*70320951SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*70320951SEmmanuel Vadot * SUCH DAMAGE. 26*70320951SEmmanuel Vadot */ 27*70320951SEmmanuel Vadot 28*70320951SEmmanuel Vadot #include <sys/cdefs.h> 29*70320951SEmmanuel Vadot __FBSDID("$FreeBSD$"); 30*70320951SEmmanuel Vadot 31*70320951SEmmanuel Vadot #include "opt_bus.h" 32*70320951SEmmanuel Vadot 33*70320951SEmmanuel Vadot #include <sys/stdint.h> 34*70320951SEmmanuel Vadot #include <sys/stddef.h> 35*70320951SEmmanuel Vadot #include <sys/param.h> 36*70320951SEmmanuel Vadot #include <sys/queue.h> 37*70320951SEmmanuel Vadot #include <sys/types.h> 38*70320951SEmmanuel Vadot #include <sys/systm.h> 39*70320951SEmmanuel Vadot #include <sys/kernel.h> 40*70320951SEmmanuel Vadot #include <sys/bus.h> 41*70320951SEmmanuel Vadot #include <sys/module.h> 42*70320951SEmmanuel Vadot #include <sys/lock.h> 43*70320951SEmmanuel Vadot #include <sys/mutex.h> 44*70320951SEmmanuel Vadot #include <sys/condvar.h> 45*70320951SEmmanuel Vadot #include <sys/sysctl.h> 46*70320951SEmmanuel Vadot #include <sys/sx.h> 47*70320951SEmmanuel Vadot #include <sys/unistd.h> 48*70320951SEmmanuel Vadot #include <sys/priv.h> 49*70320951SEmmanuel Vadot #include <sys/rman.h> 50*70320951SEmmanuel Vadot 51*70320951SEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 52*70320951SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 53*70320951SEmmanuel Vadot 54*70320951SEmmanuel Vadot #include <dev/usb/usb.h> 55*70320951SEmmanuel Vadot #include <dev/usb/usbdi.h> 56*70320951SEmmanuel Vadot 57*70320951SEmmanuel Vadot #include <dev/usb/usb_core.h> 58*70320951SEmmanuel Vadot #include <dev/usb/usb_busdma.h> 59*70320951SEmmanuel Vadot #include <dev/usb/usb_process.h> 60*70320951SEmmanuel Vadot #include <dev/usb/usb_util.h> 61*70320951SEmmanuel Vadot 62*70320951SEmmanuel Vadot #include <dev/usb/usb_controller.h> 63*70320951SEmmanuel Vadot #include <dev/usb/usb_bus.h> 64*70320951SEmmanuel Vadot #include <dev/usb/controller/xhci.h> 65*70320951SEmmanuel Vadot #include <dev/usb/controller/xhcireg.h> 66*70320951SEmmanuel Vadot 67*70320951SEmmanuel Vadot #ifdef EXT_RESOURCES 68*70320951SEmmanuel Vadot #include <dev/extres/phy/phy.h> 69*70320951SEmmanuel Vadot #endif 70*70320951SEmmanuel Vadot 71*70320951SEmmanuel Vadot #define XHCI_HC_DEVSTR "Marvell Integrated USB 3.0 controller" 72*70320951SEmmanuel Vadot #define XHCI_HC_VENDOR "Marvell" 73*70320951SEmmanuel Vadot 74*70320951SEmmanuel Vadot #define IS_DMA_32B 1 75*70320951SEmmanuel Vadot 76*70320951SEmmanuel Vadot static device_attach_t xhci_attach; 77*70320951SEmmanuel Vadot static device_detach_t xhci_detach; 78*70320951SEmmanuel Vadot 79*70320951SEmmanuel Vadot static struct ofw_compat_data compat_data[] = { 80*70320951SEmmanuel Vadot {"marvell,armada-380-xhci", true}, 81*70320951SEmmanuel Vadot {"marvell,armada3700-xhci", true}, 82*70320951SEmmanuel Vadot {"marvell,armada-8k-xhci", true}, 83*70320951SEmmanuel Vadot {"generic-xhci", true}, 84*70320951SEmmanuel Vadot {NULL, false} 85*70320951SEmmanuel Vadot }; 86*70320951SEmmanuel Vadot 87*70320951SEmmanuel Vadot static int 88*70320951SEmmanuel Vadot xhci_probe(device_t dev) 89*70320951SEmmanuel Vadot { 90*70320951SEmmanuel Vadot 91*70320951SEmmanuel Vadot if (!ofw_bus_status_okay(dev)) 92*70320951SEmmanuel Vadot return (ENXIO); 93*70320951SEmmanuel Vadot 94*70320951SEmmanuel Vadot if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 95*70320951SEmmanuel Vadot return (ENXIO); 96*70320951SEmmanuel Vadot 97*70320951SEmmanuel Vadot device_set_desc(dev, XHCI_HC_DEVSTR); 98*70320951SEmmanuel Vadot 99*70320951SEmmanuel Vadot return (BUS_PROBE_DEFAULT); 100*70320951SEmmanuel Vadot } 101*70320951SEmmanuel Vadot 102*70320951SEmmanuel Vadot static int 103*70320951SEmmanuel Vadot xhci_attach(device_t dev) 104*70320951SEmmanuel Vadot { 105*70320951SEmmanuel Vadot struct xhci_softc *sc = device_get_softc(dev); 106*70320951SEmmanuel Vadot int err = 0, rid = 0; 107*70320951SEmmanuel Vadot #ifdef EXT_RESOURCES 108*70320951SEmmanuel Vadot phandle_t node; 109*70320951SEmmanuel Vadot phy_t phy; 110*70320951SEmmanuel Vadot #endif 111*70320951SEmmanuel Vadot 112*70320951SEmmanuel Vadot sc->sc_bus.parent = dev; 113*70320951SEmmanuel Vadot sc->sc_bus.devices = sc->sc_devices; 114*70320951SEmmanuel Vadot sc->sc_bus.devices_max = XHCI_MAX_DEVICES; 115*70320951SEmmanuel Vadot 116*70320951SEmmanuel Vadot sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 117*70320951SEmmanuel Vadot RF_ACTIVE); 118*70320951SEmmanuel Vadot if (sc->sc_io_res == NULL) { 119*70320951SEmmanuel Vadot device_printf(dev, "Failed to map memory\n"); 120*70320951SEmmanuel Vadot xhci_detach(dev); 121*70320951SEmmanuel Vadot return (ENXIO); 122*70320951SEmmanuel Vadot } 123*70320951SEmmanuel Vadot 124*70320951SEmmanuel Vadot sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 125*70320951SEmmanuel Vadot sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 126*70320951SEmmanuel Vadot sc->sc_io_size = rman_get_size(sc->sc_io_res); 127*70320951SEmmanuel Vadot 128*70320951SEmmanuel Vadot sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 129*70320951SEmmanuel Vadot RF_SHAREABLE | RF_ACTIVE); 130*70320951SEmmanuel Vadot if (sc->sc_irq_res == NULL) { 131*70320951SEmmanuel Vadot device_printf(dev, "Failed to allocate IRQ\n"); 132*70320951SEmmanuel Vadot xhci_detach(dev); 133*70320951SEmmanuel Vadot return (ENXIO); 134*70320951SEmmanuel Vadot } 135*70320951SEmmanuel Vadot 136*70320951SEmmanuel Vadot #ifdef EXT_RESOURCES 137*70320951SEmmanuel Vadot node = ofw_bus_get_node(dev); 138*70320951SEmmanuel Vadot if (phy_get_by_ofw_property(dev, node, "usb-phy", &phy) == 0) 139*70320951SEmmanuel Vadot if (phy_enable(phy) != 0) 140*70320951SEmmanuel Vadot device_printf(dev, "Cannot enable phy\n"); 141*70320951SEmmanuel Vadot #endif 142*70320951SEmmanuel Vadot 143*70320951SEmmanuel Vadot sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); 144*70320951SEmmanuel Vadot if (sc->sc_bus.bdev == NULL) { 145*70320951SEmmanuel Vadot device_printf(dev, "Failed to add USB device\n"); 146*70320951SEmmanuel Vadot xhci_detach(dev); 147*70320951SEmmanuel Vadot return (ENXIO); 148*70320951SEmmanuel Vadot } 149*70320951SEmmanuel Vadot 150*70320951SEmmanuel Vadot device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 151*70320951SEmmanuel Vadot 152*70320951SEmmanuel Vadot sprintf(sc->sc_vendor, XHCI_HC_VENDOR); 153*70320951SEmmanuel Vadot device_set_desc(sc->sc_bus.bdev, XHCI_HC_DEVSTR); 154*70320951SEmmanuel Vadot 155*70320951SEmmanuel Vadot err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 156*70320951SEmmanuel Vadot NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); 157*70320951SEmmanuel Vadot if (err != 0) { 158*70320951SEmmanuel Vadot device_printf(dev, "Failed to setup error IRQ, %d\n", err); 159*70320951SEmmanuel Vadot sc->sc_intr_hdl = NULL; 160*70320951SEmmanuel Vadot xhci_detach(dev); 161*70320951SEmmanuel Vadot return (err); 162*70320951SEmmanuel Vadot } 163*70320951SEmmanuel Vadot 164*70320951SEmmanuel Vadot err = xhci_init(sc, dev, IS_DMA_32B); 165*70320951SEmmanuel Vadot if (err != 0) { 166*70320951SEmmanuel Vadot device_printf(dev, "Failed to init XHCI, with error %d\n", err); 167*70320951SEmmanuel Vadot xhci_detach(dev); 168*70320951SEmmanuel Vadot return (ENXIO); 169*70320951SEmmanuel Vadot } 170*70320951SEmmanuel Vadot 171*70320951SEmmanuel Vadot err = xhci_start_controller(sc); 172*70320951SEmmanuel Vadot if (err != 0) { 173*70320951SEmmanuel Vadot device_printf(dev, "Failed to start XHCI controller, with error %d\n", err); 174*70320951SEmmanuel Vadot xhci_detach(dev); 175*70320951SEmmanuel Vadot return (ENXIO); 176*70320951SEmmanuel Vadot } 177*70320951SEmmanuel Vadot 178*70320951SEmmanuel Vadot err = device_probe_and_attach(sc->sc_bus.bdev); 179*70320951SEmmanuel Vadot if (err != 0) { 180*70320951SEmmanuel Vadot device_printf(dev, "Failed to initialize USB, with error %d\n", err); 181*70320951SEmmanuel Vadot xhci_detach(dev); 182*70320951SEmmanuel Vadot return (ENXIO); 183*70320951SEmmanuel Vadot } 184*70320951SEmmanuel Vadot 185*70320951SEmmanuel Vadot return (0); 186*70320951SEmmanuel Vadot } 187*70320951SEmmanuel Vadot 188*70320951SEmmanuel Vadot static int 189*70320951SEmmanuel Vadot xhci_detach(device_t dev) 190*70320951SEmmanuel Vadot { 191*70320951SEmmanuel Vadot struct xhci_softc *sc = device_get_softc(dev); 192*70320951SEmmanuel Vadot int err; 193*70320951SEmmanuel Vadot 194*70320951SEmmanuel Vadot /* during module unload there are lots of children leftover */ 195*70320951SEmmanuel Vadot device_delete_children(dev); 196*70320951SEmmanuel Vadot 197*70320951SEmmanuel Vadot if (sc->sc_irq_res != NULL && sc->sc_intr_hdl != NULL) { 198*70320951SEmmanuel Vadot err = bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl); 199*70320951SEmmanuel Vadot if (err != 0) 200*70320951SEmmanuel Vadot device_printf(dev, "Could not tear down irq, %d\n", 201*70320951SEmmanuel Vadot err); 202*70320951SEmmanuel Vadot sc->sc_intr_hdl = NULL; 203*70320951SEmmanuel Vadot } 204*70320951SEmmanuel Vadot 205*70320951SEmmanuel Vadot if (sc->sc_irq_res != NULL) { 206*70320951SEmmanuel Vadot bus_release_resource(dev, SYS_RES_IRQ, 207*70320951SEmmanuel Vadot rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); 208*70320951SEmmanuel Vadot sc->sc_irq_res = NULL; 209*70320951SEmmanuel Vadot } 210*70320951SEmmanuel Vadot 211*70320951SEmmanuel Vadot if (sc->sc_io_res != NULL) { 212*70320951SEmmanuel Vadot bus_release_resource(dev, SYS_RES_MEMORY, 213*70320951SEmmanuel Vadot rman_get_rid(sc->sc_io_res), sc->sc_io_res); 214*70320951SEmmanuel Vadot sc->sc_io_res = NULL; 215*70320951SEmmanuel Vadot } 216*70320951SEmmanuel Vadot 217*70320951SEmmanuel Vadot xhci_uninit(sc); 218*70320951SEmmanuel Vadot 219*70320951SEmmanuel Vadot return (0); 220*70320951SEmmanuel Vadot } 221*70320951SEmmanuel Vadot 222*70320951SEmmanuel Vadot static device_method_t xhci_methods[] = { 223*70320951SEmmanuel Vadot /* Device interface */ 224*70320951SEmmanuel Vadot DEVMETHOD(device_probe, xhci_probe), 225*70320951SEmmanuel Vadot DEVMETHOD(device_attach, xhci_attach), 226*70320951SEmmanuel Vadot DEVMETHOD(device_detach, xhci_detach), 227*70320951SEmmanuel Vadot DEVMETHOD(device_suspend, bus_generic_suspend), 228*70320951SEmmanuel Vadot DEVMETHOD(device_resume, bus_generic_resume), 229*70320951SEmmanuel Vadot DEVMETHOD(device_shutdown, bus_generic_shutdown), 230*70320951SEmmanuel Vadot 231*70320951SEmmanuel Vadot DEVMETHOD_END 232*70320951SEmmanuel Vadot }; 233*70320951SEmmanuel Vadot 234*70320951SEmmanuel Vadot static driver_t xhci_driver = { 235*70320951SEmmanuel Vadot "xhci", 236*70320951SEmmanuel Vadot xhci_methods, 237*70320951SEmmanuel Vadot sizeof(struct xhci_softc), 238*70320951SEmmanuel Vadot }; 239*70320951SEmmanuel Vadot 240*70320951SEmmanuel Vadot static devclass_t xhci_devclass; 241*70320951SEmmanuel Vadot 242*70320951SEmmanuel Vadot DRIVER_MODULE(xhci, simplebus, xhci_driver, xhci_devclass, 0, 0); 243*70320951SEmmanuel Vadot MODULE_DEPEND(xhci, usb, 1, 1, 1); 244