ehci_mv.c revision 330897
14Srgrimes/*- 24Srgrimes * SPDX-License-Identifier: BSD-3-Clause 34Srgrimes * 44Srgrimes * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. 54Srgrimes * All rights reserved. 64Srgrimes * 74Srgrimes * Developed by Semihalf. 84Srgrimes * 94Srgrimes * Redistribution and use in source and binary forms, with or without 104Srgrimes * modification, are permitted provided that the following conditions 114Srgrimes * are met: 124Srgrimes * 1. Redistributions of source code must retain the above copyright 134Srgrimes * notice, this list of conditions and the following disclaimer. 144Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 154Srgrimes * notice, this list of conditions and the following disclaimer in the 164Srgrimes * documentation and/or other materials provided with the distribution. 174Srgrimes * 3. Neither the name of MARVELL nor the names of contributors 184Srgrimes * may be used to endorse or promote products derived from this software 194Srgrimes * without specific prior written permission. 204Srgrimes * 214Srgrimes * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 224Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 234Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 244Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 254Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 264Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 274Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 284Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 294Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30593Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 314Srgrimes * SUCH DAMAGE. 324Srgrimes */ 33115703Sobrien 34115703Sobrien/* 35115703Sobrien * FDT attachment driver for the USB Enhanced Host Controller. 3679609Speter */ 3789980Sbde 3885268Sbde#include <sys/cdefs.h> 3913225Swollman__FBSDID("$FreeBSD: stable/11/sys/dev/usb/controller/ehci_mv.c 330897 2018-03-14 03:19:51Z eadler $"); 402056Swollman 412056Swollman#include "opt_bus.h" 4245720Speter 4311865Sphk#include <sys/stdint.h> 4476166Smarkm#include <sys/stddef.h> 4533281Sbde#include <sys/param.h> 4645720Speter#include <sys/queue.h> 4776166Smarkm#include <sys/types.h> 4876166Smarkm#include <sys/systm.h> 4976166Smarkm#include <sys/kernel.h> 50121986Sjhb#include <sys/bus.h> 5111865Sphk#include <sys/module.h> 5245720Speter#include <sys/lock.h> 5345720Speter#include <sys/mutex.h> 5422093Sbde#include <sys/condvar.h> 554478Sbde#include <sys/sysctl.h> 5622093Sbde#include <sys/sx.h> 574478Sbde#include <sys/unistd.h> 583816Swollman#include <sys/callout.h> 5925083Sjdp#include <sys/malloc.h> 6030805Sbde#include <sys/priv.h> 6130805Sbde 6226309Speter#include <dev/ofw/ofw_bus.h> 632056Swollman#include <dev/ofw/ofw_bus_subr.h> 6430805Sbde 6545720Speter#include <dev/usb/usb.h> 662056Swollman#include <dev/usb/usbdi.h> 6730805Sbde 68103409Smini#include <dev/usb/usb_core.h> 693816Swollman#include <dev/usb/usb_busdma.h> 70121986Sjhb#include <dev/usb/usb_process.h> 71181780Skmacy#include <dev/usb/usb_util.h> 72181780Skmacy 73186557Skmacy#include <dev/usb/usb_controller.h> 74181780Skmacy#include <dev/usb/usb_bus.h> 75181780Skmacy#include <dev/usb/controller/ehci.h> 7689980Sbde#include <dev/usb/controller/ehcireg.h> 7760008Swollman 7889980Sbde#include <arm/mv/mvreg.h> 794Srgrimes#include <arm/mv/mvvar.h> 80147741Sdelphij 81103064Speter#define EHCI_VENDORID_MRVL 0x1286 82103064Speter#define EHCI_HC_DEVSTR "Marvell Integrated USB 2.0 controller" 83103064Speter 844Srgrimesstatic device_attach_t mv_ehci_attach; 854Srgrimesstatic device_detach_t mv_ehci_detach; 864Srgrimes 874Srgrimesstatic int err_intr(void *arg); 88143063Sjoerg 894Srgrimesstatic struct resource *irq_err; 905351Sbdestatic void *ih_err; 914Srgrimes 924Srgrimes/* EHCI HC regs start at this offset within USB range */ 9335215Sbde#define MV_USB_HOST_OFST 0x0100 9435215Sbde 9535215Sbde#define USB_BRIDGE_INTR_CAUSE 0x210 965351Sbde#define USB_BRIDGE_INTR_MASK 0x214 975351Sbde#define USB_BRIDGE_ERR_ADDR 0x21C 9882154Speter 9979609Speter#define MV_USB_ADDR_DECODE_ERR (1 << 0) 10079609Speter#define MV_USB_HOST_UNDERFLOW (1 << 1) 101143768Sdas#define MV_USB_HOST_OVERFLOW (1 << 2) 10282154Speter#define MV_USB_DEVICE_UNDERFLOW (1 << 3) 103181780Skmacy 104181780Skmacystatic struct ofw_compat_data compat_data[] = { 105181780Skmacy {"mrvl,usb-ehci", true}, 106181780Skmacy {"marvell,orion-ehci", true}, 1074Srgrimes {NULL, false} 1084Srgrimes}; 1094Srgrimes 110181780Skmacystatic void 111143063Sjoergmv_ehci_post_reset(struct ehci_softc *ehci_softc) 1124Srgrimes{ 11393024Sbde uint32_t usbmode; 11493024Sbde 11593024Sbde /* Force HOST mode */ 11693024Sbde usbmode = EOREAD4(ehci_softc, EHCI_USBMODE_NOLPM); 11793024Sbde usbmode &= ~EHCI_UM_CM; 11893024Sbde usbmode |= EHCI_UM_CM_HOST; 11993024Sbde EOWRITE4(ehci_softc, EHCI_USBMODE_NOLPM, usbmode); 12093024Sbde} 12182154Speter 12293024Sbdestatic int 12393024Sbdemv_ehci_probe(device_t self) 12482154Speter{ 12593024Sbde 12693024Sbde if (!ofw_bus_status_okay(self)) 1274Srgrimes return (ENXIO); 128143063Sjoerg 1294Srgrimes if (!ofw_bus_search_compatible(self, compat_data)->ocd_data) 13079609Speter return (ENXIO); 13183366Sjulian 13279609Speter device_set_desc(self, EHCI_HC_DEVSTR); 133208833Skib 134208833Skib return (BUS_PROBE_DEFAULT); 13583366Sjulian} 13679609Speter 137208833Skibstatic int 138208833Skibmv_ehci_attach(device_t self) 139189423Sjhb{ 140189423Sjhb ehci_softc_t *sc = device_get_softc(self); 141189423Sjhb bus_space_handle_t bsh; 142189423Sjhb int err; 143189423Sjhb int rid; 144189423Sjhb 14579609Speter /* initialise some bus fields */ 14683366Sjulian sc->sc_bus.parent = self; 147208833Skib sc->sc_bus.devices = sc->sc_devices; 14883366Sjulian sc->sc_bus.devices_max = EHCI_MAX_DEVICES; 149208833Skib sc->sc_bus.dma_bits = 32; 150189423Sjhb 151189423Sjhb /* get all DMA memory */ 15279609Speter if (usb_bus_mem_alloc_all(&sc->sc_bus, 15379609Speter USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { 1544Srgrimes return (ENOMEM); 1554Srgrimes } 156157860Scperciva 157157860Scperciva rid = 0; 158157860Scperciva sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); 159157860Scperciva if (!sc->sc_io_res) { 160106977Sdeischen device_printf(self, "Could not map memory\n"); 161106977Sdeischen goto error; 16293024Sbde } 16393024Sbde sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 16493024Sbde bsh = rman_get_bushandle(sc->sc_io_res); 1654Srgrimes sc->sc_io_size = rman_get_size(sc->sc_io_res) - MV_USB_HOST_OFST; 166209461Skib 16711865Sphk /* 168188938Sjhb * Marvell EHCI host controller registers start at certain offset 169188938Sjhb * within the whole USB registers range, so create a subregion for the 17011865Sphk * host mode configuration purposes. 17141591Sarchie */ 172190413Sjhb 1734Srgrimes if (bus_space_subregion(sc->sc_io_tag, bsh, MV_USB_HOST_OFST, 17485029Sbde sc->sc_io_size, &sc->sc_io_hdl) != 0) 17535302Sbde panic("%s: unable to subregion USB host registers", 17635302Sbde device_get_name(self)); 17735302Sbde 17846548Sbde rid = 0; 17935302Sbde if (!ofw_bus_is_compatible(self, "marvell,orion-ehci")) { 18035302Sbde irq_err = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 18135302Sbde RF_SHAREABLE | RF_ACTIVE); 18235302Sbde if (irq_err == NULL) { 18335302Sbde device_printf(self, "Could not allocate error irq\n"); 1844Srgrimes mv_ehci_detach(self); 1854Srgrimes return (ENXIO); 1864Srgrimes } 18750181Speter rid = 1; 18850181Speter } 18950181Speter 19050181Speter /* 19150181Speter * Notice: Marvell EHCI controller has TWO interrupt lines, so make 19250181Speter * sure to use the correct rid for the main one (controller interrupt) 19350181Speter * -- refer to DTS for the right resource number to use here. 19450181Speter */ 19550181Speter sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 19650181Speter RF_SHAREABLE | RF_ACTIVE); 19750181Speter if (sc->sc_irq_res == NULL) { 19850181Speter device_printf(self, "Could not allocate irq\n"); 19950181Speter goto error; 20050181Speter } 20150181Speter 202157568Sjhb sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 203157568Sjhb if (!sc->sc_bus.bdev) { 2044Srgrimes device_printf(self, "Could not add USB device\n"); 2054Srgrimes goto error; 206209461Skib } 2074Srgrimes device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 20885029Sbde device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR); 209209461Skib 21027567Sfsmp sprintf(sc->sc_vendor, "Marvell"); 211157568Sjhb 212157568Sjhb if (!ofw_bus_is_compatible(self, "marvell,orion-ehci")) { 213157568Sjhb err = bus_setup_intr(self, irq_err, INTR_TYPE_BIO, 214157568Sjhb err_intr, NULL, sc, &ih_err); 215157568Sjhb if (err) { 216157568Sjhb device_printf(self, "Could not setup error irq, %d\n", err); 217157568Sjhb ih_err = NULL; 218157568Sjhb goto error; 219209461Skib } 220157568Sjhb } 221157568Sjhb 222157568Sjhb EWRITE4(sc, USB_BRIDGE_INTR_MASK, MV_USB_ADDR_DECODE_ERR | 223157568Sjhb MV_USB_HOST_UNDERFLOW | MV_USB_HOST_OVERFLOW | 224119935Sjhb MV_USB_DEVICE_UNDERFLOW); 225119935Sjhb 226119935Sjhb err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 22727567Sfsmp NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); 2284Srgrimes if (err) { 229157568Sjhb device_printf(self, "Could not setup irq, %d\n", err); 2304Srgrimes sc->sc_intr_hdl = NULL; 2314Srgrimes goto error; 232157568Sjhb } 2334Srgrimes 2344Srgrimes /* 23585029Sbde * Workaround for Marvell integrated EHCI controller: reset of 2364Srgrimes * the EHCI core clears the USBMODE register, which sets the core in 2374Srgrimes * an undefined state (neither host nor agent), so it needs to be set 2384Srgrimes * again for proper operation. 2394Srgrimes * 24027567Sfsmp * Refer to errata document MV-S500832-00D.pdf (p. 5.24 GL USB-2) for 2416664Sbde * details. 2426664Sbde */ 2436664Sbde sc->sc_vendor_post_reset = mv_ehci_post_reset; 2446664Sbde if (bootverbose) 2455351Sbde device_printf(self, "5.24 GL USB-2 workaround enabled\n"); 2464Srgrimes 2474Srgrimes /* XXX all MV chips need it? */ 2484Srgrimes sc->sc_flags |= EHCI_SCFLG_TT | EHCI_SCFLG_NORESTERM; 2494Srgrimes sc->sc_vendor_get_port_speed = ehci_get_port_speed_portsc; 2504Srgrimes err = ehci_init(sc); 2514Srgrimes if (!err) { 2524Srgrimes err = device_probe_and_attach(sc->sc_bus.bdev); 2534Srgrimes } 2544Srgrimes if (err) { 2554Srgrimes device_printf(self, "USB init failed err=%d\n", err); 2564Srgrimes goto error; 2574Srgrimes } 2584Srgrimes return (0); 2594Srgrimes 2608876Srgrimeserror: 2614Srgrimes mv_ehci_detach(self); 2624Srgrimes return (ENXIO); 2634Srgrimes} 2644Srgrimes 2654Srgrimesstatic int 2664Srgrimesmv_ehci_detach(device_t self) 2674Srgrimes{ 2684Srgrimes ehci_softc_t *sc = device_get_softc(self); 26985268Sbde int err; 27085268Sbde 27185268Sbde /* during module unload there are lots of children leftover */ 27285268Sbde device_delete_children(self); 27385268Sbde 274209461Skib /* 27585268Sbde * disable interrupts that might have been switched on in mv_ehci_attach 27685268Sbde */ 277209461Skib if (sc->sc_io_res) { 2784Srgrimes EWRITE4(sc, USB_BRIDGE_INTR_MASK, 0); 2794Srgrimes } 2804Srgrimes if (sc->sc_irq_res && sc->sc_intr_hdl) { 2814Srgrimes /* 2824Srgrimes * only call ehci_detach() after ehci_init() 283209461Skib */ 284209461Skib ehci_detach(sc); 2854Srgrimes 286209461Skib err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 287209461Skib 288209461Skib if (err) 2894Srgrimes /* XXX or should we panic? */ 2904Srgrimes device_printf(self, "Could not tear down irq, %d\n", 291189418Sjhb err); 292209461Skib sc->sc_intr_hdl = NULL; 293209461Skib } 294209461Skib if (irq_err && ih_err) { 295209461Skib err = bus_teardown_intr(self, irq_err, ih_err); 296189418Sjhb 297209461Skib if (err) 298209461Skib device_printf(self, "Could not tear down irq, %d\n", 299189418Sjhb err); 300209461Skib ih_err = NULL; 301119935Sjhb } 302209461Skib if (irq_err) { 3034Srgrimes bus_release_resource(self, SYS_RES_IRQ, 0, irq_err); 3044Srgrimes irq_err = NULL; 3054Srgrimes } 3064Srgrimes if (sc->sc_irq_res) { 3074Srgrimes bus_release_resource(self, SYS_RES_IRQ, 1, sc->sc_irq_res); 308104094Sphk sc->sc_irq_res = NULL; 309209461Skib } 3104Srgrimes if (sc->sc_io_res) { 311103409Smini bus_release_resource(self, SYS_RES_MEMORY, 0, 31240565Sbde sc->sc_io_res); 313189418Sjhb sc->sc_io_res = NULL; 314189418Sjhb } 315189418Sjhb usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); 316190413Sjhb 317189418Sjhb return (0); 318159087Sdavidxu} 319189418Sjhb 320190413Sjhbstatic int 321189418Sjhberr_intr(void *arg) 322190413Sjhb{ 323189418Sjhb ehci_softc_t *sc = arg; 324189418Sjhb unsigned int cause; 325190413Sjhb 326190413Sjhb cause = EREAD4(sc, USB_BRIDGE_INTR_CAUSE); 327190413Sjhb if (cause) { 328190413Sjhb printf("USB error: "); 329189418Sjhb if (cause & MV_USB_ADDR_DECODE_ERR) { 330189418Sjhb uint32_t addr; 331159087Sdavidxu 332190413Sjhb addr = EREAD4(sc, USB_BRIDGE_ERR_ADDR); 333190413Sjhb printf("address decoding error (addr=%#x)\n", addr); 334189418Sjhb } 33519653Sbde if (cause & MV_USB_HOST_UNDERFLOW) 336209460Skib printf("host underflow\n"); 3374Srgrimes if (cause & MV_USB_HOST_OVERFLOW) 3384Srgrimes printf("host overflow\n"); 3394Srgrimes if (cause & MV_USB_DEVICE_UNDERFLOW) 3404Srgrimes printf("device underflow\n"); 3414Srgrimes if (cause & ~(MV_USB_ADDR_DECODE_ERR | MV_USB_HOST_UNDERFLOW | 3424Srgrimes MV_USB_HOST_OVERFLOW | MV_USB_DEVICE_UNDERFLOW)) 343189418Sjhb printf("unknown cause (cause=%#x)\n", cause); 3444Srgrimes 34579824Stegge EWRITE4(sc, USB_BRIDGE_INTR_CAUSE, 0); 34692860Simp } 347189418Sjhb return (FILTER_HANDLED); 3484Srgrimes} 349209461Skib 3504Srgrimesstatic device_method_t ehci_methods[] = { 3514Srgrimes /* Device interface */ 3524Srgrimes DEVMETHOD(device_probe, mv_ehci_probe), 3535351Sbde DEVMETHOD(device_attach, mv_ehci_attach), 35487702Sjhb DEVMETHOD(device_detach, mv_ehci_detach), 3554Srgrimes DEVMETHOD(device_suspend, bus_generic_suspend), 35692860Simp DEVMETHOD(device_resume, bus_generic_resume), 3574Srgrimes DEVMETHOD(device_shutdown, bus_generic_shutdown), 3584Srgrimes 35985009Stegge DEVMETHOD_END 36085009Stegge}; 36185009Stegge 36285009Steggestatic driver_t ehci_driver = { 36385009Stegge "ehci", 364189418Sjhb ehci_methods, 3654Srgrimes sizeof(ehci_softc_t), 3664Srgrimes}; 36792860Simp 3684Srgrimesstatic devclass_t ehci_devclass; 3694Srgrimes 3704SrgrimesDRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0); 3714SrgrimesMODULE_DEPEND(ehci, usb, 1, 1, 1); 3724Srgrimes