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