octusb_octeon.c revision 228483
1210312Sjmallett#include <sys/cdefs.h> 2210312Sjmallett__FBSDID("$FreeBSD: head/sys/mips/cavium/usb/octusb_octeon.c 228483 2011-12-14 00:28:54Z hselasky $"); 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; 72210312Sjmallettstatic device_shutdown_t octusb_octeon_shutdown; 73210312Sjmallett 74210312Sjmallettstruct octusb_octeon_softc { 75210312Sjmallett struct octusb_softc sc_dci; /* must be first */ 76210312Sjmallett}; 77210312Sjmallett 78210312Sjmallettstatic void 79210312Sjmallettoctusb_octeon_identify(driver_t *drv, device_t parent) 80210312Sjmallett{ 81210312Sjmallett if (octeon_has_feature(OCTEON_FEATURE_USB)) 82210312Sjmallett BUS_ADD_CHILD(parent, 0, "octusb", 0); 83210312Sjmallett} 84210312Sjmallett 85210312Sjmallettstatic int 86210312Sjmallettoctusb_octeon_probe(device_t dev) 87210312Sjmallett{ 88210312Sjmallett device_set_desc(dev, "Cavium Octeon USB controller"); 89210312Sjmallett return (0); 90210312Sjmallett} 91210312Sjmallett 92210312Sjmallettstatic int 93210312Sjmallettoctusb_octeon_attach(device_t dev) 94210312Sjmallett{ 95210312Sjmallett struct octusb_octeon_softc *sc = device_get_softc(dev); 96210312Sjmallett int err; 97210312Sjmallett int rid; 98210312Sjmallett 99210312Sjmallett /* setup controller interface softc */ 100210312Sjmallett 101210312Sjmallett /* initialise some bus fields */ 102210312Sjmallett sc->sc_dci.sc_bus.parent = dev; 103210312Sjmallett sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices; 104210312Sjmallett sc->sc_dci.sc_bus.devices_max = OCTUSB_MAX_DEVICES; 105210312Sjmallett 106210312Sjmallett /* get all DMA memory */ 107210312Sjmallett if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus, 108210312Sjmallett USB_GET_DMA_TAG(dev), NULL)) { 109210312Sjmallett return (ENOMEM); 110210312Sjmallett } 111210312Sjmallett rid = 0; 112210312Sjmallett sc->sc_dci.sc_irq_res = 113210312Sjmallett bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 114210312Sjmallett CVMX_IRQ_USB, CVMX_IRQ_USB, 1, RF_ACTIVE); 115210312Sjmallett if (!(sc->sc_dci.sc_irq_res)) { 116210312Sjmallett goto error; 117210312Sjmallett } 118210312Sjmallett 119210312Sjmallett sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); 120210312Sjmallett if (!(sc->sc_dci.sc_bus.bdev)) { 121210312Sjmallett goto error; 122210312Sjmallett } 123210312Sjmallett device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); 124210312Sjmallett 125210312Sjmallett#if (__FreeBSD_version >= 700031) 126210312Sjmallett err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 127210312Sjmallett NULL, (driver_intr_t *)octusb_interrupt, sc, &sc->sc_dci.sc_intr_hdl); 128210312Sjmallett#else 129210312Sjmallett err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 130210312Sjmallett (driver_intr_t *)octusb_interrupt, sc, &sc->sc_dci.sc_intr_hdl); 131210312Sjmallett#endif 132210312Sjmallett if (err) { 133210312Sjmallett sc->sc_dci.sc_intr_hdl = NULL; 134210312Sjmallett goto error; 135210312Sjmallett } 136210312Sjmallett err = octusb_init(&sc->sc_dci); 137210312Sjmallett if (!err) { 138210312Sjmallett err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); 139210312Sjmallett } 140210312Sjmallett if (err) { 141210312Sjmallett goto error; 142210312Sjmallett } 143210312Sjmallett return (0); 144210312Sjmallett 145210312Sjmalletterror: 146210312Sjmallett octusb_octeon_detach(dev); 147210312Sjmallett return (ENXIO); 148210312Sjmallett} 149210312Sjmallett 150210312Sjmallettstatic int 151210312Sjmallettoctusb_octeon_detach(device_t dev) 152210312Sjmallett{ 153210312Sjmallett struct octusb_octeon_softc *sc = device_get_softc(dev); 154210312Sjmallett device_t bdev; 155210312Sjmallett int err; 156210312Sjmallett 157210312Sjmallett if (sc->sc_dci.sc_bus.bdev) { 158210312Sjmallett bdev = sc->sc_dci.sc_bus.bdev; 159210312Sjmallett device_detach(bdev); 160210312Sjmallett device_delete_child(dev, bdev); 161210312Sjmallett } 162210312Sjmallett /* during module unload there are lots of children leftover */ 163227849Shselasky device_delete_children(dev); 164210312Sjmallett 165210312Sjmallett if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) { 166210312Sjmallett /* 167210312Sjmallett * only call octusb_octeon_uninit() after octusb_octeon_init() 168210312Sjmallett */ 169210312Sjmallett octusb_uninit(&sc->sc_dci); 170210312Sjmallett 171210312Sjmallett err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res, 172210312Sjmallett sc->sc_dci.sc_intr_hdl); 173210312Sjmallett sc->sc_dci.sc_intr_hdl = NULL; 174210312Sjmallett } 175210312Sjmallett if (sc->sc_dci.sc_irq_res) { 176210312Sjmallett bus_release_resource(dev, SYS_RES_IRQ, 0, 177210312Sjmallett sc->sc_dci.sc_irq_res); 178210312Sjmallett sc->sc_dci.sc_irq_res = NULL; 179210312Sjmallett } 180210312Sjmallett usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); 181210312Sjmallett 182210312Sjmallett return (0); 183210312Sjmallett} 184210312Sjmallett 185210312Sjmallettstatic device_method_t octusb_octeon_methods[] = { 186210312Sjmallett /* Device interface */ 187210312Sjmallett DEVMETHOD(device_identify, octusb_octeon_identify), 188210312Sjmallett DEVMETHOD(device_probe, octusb_octeon_probe), 189210312Sjmallett DEVMETHOD(device_attach, octusb_octeon_attach), 190210312Sjmallett DEVMETHOD(device_detach, octusb_octeon_detach), 191228483Shselasky DEVMETHOD(device_resume, bus_generic_resume), 192228483Shselasky DEVMETHOD(device_suspend, bus_generic_suspend), 193228483Shselasky DEVMETHOD(device_shutdown, bus_generic_shutdown), 194210312Sjmallett 195227843Smarius DEVMETHOD_END 196210312Sjmallett}; 197210312Sjmallett 198210312Sjmallettstatic driver_t octusb_octeon_driver = { 199228483Shselasky .name = "octusb", 200228483Shselasky .methods = octusb_octeon_methods, 201228483Shselasky .size = sizeof(struct octusb_octeon_softc), 202210312Sjmallett}; 203210312Sjmallett 204210312Sjmallettstatic devclass_t octusb_octeon_devclass; 205210312Sjmallett 206210312SjmallettDRIVER_MODULE(octusb, ciu, octusb_octeon_driver, octusb_octeon_devclass, 0, 0); 207