xhci_mv.c revision 296827
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: head/sys/dev/usb/controller/xhci_mv.c 296827 2016-03-14 07:24:08Z wma $"); 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#define XHCI_HC_DEVSTR "Marvell Integrated USB 3.0 controller" 68#define XHCI_HC_VENDOR "Marvell" 69 70#define IS_DMA_32B 1 71 72static device_attach_t xhci_attach; 73static device_detach_t xhci_detach; 74 75static struct ofw_compat_data compat_data[] = { 76 {"marvell,armada-380-xhci", true}, 77 {NULL, false} 78}; 79 80static int 81xhci_probe(device_t dev) 82{ 83 84 if (!ofw_bus_status_okay(dev)) 85 return (ENXIO); 86 87 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 88 return (ENXIO); 89 90 device_set_desc(dev, XHCI_HC_DEVSTR); 91 92 return (BUS_PROBE_DEFAULT); 93} 94 95static int 96xhci_attach(device_t dev) 97{ 98 struct xhci_softc *sc = device_get_softc(dev); 99 int err = 0, rid = 0; 100 101 sc->sc_bus.parent = dev; 102 sc->sc_bus.devices = sc->sc_devices; 103 sc->sc_bus.devices_max = XHCI_MAX_DEVICES; 104 105 sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 106 RF_ACTIVE); 107 if (sc->sc_io_res == NULL) { 108 device_printf(dev, "Failed to map memory\n"); 109 xhci_detach(dev); 110 return (ENXIO); 111 } 112 113 sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 114 sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 115 sc->sc_io_size = rman_get_size(sc->sc_io_res); 116 117 sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 118 RF_SHAREABLE | RF_ACTIVE); 119 if (sc->sc_irq_res == NULL) { 120 device_printf(dev, "Failed to allocate IRQ\n"); 121 xhci_detach(dev); 122 return (ENXIO); 123 } 124 125 sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); 126 if (sc->sc_bus.bdev == NULL) { 127 device_printf(dev, "Failed to add USB device\n"); 128 xhci_detach(dev); 129 return (ENXIO); 130 } 131 132 device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 133 134 sprintf(sc->sc_vendor, XHCI_HC_VENDOR); 135 device_set_desc(sc->sc_bus.bdev, XHCI_HC_DEVSTR); 136 137 err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 138 NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); 139 if (err != 0) { 140 device_printf(dev, "Failed to setup error IRQ, %d\n", err); 141 sc->sc_intr_hdl = NULL; 142 xhci_detach(dev); 143 return (err); 144 } 145 146 err = xhci_init(sc, dev, IS_DMA_32B); 147 if (err != 0) { 148 device_printf(dev, "Failed to init XHCI, with error %d\n", err); 149 xhci_detach(dev); 150 return (ENXIO); 151 } 152 153 err = xhci_start_controller(sc); 154 if (err != 0) { 155 device_printf(dev, "Failed to start XHCI controller, with error %d\n", err); 156 xhci_detach(dev); 157 return (ENXIO); 158 } 159 160 err = device_probe_and_attach(sc->sc_bus.bdev); 161 if (err != 0) { 162 device_printf(dev, "Failed to initialize USB, with error %d\n", err); 163 xhci_detach(dev); 164 return (ENXIO); 165 } 166 167 return (0); 168} 169 170static int 171xhci_detach(device_t dev) 172{ 173 struct xhci_softc *sc = device_get_softc(dev); 174 device_t bdev; 175 int err; 176 177 if (sc->sc_bus.bdev != NULL) { 178 bdev = sc->sc_bus.bdev; 179 device_detach(bdev); 180 device_delete_child(dev, bdev); 181 } 182 183 /* during module unload there are lots of children leftover */ 184 device_delete_children(dev); 185 186 if (sc->sc_irq_res != NULL && sc->sc_intr_hdl != NULL) { 187 err = bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl); 188 if (err != 0) 189 device_printf(dev, "Could not tear down irq, %d\n", 190 err); 191 sc->sc_intr_hdl = NULL; 192 } 193 194 if (sc->sc_irq_res != NULL) { 195 bus_release_resource(dev, SYS_RES_IRQ, 196 rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); 197 sc->sc_irq_res = NULL; 198 } 199 200 if (sc->sc_io_res != NULL) { 201 bus_release_resource(dev, SYS_RES_MEMORY, 202 rman_get_rid(sc->sc_io_res), sc->sc_io_res); 203 sc->sc_io_res = NULL; 204 } 205 206 xhci_uninit(sc); 207 208 return (0); 209} 210 211static device_method_t xhci_methods[] = { 212 /* Device interface */ 213 DEVMETHOD(device_probe, xhci_probe), 214 DEVMETHOD(device_attach, xhci_attach), 215 DEVMETHOD(device_detach, xhci_detach), 216 DEVMETHOD(device_suspend, bus_generic_suspend), 217 DEVMETHOD(device_resume, bus_generic_resume), 218 DEVMETHOD(device_shutdown, bus_generic_shutdown), 219 220 DEVMETHOD_END 221}; 222 223static driver_t xhci_driver = { 224 "xhci", 225 xhci_methods, 226 sizeof(struct xhci_softc), 227}; 228 229static devclass_t xhci_devclass; 230 231DRIVER_MODULE(xhci, simplebus, xhci_driver, xhci_devclass, 0, 0); 232MODULE_DEPEND(xhci, usb, 1, 1, 1); 233