1210312Sjmallett#include <sys/cdefs.h> 2210312Sjmallett__FBSDID("$FreeBSD$"); 3210312Sjmallett 4210312Sjmallett/*- 5210312Sjmallett * Copyright (c) 2007-2008 Hans Petter Selasky. All rights reserved. 6210312Sjmallett * 7210312Sjmallett * Redistribution and use in source and binary forms, with or without 8210312Sjmallett * modification, are permitted provided that the following conditions 9210312Sjmallett * are met: 10210312Sjmallett * 1. Redistributions of source code must retain the above copyright 11210312Sjmallett * notice, this list of conditions and the following disclaimer. 12210312Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 13210312Sjmallett * notice, this list of conditions and the following disclaimer in the 14210312Sjmallett * documentation and/or other materials provided with the distribution. 15210312Sjmallett * 16210312Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17210312Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18210312Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19210312Sjmallett * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20210312Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21210312Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22210312Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23210312Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24210312Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25210312Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26210312Sjmallett * SUCH DAMAGE. 27210312Sjmallett */ 28210312Sjmallett 29210312Sjmallett#include <sys/stdint.h> 30210312Sjmallett#include <sys/stddef.h> 31210312Sjmallett#include <sys/param.h> 32210312Sjmallett#include <sys/queue.h> 33210312Sjmallett#include <sys/types.h> 34210312Sjmallett#include <sys/systm.h> 35210312Sjmallett#include <sys/kernel.h> 36210312Sjmallett#include <sys/bus.h> 37210312Sjmallett#include <sys/module.h> 38210312Sjmallett#include <sys/lock.h> 39210312Sjmallett#include <sys/mutex.h> 40210312Sjmallett#include <sys/condvar.h> 41210312Sjmallett#include <sys/sysctl.h> 42210312Sjmallett#include <sys/sx.h> 43210312Sjmallett#include <sys/unistd.h> 44210312Sjmallett#include <sys/callout.h> 45210312Sjmallett#include <sys/malloc.h> 46210312Sjmallett#include <sys/priv.h> 47210312Sjmallett#include <sys/rman.h> 48210312Sjmallett 49210312Sjmallett#include <dev/usb/usb.h> 50210312Sjmallett#include <dev/usb/usbdi.h> 51210312Sjmallett 52210312Sjmallett#include <dev/usb/usb_core.h> 53210312Sjmallett#include <dev/usb/usb_busdma.h> 54210312Sjmallett#include <dev/usb/usb_process.h> 55210312Sjmallett#include <dev/usb/usb_util.h> 56210312Sjmallett 57210312Sjmallett#include <dev/usb/usb_controller.h> 58210312Sjmallett#include <dev/usb/usb_bus.h> 59210312Sjmallett 60210312Sjmallett#include <contrib/octeon-sdk/cvmx.h> 61210312Sjmallett#include <contrib/octeon-sdk/cvmx-interrupt.h> 62210312Sjmallett#include <contrib/octeon-sdk/cvmx-usb.h> 63210312Sjmallett 64210312Sjmallett#include <mips/cavium/usb/octusb.h> 65210312Sjmallett 66210312Sjmallett#define MEM_RID 0 67210312Sjmallett 68210312Sjmallettstatic device_identify_t octusb_octeon_identify; 69210312Sjmallettstatic device_probe_t octusb_octeon_probe; 70210312Sjmallettstatic device_attach_t octusb_octeon_attach; 71210312Sjmallettstatic device_detach_t octusb_octeon_detach; 72210312Sjmallett 73210312Sjmallettstruct octusb_octeon_softc { 74210312Sjmallett struct octusb_softc sc_dci; /* must be first */ 75210312Sjmallett}; 76210312Sjmallett 77210312Sjmallettstatic void 78210312Sjmallettoctusb_octeon_identify(driver_t *drv, device_t parent) 79210312Sjmallett{ 80210312Sjmallett if (octeon_has_feature(OCTEON_FEATURE_USB)) 81210312Sjmallett BUS_ADD_CHILD(parent, 0, "octusb", 0); 82210312Sjmallett} 83210312Sjmallett 84210312Sjmallettstatic int 85210312Sjmallettoctusb_octeon_probe(device_t dev) 86210312Sjmallett{ 87210312Sjmallett device_set_desc(dev, "Cavium Octeon USB controller"); 88210312Sjmallett return (0); 89210312Sjmallett} 90210312Sjmallett 91210312Sjmallettstatic int 92210312Sjmallettoctusb_octeon_attach(device_t dev) 93210312Sjmallett{ 94210312Sjmallett struct octusb_octeon_softc *sc = device_get_softc(dev); 95210312Sjmallett int err; 96210312Sjmallett int rid; 97210312Sjmallett 98210312Sjmallett /* setup controller interface softc */ 99210312Sjmallett 100210312Sjmallett /* initialise some bus fields */ 101210312Sjmallett sc->sc_dci.sc_bus.parent = dev; 102210312Sjmallett sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices; 103210312Sjmallett sc->sc_dci.sc_bus.devices_max = OCTUSB_MAX_DEVICES; 104210312Sjmallett 105210312Sjmallett /* get all DMA memory */ 106210312Sjmallett if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus, 107210312Sjmallett USB_GET_DMA_TAG(dev), NULL)) { 108210312Sjmallett return (ENOMEM); 109210312Sjmallett } 110210312Sjmallett rid = 0; 111210312Sjmallett sc->sc_dci.sc_irq_res = 112210312Sjmallett bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 113210312Sjmallett CVMX_IRQ_USB, CVMX_IRQ_USB, 1, RF_ACTIVE); 114210312Sjmallett if (!(sc->sc_dci.sc_irq_res)) { 115210312Sjmallett goto error; 116210312Sjmallett } 117210312Sjmallett 118210312Sjmallett sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); 119210312Sjmallett if (!(sc->sc_dci.sc_bus.bdev)) { 120210312Sjmallett goto error; 121210312Sjmallett } 122210312Sjmallett device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); 123210312Sjmallett 124210312Sjmallett#if (__FreeBSD_version >= 700031) 125210312Sjmallett err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 126210312Sjmallett NULL, (driver_intr_t *)octusb_interrupt, sc, &sc->sc_dci.sc_intr_hdl); 127210312Sjmallett#else 128210312Sjmallett err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 129210312Sjmallett (driver_intr_t *)octusb_interrupt, sc, &sc->sc_dci.sc_intr_hdl); 130210312Sjmallett#endif 131210312Sjmallett if (err) { 132210312Sjmallett sc->sc_dci.sc_intr_hdl = NULL; 133210312Sjmallett goto error; 134210312Sjmallett } 135210312Sjmallett err = octusb_init(&sc->sc_dci); 136210312Sjmallett if (!err) { 137210312Sjmallett err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); 138210312Sjmallett } 139210312Sjmallett if (err) { 140210312Sjmallett goto error; 141210312Sjmallett } 142210312Sjmallett return (0); 143210312Sjmallett 144210312Sjmalletterror: 145210312Sjmallett octusb_octeon_detach(dev); 146210312Sjmallett return (ENXIO); 147210312Sjmallett} 148210312Sjmallett 149210312Sjmallettstatic int 150210312Sjmallettoctusb_octeon_detach(device_t dev) 151210312Sjmallett{ 152210312Sjmallett struct octusb_octeon_softc *sc = device_get_softc(dev); 153210312Sjmallett device_t bdev; 154210312Sjmallett int err; 155210312Sjmallett 156210312Sjmallett if (sc->sc_dci.sc_bus.bdev) { 157210312Sjmallett bdev = sc->sc_dci.sc_bus.bdev; 158210312Sjmallett device_detach(bdev); 159210312Sjmallett device_delete_child(dev, bdev); 160210312Sjmallett } 161210312Sjmallett /* during module unload there are lots of children leftover */ 162229118Shselasky device_delete_children(dev); 163210312Sjmallett 164210312Sjmallett if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) { 165210312Sjmallett /* 166210312Sjmallett * only call octusb_octeon_uninit() after octusb_octeon_init() 167210312Sjmallett */ 168210312Sjmallett octusb_uninit(&sc->sc_dci); 169210312Sjmallett 170210312Sjmallett err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res, 171210312Sjmallett sc->sc_dci.sc_intr_hdl); 172210312Sjmallett sc->sc_dci.sc_intr_hdl = NULL; 173210312Sjmallett } 174210312Sjmallett if (sc->sc_dci.sc_irq_res) { 175210312Sjmallett bus_release_resource(dev, SYS_RES_IRQ, 0, 176210312Sjmallett sc->sc_dci.sc_irq_res); 177210312Sjmallett sc->sc_dci.sc_irq_res = NULL; 178210312Sjmallett } 179210312Sjmallett usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); 180210312Sjmallett 181210312Sjmallett return (0); 182210312Sjmallett} 183210312Sjmallett 184210312Sjmallettstatic device_method_t octusb_octeon_methods[] = { 185210312Sjmallett /* Device interface */ 186210312Sjmallett DEVMETHOD(device_identify, octusb_octeon_identify), 187210312Sjmallett DEVMETHOD(device_probe, octusb_octeon_probe), 188210312Sjmallett DEVMETHOD(device_attach, octusb_octeon_attach), 189210312Sjmallett DEVMETHOD(device_detach, octusb_octeon_detach), 190229096Shselasky DEVMETHOD(device_resume, bus_generic_resume), 191229096Shselasky DEVMETHOD(device_suspend, bus_generic_suspend), 192229096Shselasky DEVMETHOD(device_shutdown, bus_generic_shutdown), 193210312Sjmallett 194229093Shselasky DEVMETHOD_END 195210312Sjmallett}; 196210312Sjmallett 197210312Sjmallettstatic driver_t octusb_octeon_driver = { 198229096Shselasky .name = "octusb", 199229096Shselasky .methods = octusb_octeon_methods, 200229096Shselasky .size = sizeof(struct octusb_octeon_softc), 201210312Sjmallett}; 202210312Sjmallett 203210312Sjmallettstatic devclass_t octusb_octeon_devclass; 204210312Sjmallett 205210312SjmallettDRIVER_MODULE(octusb, ciu, octusb_octeon_driver, octusb_octeon_devclass, 0, 0); 206