octusb_octeon.c revision 210312
1210312Sjmallett#include <sys/cdefs.h> 2210312Sjmallett__FBSDID("$FreeBSD: head/sys/mips/cavium/usb/octusb_octeon.c 210312 2010-07-20 19:32:25Z jmallett $"); 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/linker_set.h> 38210312Sjmallett#include <sys/module.h> 39210312Sjmallett#include <sys/lock.h> 40210312Sjmallett#include <sys/mutex.h> 41210312Sjmallett#include <sys/condvar.h> 42210312Sjmallett#include <sys/sysctl.h> 43210312Sjmallett#include <sys/sx.h> 44210312Sjmallett#include <sys/unistd.h> 45210312Sjmallett#include <sys/callout.h> 46210312Sjmallett#include <sys/malloc.h> 47210312Sjmallett#include <sys/priv.h> 48210312Sjmallett#include <sys/rman.h> 49210312Sjmallett 50210312Sjmallett#include <dev/usb/usb.h> 51210312Sjmallett#include <dev/usb/usbdi.h> 52210312Sjmallett 53210312Sjmallett#include <dev/usb/usb_core.h> 54210312Sjmallett#include <dev/usb/usb_busdma.h> 55210312Sjmallett#include <dev/usb/usb_process.h> 56210312Sjmallett#include <dev/usb/usb_util.h> 57210312Sjmallett 58210312Sjmallett#include <dev/usb/usb_controller.h> 59210312Sjmallett#include <dev/usb/usb_bus.h> 60210312Sjmallett 61210312Sjmallett#include <contrib/octeon-sdk/cvmx.h> 62210312Sjmallett#include <contrib/octeon-sdk/cvmx-interrupt.h> 63210312Sjmallett#include <contrib/octeon-sdk/cvmx-usb.h> 64210312Sjmallett 65210312Sjmallett#include <mips/cavium/usb/octusb.h> 66210312Sjmallett 67210312Sjmallett#define MEM_RID 0 68210312Sjmallett 69210312Sjmallettstatic device_identify_t octusb_octeon_identify; 70210312Sjmallettstatic device_probe_t octusb_octeon_probe; 71210312Sjmallettstatic device_attach_t octusb_octeon_attach; 72210312Sjmallettstatic device_detach_t octusb_octeon_detach; 73210312Sjmallettstatic device_shutdown_t octusb_octeon_shutdown; 74210312Sjmallett 75210312Sjmallettstruct octusb_octeon_softc { 76210312Sjmallett struct octusb_softc sc_dci; /* must be first */ 77210312Sjmallett}; 78210312Sjmallett 79210312Sjmallettstatic void 80210312Sjmallettoctusb_octeon_identify(driver_t *drv, device_t parent) 81210312Sjmallett{ 82210312Sjmallett if (octeon_has_feature(OCTEON_FEATURE_USB)) 83210312Sjmallett BUS_ADD_CHILD(parent, 0, "octusb", 0); 84210312Sjmallett} 85210312Sjmallett 86210312Sjmallettstatic int 87210312Sjmallettoctusb_octeon_probe(device_t dev) 88210312Sjmallett{ 89210312Sjmallett device_set_desc(dev, "Cavium Octeon USB controller"); 90210312Sjmallett return (0); 91210312Sjmallett} 92210312Sjmallett 93210312Sjmallettstatic int 94210312Sjmallettoctusb_octeon_attach(device_t dev) 95210312Sjmallett{ 96210312Sjmallett struct octusb_octeon_softc *sc = device_get_softc(dev); 97210312Sjmallett int err; 98210312Sjmallett int rid; 99210312Sjmallett 100210312Sjmallett /* setup controller interface softc */ 101210312Sjmallett 102210312Sjmallett /* initialise some bus fields */ 103210312Sjmallett sc->sc_dci.sc_bus.parent = dev; 104210312Sjmallett sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices; 105210312Sjmallett sc->sc_dci.sc_bus.devices_max = OCTUSB_MAX_DEVICES; 106210312Sjmallett 107210312Sjmallett /* get all DMA memory */ 108210312Sjmallett if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus, 109210312Sjmallett USB_GET_DMA_TAG(dev), NULL)) { 110210312Sjmallett return (ENOMEM); 111210312Sjmallett } 112210312Sjmallett rid = 0; 113210312Sjmallett sc->sc_dci.sc_irq_res = 114210312Sjmallett bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 115210312Sjmallett CVMX_IRQ_USB, CVMX_IRQ_USB, 1, RF_ACTIVE); 116210312Sjmallett if (!(sc->sc_dci.sc_irq_res)) { 117210312Sjmallett goto error; 118210312Sjmallett } 119210312Sjmallett 120210312Sjmallett sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); 121210312Sjmallett if (!(sc->sc_dci.sc_bus.bdev)) { 122210312Sjmallett goto error; 123210312Sjmallett } 124210312Sjmallett device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); 125210312Sjmallett 126210312Sjmallett#if (__FreeBSD_version >= 700031) 127210312Sjmallett err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 128210312Sjmallett NULL, (driver_intr_t *)octusb_interrupt, sc, &sc->sc_dci.sc_intr_hdl); 129210312Sjmallett#else 130210312Sjmallett err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 131210312Sjmallett (driver_intr_t *)octusb_interrupt, sc, &sc->sc_dci.sc_intr_hdl); 132210312Sjmallett#endif 133210312Sjmallett if (err) { 134210312Sjmallett sc->sc_dci.sc_intr_hdl = NULL; 135210312Sjmallett goto error; 136210312Sjmallett } 137210312Sjmallett err = octusb_init(&sc->sc_dci); 138210312Sjmallett if (!err) { 139210312Sjmallett err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); 140210312Sjmallett } 141210312Sjmallett if (err) { 142210312Sjmallett goto error; 143210312Sjmallett } 144210312Sjmallett return (0); 145210312Sjmallett 146210312Sjmalletterror: 147210312Sjmallett octusb_octeon_detach(dev); 148210312Sjmallett return (ENXIO); 149210312Sjmallett} 150210312Sjmallett 151210312Sjmallettstatic int 152210312Sjmallettoctusb_octeon_detach(device_t dev) 153210312Sjmallett{ 154210312Sjmallett struct octusb_octeon_softc *sc = device_get_softc(dev); 155210312Sjmallett device_t bdev; 156210312Sjmallett int err; 157210312Sjmallett 158210312Sjmallett if (sc->sc_dci.sc_bus.bdev) { 159210312Sjmallett bdev = sc->sc_dci.sc_bus.bdev; 160210312Sjmallett device_detach(bdev); 161210312Sjmallett device_delete_child(dev, bdev); 162210312Sjmallett } 163210312Sjmallett /* during module unload there are lots of children leftover */ 164210312Sjmallett device_delete_all_children(dev); 165210312Sjmallett 166210312Sjmallett if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) { 167210312Sjmallett /* 168210312Sjmallett * only call octusb_octeon_uninit() after octusb_octeon_init() 169210312Sjmallett */ 170210312Sjmallett octusb_uninit(&sc->sc_dci); 171210312Sjmallett 172210312Sjmallett err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res, 173210312Sjmallett sc->sc_dci.sc_intr_hdl); 174210312Sjmallett sc->sc_dci.sc_intr_hdl = NULL; 175210312Sjmallett } 176210312Sjmallett if (sc->sc_dci.sc_irq_res) { 177210312Sjmallett bus_release_resource(dev, SYS_RES_IRQ, 0, 178210312Sjmallett sc->sc_dci.sc_irq_res); 179210312Sjmallett sc->sc_dci.sc_irq_res = NULL; 180210312Sjmallett } 181210312Sjmallett usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); 182210312Sjmallett 183210312Sjmallett return (0); 184210312Sjmallett} 185210312Sjmallett 186210312Sjmallettstatic int 187210312Sjmallettoctusb_octeon_shutdown(device_t dev) 188210312Sjmallett{ 189210312Sjmallett struct octusb_octeon_softc *sc = device_get_softc(dev); 190210312Sjmallett int err; 191210312Sjmallett 192210312Sjmallett err = bus_generic_shutdown(dev); 193210312Sjmallett if (err) 194210312Sjmallett return (err); 195210312Sjmallett 196210312Sjmallett octusb_uninit(&sc->sc_dci); 197210312Sjmallett 198210312Sjmallett return (0); 199210312Sjmallett} 200210312Sjmallett 201210312Sjmallettstatic device_method_t octusb_octeon_methods[] = { 202210312Sjmallett /* Device interface */ 203210312Sjmallett DEVMETHOD(device_identify, octusb_octeon_identify), 204210312Sjmallett DEVMETHOD(device_probe, octusb_octeon_probe), 205210312Sjmallett DEVMETHOD(device_attach, octusb_octeon_attach), 206210312Sjmallett DEVMETHOD(device_detach, octusb_octeon_detach), 207210312Sjmallett DEVMETHOD(device_shutdown, octusb_octeon_shutdown), 208210312Sjmallett 209210312Sjmallett /* Bus interface */ 210210312Sjmallett DEVMETHOD(bus_print_child, bus_generic_print_child), 211210312Sjmallett 212210312Sjmallett {0, 0} 213210312Sjmallett}; 214210312Sjmallett 215210312Sjmallettstatic driver_t octusb_octeon_driver = { 216210312Sjmallett "octusb", 217210312Sjmallett octusb_octeon_methods, 218210312Sjmallett sizeof(struct octusb_octeon_softc), 219210312Sjmallett}; 220210312Sjmallett 221210312Sjmallettstatic devclass_t octusb_octeon_devclass; 222210312Sjmallett 223210312SjmallettDRIVER_MODULE(octusb, ciu, octusb_octeon_driver, octusb_octeon_devclass, 0, 0); 224