1191290Sgonzo/*- 2191290Sgonzo * Copyright (c) 2008 Sam Leffler. All rights reserved. 3191290Sgonzo * 4191290Sgonzo * Redistribution and use in source and binary forms, with or without 5191290Sgonzo * modification, are permitted provided that the following conditions 6191290Sgonzo * are met: 7191290Sgonzo * 1. Redistributions of source code must retain the above copyright 8191290Sgonzo * notice, this list of conditions and the following disclaimer. 9191290Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 10191290Sgonzo * notice, this list of conditions and the following disclaimer in the 11191290Sgonzo * documentation and/or other materials provided with the distribution. 12191290Sgonzo * 13191290Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14191290Sgonzo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15191290Sgonzo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16191290Sgonzo * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17191290Sgonzo * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18191290Sgonzo * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19191290Sgonzo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20191290Sgonzo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21191290Sgonzo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22191290Sgonzo * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23191290Sgonzo */ 24191290Sgonzo 25191290Sgonzo/* 26191290Sgonzo * AR71XX attachment driver for the USB Enhanced Host Controller. 27191290Sgonzo */ 28191290Sgonzo 29191290Sgonzo#include <sys/cdefs.h> 30191290Sgonzo__FBSDID("$FreeBSD: stable/10/sys/mips/atheros/ar71xx_ehci.c 308402 2016-11-07 09:19:04Z hselasky $"); 31191290Sgonzo 32191290Sgonzo#include "opt_bus.h" 33191290Sgonzo 34191290Sgonzo#include <sys/param.h> 35191290Sgonzo#include <sys/systm.h> 36191290Sgonzo#include <sys/bus.h> 37191290Sgonzo#include <sys/rman.h> 38195985Sgonzo#include <sys/condvar.h> 39195985Sgonzo#include <sys/kernel.h> 40195985Sgonzo#include <sys/module.h> 41191290Sgonzo 42191290Sgonzo#include <machine/bus.h> 43191290Sgonzo 44191290Sgonzo#include <dev/usb/usb.h> 45195985Sgonzo#include <dev/usb/usbdi.h> 46191290Sgonzo 47191290Sgonzo#include <dev/usb/usb_core.h> 48191290Sgonzo#include <dev/usb/usb_busdma.h> 49191290Sgonzo#include <dev/usb/usb_process.h> 50191290Sgonzo#include <dev/usb/usb_util.h> 51191290Sgonzo 52191290Sgonzo#include <dev/usb/usb_controller.h> 53191290Sgonzo#include <dev/usb/usb_bus.h> 54191290Sgonzo#include <dev/usb/controller/ehci.h> 55199233Sgonzo#include <dev/usb/controller/ehcireg.h> 56191290Sgonzo 57220051Sadrian#include <mips/atheros/ar71xx_setup.h> 58191290Sgonzo#include <mips/atheros/ar71xx_bus_space_reversed.h> 59191290Sgonzo 60191290Sgonzo#define EHCI_HC_DEVSTR "AR71XX Integrated USB 2.0 controller" 61191290Sgonzo 62191290Sgonzostruct ar71xx_ehci_softc { 63191290Sgonzo ehci_softc_t base; /* storage for EHCI code */ 64191290Sgonzo}; 65191290Sgonzo 66191290Sgonzostatic device_attach_t ar71xx_ehci_attach; 67191290Sgonzostatic device_detach_t ar71xx_ehci_detach; 68191290Sgonzo 69191290Sgonzobs_r_1_proto(reversed); 70191290Sgonzobs_w_1_proto(reversed); 71191290Sgonzo 72191290Sgonzostatic int 73191290Sgonzoar71xx_ehci_probe(device_t self) 74191290Sgonzo{ 75191290Sgonzo 76191290Sgonzo device_set_desc(self, EHCI_HC_DEVSTR); 77191290Sgonzo 78265999Sian return (BUS_PROBE_NOWILDCARD); 79191290Sgonzo} 80191290Sgonzo 81191290Sgonzostatic int 82191290Sgonzoar71xx_ehci_attach(device_t self) 83191290Sgonzo{ 84191290Sgonzo struct ar71xx_ehci_softc *isc = device_get_softc(self); 85191290Sgonzo ehci_softc_t *sc = &isc->base; 86191290Sgonzo int err; 87191290Sgonzo int rid; 88191290Sgonzo 89191290Sgonzo /* initialise some bus fields */ 90191290Sgonzo sc->sc_bus.parent = self; 91191290Sgonzo sc->sc_bus.devices = sc->sc_devices; 92191290Sgonzo sc->sc_bus.devices_max = EHCI_MAX_DEVICES; 93278278Shselasky sc->sc_bus.dma_bits = 32; 94191290Sgonzo 95191290Sgonzo /* get all DMA memory */ 96195985Sgonzo if (usb_bus_mem_alloc_all(&sc->sc_bus, 97191290Sgonzo USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { 98191290Sgonzo return (ENOMEM); 99191290Sgonzo } 100191290Sgonzo 101191290Sgonzo sc->sc_bus.usbrev = USB_REV_2_0; 102191290Sgonzo 103191290Sgonzo /* NB: hints fix the memory location and irq */ 104191290Sgonzo 105191290Sgonzo rid = 0; 106191290Sgonzo sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); 107191290Sgonzo if (!sc->sc_io_res) { 108191290Sgonzo device_printf(self, "Could not map memory\n"); 109191290Sgonzo goto error; 110191290Sgonzo } 111191290Sgonzo 112191290Sgonzo /* 113191290Sgonzo * Craft special resource for bus space ops that handle 114191290Sgonzo * byte-alignment of non-word addresses. 115191290Sgonzo */ 116191293Sgonzo sc->sc_io_tag = ar71xx_bus_space_reversed; 117191290Sgonzo sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 118191290Sgonzo sc->sc_io_size = rman_get_size(sc->sc_io_res); 119191290Sgonzo 120191290Sgonzo rid = 0; 121191290Sgonzo sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 122191290Sgonzo RF_ACTIVE); 123191290Sgonzo if (sc->sc_irq_res == NULL) { 124191290Sgonzo device_printf(self, "Could not allocate irq\n"); 125191290Sgonzo goto error; 126191290Sgonzo } 127191290Sgonzo sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 128191290Sgonzo if (!sc->sc_bus.bdev) { 129191290Sgonzo device_printf(self, "Could not add USB device\n"); 130191290Sgonzo goto error; 131191290Sgonzo } 132191290Sgonzo device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 133191290Sgonzo device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR); 134191290Sgonzo 135191290Sgonzo sprintf(sc->sc_vendor, "Atheros"); 136191290Sgonzo 137191290Sgonzo 138191290Sgonzo err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 139191290Sgonzo NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); 140191290Sgonzo if (err) { 141191290Sgonzo device_printf(self, "Could not setup irq, %d\n", err); 142191290Sgonzo sc->sc_intr_hdl = NULL; 143191290Sgonzo goto error; 144191290Sgonzo } 145191290Sgonzo 146191290Sgonzo /* 147191290Sgonzo * Arrange to force Host mode, select big-endian byte alignment, 148191290Sgonzo * and arrange to not terminate reset operations (the adapter 149191290Sgonzo * will ignore it if we do but might as well save a reg write). 150191290Sgonzo * Also, the controller has an embedded Transaction Translator 151191290Sgonzo * which means port speed must be read from the Port Status 152191290Sgonzo * register following a port enable. 153191290Sgonzo */ 154196795Sgonzo sc->sc_flags = EHCI_SCFLG_SETMODE; 155220051Sadrian 156220051Sadrian switch (ar71xx_soc) { 157220051Sadrian case AR71XX_SOC_AR7241: 158220051Sadrian case AR71XX_SOC_AR7242: 159220051Sadrian case AR71XX_SOC_AR9130: 160220051Sadrian case AR71XX_SOC_AR9132: 161249125Sadrian case AR71XX_SOC_AR9330: 162249125Sadrian case AR71XX_SOC_AR9331: 163220051Sadrian sc->sc_flags |= EHCI_SCFLG_TT | EHCI_SCFLG_NORESTERM; 164220051Sadrian break; 165220051Sadrian default: 166220051Sadrian /* fallthrough */ 167220051Sadrian break; 168220051Sadrian } 169220051Sadrian 170220296Sadrian /* 171220296Sadrian * ehci_reset() needs the correct offset to access the host controller 172220296Sadrian * registers. The AR724x/AR913x offsets aren't 0. 173220296Sadrian */ 174220296Sadrian sc->sc_offs = EHCI_CAPLENGTH(EREAD4(sc, EHCI_CAPLEN_HCIVERSION)); 175220296Sadrian 176220296Sadrian 177191290Sgonzo (void) ehci_reset(sc); 178191290Sgonzo 179191290Sgonzo err = ehci_init(sc); 180191290Sgonzo if (!err) { 181191290Sgonzo err = device_probe_and_attach(sc->sc_bus.bdev); 182191290Sgonzo } 183191290Sgonzo if (err) { 184191290Sgonzo device_printf(self, "USB init failed err=%d\n", err); 185191290Sgonzo goto error; 186191290Sgonzo } 187191290Sgonzo return (0); 188191290Sgonzo 189191290Sgonzoerror: 190191290Sgonzo ar71xx_ehci_detach(self); 191191290Sgonzo return (ENXIO); 192191290Sgonzo} 193191290Sgonzo 194191290Sgonzostatic int 195191290Sgonzoar71xx_ehci_detach(device_t self) 196191290Sgonzo{ 197191290Sgonzo struct ar71xx_ehci_softc *isc = device_get_softc(self); 198191290Sgonzo ehci_softc_t *sc = &isc->base; 199191290Sgonzo int err; 200191290Sgonzo 201191290Sgonzo /* during module unload there are lots of children leftover */ 202227849Shselasky device_delete_children(self); 203191290Sgonzo 204191290Sgonzo if (sc->sc_irq_res && sc->sc_intr_hdl) { 205191290Sgonzo /* 206191290Sgonzo * only call ehci_detach() after ehci_init() 207191290Sgonzo */ 208191290Sgonzo ehci_detach(sc); 209191290Sgonzo 210191290Sgonzo err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 211191290Sgonzo 212191290Sgonzo if (err) 213191290Sgonzo /* XXX or should we panic? */ 214191290Sgonzo device_printf(self, "Could not tear down irq, %d\n", 215191290Sgonzo err); 216191290Sgonzo sc->sc_intr_hdl = NULL; 217191290Sgonzo } 218191290Sgonzo 219191290Sgonzo if (sc->sc_irq_res) { 220191290Sgonzo bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); 221191290Sgonzo sc->sc_irq_res = NULL; 222191290Sgonzo } 223191290Sgonzo if (sc->sc_io_res) { 224191290Sgonzo bus_release_resource(self, SYS_RES_MEMORY, 0, 225191290Sgonzo sc->sc_io_res); 226191290Sgonzo sc->sc_io_res = NULL; 227191290Sgonzo } 228195985Sgonzo usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); 229191290Sgonzo 230191290Sgonzo return (0); 231191290Sgonzo} 232191290Sgonzo 233191290Sgonzostatic device_method_t ehci_methods[] = { 234191290Sgonzo /* Device interface */ 235191290Sgonzo DEVMETHOD(device_probe, ar71xx_ehci_probe), 236191290Sgonzo DEVMETHOD(device_attach, ar71xx_ehci_attach), 237191290Sgonzo DEVMETHOD(device_detach, ar71xx_ehci_detach), 238228483Shselasky DEVMETHOD(device_suspend, bus_generic_suspend), 239228483Shselasky DEVMETHOD(device_resume, bus_generic_resume), 240228483Shselasky DEVMETHOD(device_shutdown, bus_generic_shutdown), 241191290Sgonzo 242227843Smarius DEVMETHOD_END 243191290Sgonzo}; 244191290Sgonzo 245191290Sgonzostatic driver_t ehci_driver = { 246228483Shselasky .name = "ehci", 247228483Shselasky .methods = ehci_methods, 248228483Shselasky .size = sizeof(struct ar71xx_ehci_softc), 249191290Sgonzo}; 250191290Sgonzo 251191290Sgonzostatic devclass_t ehci_devclass; 252191290Sgonzo 253191290SgonzoDRIVER_MODULE(ehci, nexus, ehci_driver, ehci_devclass, 0, 0); 254191290SgonzoMODULE_DEPEND(ehci, usb, 1, 1, 1); 255