ar71xx_ehci.c revision 290910
1275988Sngie/*- 2240116Smarcel * Copyright (c) 2008 Sam Leffler. All rights reserved. 3240116Smarcel * 4240116Smarcel * Redistribution and use in source and binary forms, with or without 5240116Smarcel * modification, are permitted provided that the following conditions 6240116Smarcel * are met: 7240116Smarcel * 1. Redistributions of source code must retain the above copyright 8240116Smarcel * notice, this list of conditions and the following disclaimer. 9240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright 10240116Smarcel * notice, this list of conditions and the following disclaimer in the 11240116Smarcel * documentation and/or other materials provided with the distribution. 12240116Smarcel * 13240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14240116Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15240116Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16240116Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17240116Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18240116Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19240116Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20240116Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21240116Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22240116Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23240116Smarcel */ 24275988Sngie 25240116Smarcel/* 26275988Sngie * AR71XX attachment driver for the USB Enhanced Host Controller. 27275988Sngie */ 28240116Smarcel 29240116Smarcel#include <sys/cdefs.h> 30240116Smarcel__FBSDID("$FreeBSD: head/sys/mips/atheros/ar71xx_ehci.c 290910 2015-11-16 04:28:00Z adrian $"); 31275988Sngie 32275988Sngie#include "opt_bus.h" 33275988Sngie 34240116Smarcel#include <sys/param.h> 35240116Smarcel#include <sys/systm.h> 36240116Smarcel#include <sys/bus.h> 37240116Smarcel#include <sys/rman.h> 38240116Smarcel#include <sys/condvar.h> 39240116Smarcel#include <sys/kernel.h> 40240116Smarcel#include <sys/module.h> 41240116Smarcel 42275988Sngie#include <machine/bus.h> 43240116Smarcel 44240116Smarcel#include <dev/usb/usb.h> 45240116Smarcel#include <dev/usb/usbdi.h> 46240116Smarcel 47275988Sngie#include <dev/usb/usb_core.h> 48275988Sngie#include <dev/usb/usb_busdma.h> 49240116Smarcel#include <dev/usb/usb_process.h> 50240116Smarcel#include <dev/usb/usb_util.h> 51240116Smarcel 52240116Smarcel#include <dev/usb/usb_controller.h> 53240116Smarcel#include <dev/usb/usb_bus.h> 54240116Smarcel#include <dev/usb/controller/ehci.h> 55240116Smarcel#include <dev/usb/controller/ehcireg.h> 56240116Smarcel 57240116Smarcel#include <mips/atheros/ar71xx_setup.h> 58240116Smarcel#include <mips/atheros/ar71xxreg.h> /* for stuff in ar71xx_cpudef.h */ 59240116Smarcel#include <mips/atheros/ar71xx_cpudef.h> 60240116Smarcel#include <mips/atheros/ar71xx_bus_space_reversed.h> 61240116Smarcel 62240116Smarcel#define EHCI_HC_DEVSTR "AR71XX Integrated USB 2.0 controller" 63240116Smarcel 64240116Smarcelstruct ar71xx_ehci_softc { 65240116Smarcel ehci_softc_t base; /* storage for EHCI code */ 66240116Smarcel}; 67240116Smarcel 68240116Smarcelstatic device_attach_t ar71xx_ehci_attach; 69240116Smarcelstatic device_detach_t ar71xx_ehci_detach; 70240116Smarcel 71240116Smarcelbs_r_1_proto(reversed); 72240116Smarcelbs_w_1_proto(reversed); 73240116Smarcel 74240116Smarcelstatic int 75240116Smarcelar71xx_ehci_probe(device_t self) 76240116Smarcel{ 77240116Smarcel 78240116Smarcel device_set_desc(self, EHCI_HC_DEVSTR); 79240116Smarcel 80240116Smarcel return (BUS_PROBE_NOWILDCARD); 81240116Smarcel} 82240116Smarcel 83240116Smarcelstatic void 84240116Smarcelar71xx_ehci_intr(void *arg) 85240116Smarcel{ 86240116Smarcel 87240116Smarcel /* XXX TODO: should really see if this was our interrupt.. */ 88240116Smarcel ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_USB); 89240116Smarcel ehci_interrupt(arg); 90240116Smarcel} 91240116Smarcel 92240116Smarcelstatic int 93240116Smarcelar71xx_ehci_attach(device_t self) 94240116Smarcel{ 95240116Smarcel struct ar71xx_ehci_softc *isc = device_get_softc(self); 96240116Smarcel ehci_softc_t *sc = &isc->base; 97240116Smarcel int err; 98240116Smarcel int rid; 99240116Smarcel 100240116Smarcel /* initialise some bus fields */ 101240116Smarcel sc->sc_bus.parent = self; 102240116Smarcel sc->sc_bus.devices = sc->sc_devices; 103240116Smarcel sc->sc_bus.devices_max = EHCI_MAX_DEVICES; 104240116Smarcel sc->sc_bus.dma_bits = 32; 105240116Smarcel 106240116Smarcel /* get all DMA memory */ 107240116Smarcel if (usb_bus_mem_alloc_all(&sc->sc_bus, 108240116Smarcel USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { 109240116Smarcel return (ENOMEM); 110240116Smarcel } 111240116Smarcel 112240116Smarcel sc->sc_bus.usbrev = USB_REV_2_0; 113240116Smarcel 114240116Smarcel /* NB: hints fix the memory location and irq */ 115240116Smarcel 116240116Smarcel rid = 0; 117240116Smarcel sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); 118240116Smarcel if (!sc->sc_io_res) { 119240116Smarcel device_printf(self, "Could not map memory\n"); 120240116Smarcel goto error; 121240116Smarcel } 122240116Smarcel 123240116Smarcel /* 124240116Smarcel * Craft special resource for bus space ops that handle 125240116Smarcel * byte-alignment of non-word addresses. 126240116Smarcel */ 127240116Smarcel sc->sc_io_tag = ar71xx_bus_space_reversed; 128240116Smarcel sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 129240116Smarcel sc->sc_io_size = rman_get_size(sc->sc_io_res); 130240116Smarcel 131240116Smarcel rid = 0; 132240116Smarcel sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 133240116Smarcel RF_ACTIVE | RF_SHAREABLE); 134240116Smarcel if (sc->sc_irq_res == NULL) { 135240116Smarcel device_printf(self, "Could not allocate irq\n"); 136240116Smarcel goto error; 137240116Smarcel } 138240116Smarcel sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 139240116Smarcel if (!sc->sc_bus.bdev) { 140240116Smarcel device_printf(self, "Could not add USB device\n"); 141240116Smarcel goto error; 142240116Smarcel } 143240116Smarcel device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 144240116Smarcel device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR); 145240116Smarcel 146240116Smarcel sprintf(sc->sc_vendor, "Atheros"); 147240116Smarcel 148240116Smarcel err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 149240116Smarcel NULL, ar71xx_ehci_intr, sc, &sc->sc_intr_hdl); 150240116Smarcel if (err) { 151240116Smarcel device_printf(self, "Could not setup irq, %d\n", err); 152240116Smarcel sc->sc_intr_hdl = NULL; 153240116Smarcel goto error; 154240116Smarcel } 155240116Smarcel 156240116Smarcel /* 157240116Smarcel * Arrange to force Host mode, select big-endian byte alignment, 158275988Sngie * and arrange to not terminate reset operations (the adapter 159240116Smarcel * will ignore it if we do but might as well save a reg write). 160240116Smarcel * Also, the controller has an embedded Transaction Translator 161240116Smarcel * which means port speed must be read from the Port Status 162275988Sngie * register following a port enable. 163275988Sngie */ 164240116Smarcel sc->sc_flags = EHCI_SCFLG_SETMODE; 165240116Smarcel 166240116Smarcel switch (ar71xx_soc) { 167275988Sngie case AR71XX_SOC_AR7241: 168240116Smarcel case AR71XX_SOC_AR7242: 169240116Smarcel case AR71XX_SOC_AR9130: 170240116Smarcel case AR71XX_SOC_AR9132: 171240116Smarcel case AR71XX_SOC_AR9330: 172240116Smarcel case AR71XX_SOC_AR9331: 173240116Smarcel case AR71XX_SOC_AR9341: 174240116Smarcel case AR71XX_SOC_AR9342: 175240116Smarcel case AR71XX_SOC_AR9344: 176240116Smarcel case AR71XX_SOC_QCA9533: 177240116Smarcel case AR71XX_SOC_QCA9533_V2: 178240116Smarcel case AR71XX_SOC_QCA9556: 179240116Smarcel case AR71XX_SOC_QCA9558: 180240116Smarcel sc->sc_flags |= EHCI_SCFLG_TT | EHCI_SCFLG_NORESTERM; 181240116Smarcel break; 182240116Smarcel default: 183240116Smarcel /* fallthrough */ 184240116Smarcel break; 185240116Smarcel } 186240116Smarcel 187240116Smarcel /* 188240116Smarcel * ehci_reset() needs the correct offset to access the host controller 189240116Smarcel * registers. The AR724x/AR913x offsets aren't 0. 190240116Smarcel */ 191240116Smarcel sc->sc_offs = EHCI_CAPLENGTH(EREAD4(sc, EHCI_CAPLEN_HCIVERSION)); 192240116Smarcel 193240116Smarcel (void) ehci_reset(sc); 194240116Smarcel 195240116Smarcel err = ehci_init(sc); 196240116Smarcel if (!err) { 197240116Smarcel err = device_probe_and_attach(sc->sc_bus.bdev); 198240116Smarcel } 199240116Smarcel if (err) { 200240116Smarcel device_printf(self, "USB init failed err=%d\n", err); 201240116Smarcel goto error; 202240116Smarcel } 203240116Smarcel return (0); 204275988Sngie 205240116Smarcelerror: 206240116Smarcel ar71xx_ehci_detach(self); 207240116Smarcel return (ENXIO); 208275988Sngie} 209275988Sngie 210240116Smarcelstatic int 211240116Smarcelar71xx_ehci_detach(device_t self) 212240116Smarcel{ 213240116Smarcel struct ar71xx_ehci_softc *isc = device_get_softc(self); 214240116Smarcel ehci_softc_t *sc = &isc->base; 215240116Smarcel device_t bdev; 216240116Smarcel int err; 217240116Smarcel 218240116Smarcel if (sc->sc_bus.bdev) { 219240116Smarcel bdev = sc->sc_bus.bdev; 220240116Smarcel device_detach(bdev); 221240116Smarcel device_delete_child(self, bdev); 222240116Smarcel } 223240116Smarcel /* during module unload there are lots of children leftover */ 224240116Smarcel device_delete_children(self); 225240116Smarcel 226240116Smarcel if (sc->sc_irq_res && sc->sc_intr_hdl) { 227240116Smarcel /* 228240116Smarcel * only call ehci_detach() after ehci_init() 229240116Smarcel */ 230240116Smarcel ehci_detach(sc); 231240116Smarcel 232240116Smarcel err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 233240116Smarcel 234240116Smarcel if (err) 235240116Smarcel /* XXX or should we panic? */ 236240116Smarcel device_printf(self, "Could not tear down irq, %d\n", 237240116Smarcel err); 238240116Smarcel sc->sc_intr_hdl = NULL; 239240116Smarcel } 240240116Smarcel 241240116Smarcel if (sc->sc_irq_res) { 242240116Smarcel bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); 243240116Smarcel sc->sc_irq_res = NULL; 244240116Smarcel } 245240116Smarcel if (sc->sc_io_res) { 246240116Smarcel bus_release_resource(self, SYS_RES_MEMORY, 0, 247240116Smarcel sc->sc_io_res); 248240116Smarcel sc->sc_io_res = NULL; 249240116Smarcel } 250275988Sngie usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); 251240116Smarcel 252240116Smarcel return (0); 253240116Smarcel} 254275988Sngie 255275988Sngiestatic device_method_t ehci_methods[] = { 256240116Smarcel /* Device interface */ 257240116Smarcel DEVMETHOD(device_probe, ar71xx_ehci_probe), 258240116Smarcel DEVMETHOD(device_attach, ar71xx_ehci_attach), 259275988Sngie DEVMETHOD(device_detach, ar71xx_ehci_detach), 260275988Sngie DEVMETHOD(device_suspend, bus_generic_suspend), 261240116Smarcel DEVMETHOD(device_resume, bus_generic_resume), 262240116Smarcel DEVMETHOD(device_shutdown, bus_generic_shutdown), 263240116Smarcel 264240116Smarcel DEVMETHOD_END 265240116Smarcel}; 266240116Smarcel 267240116Smarcelstatic driver_t ehci_driver = { 268240116Smarcel .name = "ehci", 269240116Smarcel .methods = ehci_methods, 270240116Smarcel .size = sizeof(struct ar71xx_ehci_softc), 271240116Smarcel}; 272240116Smarcel 273240116Smarcelstatic devclass_t ehci_devclass; 274240116Smarcel 275240116SmarcelDRIVER_MODULE(ehci, nexus, ehci_driver, ehci_devclass, 0, 0); 276240116SmarcelDRIVER_MODULE(ehci, apb, ehci_driver, ehci_devclass, 0, 0); 277240116Smarcel 278240116SmarcelMODULE_DEPEND(ehci, usb, 1, 1, 1); 279240116Smarcel