ar71xx_ohci.c revision 330897
1273929Sjmmv/*- 2240116Smarcel * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3240116Smarcel * 4240116Smarcel * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 5240116Smarcel * All rights reserved. 6240116Smarcel * 7240116Smarcel * Redistribution and use in source and binary forms, with or without 8240116Smarcel * modification, are permitted provided that the following conditions 9240116Smarcel * are met: 10240116Smarcel * 1. Redistributions of source code must retain the above copyright 11240116Smarcel * notice unmodified, this list of conditions, and the following 12240116Smarcel * disclaimer. 13240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright 14240116Smarcel * notice, this list of conditions and the following disclaimer in the 15240116Smarcel * documentation and/or other materials provided with the distribution. 16240116Smarcel * 17240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18240116Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19240116Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20240116Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21240116Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23240116Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24273929Sjmmv * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25240116Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26273929Sjmmv * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27273929Sjmmv * SUCH DAMAGE. 28240116Smarcel */ 29240116Smarcel 30240116Smarcel#include <sys/cdefs.h> 31273929Sjmmv__FBSDID("$FreeBSD: stable/11/sys/mips/atheros/ar71xx_ohci.c 330897 2018-03-14 03:19:51Z eadler $"); 32240116Smarcel 33240116Smarcel#include <sys/param.h> 34240116Smarcel#include <sys/systm.h> 35240116Smarcel#include <sys/bus.h> 36240116Smarcel#include <sys/rman.h> 37240116Smarcel#include <sys/condvar.h> 38240116Smarcel#include <sys/kernel.h> 39240116Smarcel#include <sys/module.h> 40240116Smarcel 41240116Smarcel#include <dev/usb/usb.h> 42240116Smarcel#include <dev/usb/usbdi.h> 43240116Smarcel 44240116Smarcel#include <dev/usb/usb_core.h> 45240116Smarcel#include <dev/usb/usb_busdma.h> 46240116Smarcel#include <dev/usb/usb_process.h> 47240116Smarcel#include <dev/usb/usb_util.h> 48240116Smarcel 49240116Smarcel#include <dev/usb/usb_controller.h> 50240116Smarcel#include <dev/usb/usb_bus.h> 51240116Smarcel#include <dev/usb/controller/ohci.h> 52240116Smarcel#include <dev/usb/controller/ohcireg.h> 53240116Smarcel 54240116Smarcel#include <mips/atheros/ar71xxreg.h> /* for stuff in ar71xx_cpudef.h */ 55240116Smarcel#include <mips/atheros/ar71xx_cpudef.h> 56240116Smarcel 57240116Smarcelstatic int ar71xx_ohci_attach(device_t dev); 58240116Smarcelstatic int ar71xx_ohci_detach(device_t dev); 59240116Smarcelstatic int ar71xx_ohci_probe(device_t dev); 60240116Smarcel 61240116Smarcelstruct ar71xx_ohci_softc 62240116Smarcel{ 63240116Smarcel struct ohci_softc sc_ohci; 64240116Smarcel}; 65240116Smarcel 66240116Smarcelstatic int 67240116Smarcelar71xx_ohci_probe(device_t dev) 68240116Smarcel{ 69240116Smarcel device_set_desc(dev, "AR71XX integrated OHCI controller"); 70240116Smarcel return (BUS_PROBE_DEFAULT); 71240116Smarcel} 72240116Smarcel 73240116Smarcelstatic void 74240116Smarcelar71xx_ohci_intr(void *arg) 75240116Smarcel{ 76240116Smarcel 77240116Smarcel /* XXX TODO: should really see if this was our interrupt.. */ 78240116Smarcel ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_USB); 79240116Smarcel ohci_interrupt(arg); 80240116Smarcel} 81240116Smarcel 82240116Smarcel 83240116Smarcelstatic int 84240116Smarcelar71xx_ohci_attach(device_t dev) 85240116Smarcel{ 86240116Smarcel struct ar71xx_ohci_softc *sc = device_get_softc(dev); 87240116Smarcel int err; 88240116Smarcel int rid; 89240116Smarcel 90240116Smarcel /* initialise some bus fields */ 91240116Smarcel sc->sc_ohci.sc_bus.parent = dev; 92240116Smarcel sc->sc_ohci.sc_bus.devices = sc->sc_ohci.sc_devices; 93240116Smarcel sc->sc_ohci.sc_bus.devices_max = OHCI_MAX_DEVICES; 94240116Smarcel sc->sc_ohci.sc_bus.dma_bits = 32; 95240116Smarcel 96240116Smarcel /* get all DMA memory */ 97240116Smarcel if (usb_bus_mem_alloc_all(&sc->sc_ohci.sc_bus, 98240116Smarcel USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) { 99240116Smarcel return (ENOMEM); 100240116Smarcel } 101240116Smarcel 102240116Smarcel sc->sc_ohci.sc_dev = dev; 103240116Smarcel 104240116Smarcel rid = 0; 105240116Smarcel sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 106240116Smarcel RF_ACTIVE); 107240116Smarcel if (sc->sc_ohci.sc_io_res == NULL) { 108240116Smarcel err = ENOMEM; 109240116Smarcel goto error; 110240116Smarcel } 111240116Smarcel sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res); 112240116Smarcel sc->sc_ohci.sc_io_hdl = rman_get_bushandle(sc->sc_ohci.sc_io_res); 113240116Smarcel sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res); 114240116Smarcel 115240116Smarcel rid = 0; 116240116Smarcel sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 117240116Smarcel RF_ACTIVE); 118240116Smarcel if (sc->sc_ohci.sc_irq_res == NULL) { 119240116Smarcel err = ENOMEM; 120240116Smarcel goto error; 121240116Smarcel } 122240116Smarcel sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usbus", -1); 123240116Smarcel if (sc->sc_ohci.sc_bus.bdev == NULL) { 124240116Smarcel err = ENOMEM; 125240116Smarcel goto error; 126240116Smarcel } 127240116Smarcel device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus); 128240116Smarcel 129240116Smarcel err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, 130240116Smarcel INTR_TYPE_BIO | INTR_MPSAFE, NULL, 131240116Smarcel ar71xx_ohci_intr, sc, &sc->sc_ohci.sc_intr_hdl); 132240116Smarcel if (err) { 133240116Smarcel err = ENXIO; 134240116Smarcel goto error; 135240116Smarcel } 136240116Smarcel 137240116Smarcel strlcpy(sc->sc_ohci.sc_vendor, "Atheros", sizeof(sc->sc_ohci.sc_vendor)); 138240116Smarcel 139240116Smarcel bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, OHCI_CONTROL, 0); 140240116Smarcel 141240116Smarcel err = ohci_init(&sc->sc_ohci); 142240116Smarcel if (!err) 143240116Smarcel err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev); 144240116Smarcel 145240116Smarcel if (err) 146240116Smarcel goto error; 147240116Smarcel return (0); 148240116Smarcel 149240116Smarcelerror: 150240116Smarcel if (err) { 151240116Smarcel ar71xx_ohci_detach(dev); 152240116Smarcel return (err); 153240116Smarcel } 154240116Smarcel return (err); 155240116Smarcel} 156240116Smarcel 157240116Smarcelstatic int 158240116Smarcelar71xx_ohci_detach(device_t dev) 159240116Smarcel{ 160240116Smarcel struct ar71xx_ohci_softc *sc = device_get_softc(dev); 161240116Smarcel 162240116Smarcel /* during module unload there are lots of children leftover */ 163240116Smarcel device_delete_children(dev); 164240116Smarcel 165240116Smarcel /* 166240116Smarcel * Put the controller into reset, then disable clocks and do 167240116Smarcel * the MI tear down. We have to disable the clocks/hardware 168240116Smarcel * after we do the rest of the teardown. We also disable the 169240116Smarcel * clocks in the opposite order we acquire them, but that 170240116Smarcel * doesn't seem to be absolutely necessary. We free up the 171240116Smarcel * clocks after we disable them, so the system could, in 172240116Smarcel * theory, reuse them. 173240116Smarcel */ 174240116Smarcel bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, 175240116Smarcel OHCI_CONTROL, 0); 176240116Smarcel 177240116Smarcel if (sc->sc_ohci.sc_intr_hdl) { 178240116Smarcel bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, sc->sc_ohci.sc_intr_hdl); 179240116Smarcel sc->sc_ohci.sc_intr_hdl = NULL; 180240116Smarcel } 181240116Smarcel 182240116Smarcel if (sc->sc_ohci.sc_irq_res && sc->sc_ohci.sc_intr_hdl) { 183240116Smarcel /* 184240116Smarcel * only call ohci_detach() after ohci_init() 185240116Smarcel */ 186240116Smarcel ohci_detach(&sc->sc_ohci); 187240116Smarcel 188240116Smarcel bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res); 189240116Smarcel sc->sc_ohci.sc_irq_res = NULL; 190240116Smarcel } 191240116Smarcel if (sc->sc_ohci.sc_io_res) { 192240116Smarcel bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_ohci.sc_io_res); 193240116Smarcel sc->sc_ohci.sc_io_res = NULL; 194240116Smarcel sc->sc_ohci.sc_io_tag = 0; 195240116Smarcel sc->sc_ohci.sc_io_hdl = 0; 196240116Smarcel } 197240116Smarcel usb_bus_mem_free_all(&sc->sc_ohci.sc_bus, &ohci_iterate_hw_softc); 198240116Smarcel 199240116Smarcel return (0); 200240116Smarcel} 201240116Smarcel 202240116Smarcelstatic device_method_t ohci_methods[] = { 203240116Smarcel /* Device interface */ 204240116Smarcel DEVMETHOD(device_probe, ar71xx_ohci_probe), 205240116Smarcel DEVMETHOD(device_attach, ar71xx_ohci_attach), 206240116Smarcel DEVMETHOD(device_detach, ar71xx_ohci_detach), 207240116Smarcel DEVMETHOD(device_suspend, bus_generic_suspend), 208240116Smarcel DEVMETHOD(device_resume, bus_generic_resume), 209240116Smarcel DEVMETHOD(device_shutdown, bus_generic_shutdown), 210240116Smarcel 211240116Smarcel DEVMETHOD_END 212240116Smarcel}; 213240116Smarcel 214240116Smarcelstatic driver_t ohci_driver = { 215240116Smarcel .name = "ohci", 216240116Smarcel .methods = ohci_methods, 217240116Smarcel .size = sizeof(struct ar71xx_ohci_softc), 218240116Smarcel}; 219240116Smarcel 220240116Smarcelstatic devclass_t ohci_devclass; 221240116Smarcel 222240116SmarcelDRIVER_MODULE(ohci, apb, ohci_driver, ohci_devclass, 0, 0); 223240116Smarcel