1303475Sandrew/*- 2303475Sandrew * Copyright (c) 2012 Ganbold Tsagaankhuu <ganbold@freebsd.org> 3303475Sandrew * Copyright (c) 2016 The FreeBSD Foundation 4303475Sandrew * All rights reserved. 5303475Sandrew * 6303475Sandrew * This software was developed by Andrew Turner under 7303475Sandrew * sponsorship from the FreeBSD Foundation. 8303475Sandrew * 9303475Sandrew * Redistribution and use in source and binary forms, with or without 10303475Sandrew * modification, are permitted provided that the following conditions 11303475Sandrew * are met: 12303475Sandrew * 1. Redistributions of source code must retain the above copyright 13303475Sandrew * notice, this list of conditions and the following disclaimer. 14303475Sandrew * 2. Redistributions in binary form must reproduce the above copyright 15303475Sandrew * notice, this list of conditions and the following disclaimer in the 16303475Sandrew * documentation and/or other materials provided with the distribution. 17303475Sandrew * 18303475Sandrew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19303475Sandrew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20303475Sandrew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21303475Sandrew * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22303475Sandrew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23303475Sandrew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24303475Sandrew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25303475Sandrew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26303475Sandrew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27303475Sandrew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28303475Sandrew * SUCH DAMAGE. 29303475Sandrew */ 30303475Sandrew 31303475Sandrew/* 32303475Sandrew * Generic EHCI driver based on the Allwinner A10 EHCI driver 33303475Sandrew */ 34303475Sandrew 35303475Sandrew#include <sys/cdefs.h> 36303475Sandrew__FBSDID("$FreeBSD: stable/11/sys/dev/usb/controller/generic_ehci.c 308401 2016-11-07 08:36:06Z hselasky $"); 37303475Sandrew 38303475Sandrew#include "opt_bus.h" 39303475Sandrew 40303475Sandrew#include <sys/param.h> 41303475Sandrew#include <sys/systm.h> 42303475Sandrew#include <sys/bus.h> 43303475Sandrew#include <sys/rman.h> 44303475Sandrew#include <sys/condvar.h> 45303475Sandrew#include <sys/kernel.h> 46303475Sandrew#include <sys/module.h> 47303475Sandrew 48303475Sandrew#include <machine/bus.h> 49303475Sandrew 50303475Sandrew#include <dev/usb/usb.h> 51303475Sandrew#include <dev/usb/usbdi.h> 52303475Sandrew 53303475Sandrew#include <dev/usb/usb_core.h> 54303475Sandrew#include <dev/usb/usb_busdma.h> 55303475Sandrew#include <dev/usb/usb_process.h> 56303475Sandrew#include <dev/usb/usb_util.h> 57303475Sandrew 58303475Sandrew#include <dev/usb/usb_controller.h> 59303475Sandrew#include <dev/usb/usb_bus.h> 60303475Sandrew#include <dev/usb/controller/ehci.h> 61303475Sandrew#include <dev/usb/controller/ehcireg.h> 62303475Sandrew 63303475Sandrew#include <contrib/dev/acpica/include/acpi.h> 64303475Sandrew#include <contrib/dev/acpica/include/accommon.h> 65303475Sandrew#include <dev/acpica/acpivar.h> 66303475Sandrew 67303475Sandrewstatic device_attach_t generic_ehci_attach; 68303475Sandrewstatic device_detach_t generic_ehci_detach; 69303475Sandrew 70303475Sandrewstatic int 71303475Sandrewgeneric_ehci_probe(device_t self) 72303475Sandrew{ 73303475Sandrew ACPI_HANDLE h; 74303475Sandrew 75303475Sandrew if ((h = acpi_get_handle(self)) == NULL || 76303475Sandrew !acpi_MatchHid(h, "PNP0D20")) 77303475Sandrew return (ENXIO); 78303475Sandrew 79303475Sandrew device_set_desc(self, "Generic EHCI Controller"); 80303475Sandrew return (BUS_PROBE_DEFAULT); 81303475Sandrew} 82303475Sandrew 83303475Sandrewstatic int 84303475Sandrewgeneric_ehci_attach(device_t self) 85303475Sandrew{ 86303475Sandrew ehci_softc_t *sc = device_get_softc(self); 87303475Sandrew int err; 88303475Sandrew int rid; 89303475Sandrew 90303475Sandrew /* initialise some bus fields */ 91303475Sandrew sc->sc_bus.parent = self; 92303475Sandrew sc->sc_bus.devices = sc->sc_devices; 93303475Sandrew sc->sc_bus.devices_max = EHCI_MAX_DEVICES; 94303475Sandrew sc->sc_bus.dma_bits = 32; 95303475Sandrew 96303475Sandrew /* get all DMA memory */ 97303475Sandrew if (usb_bus_mem_alloc_all(&sc->sc_bus, 98303475Sandrew USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { 99303475Sandrew return (ENOMEM); 100303475Sandrew } 101303475Sandrew 102303475Sandrew sc->sc_bus.usbrev = USB_REV_2_0; 103303475Sandrew 104303475Sandrew rid = 0; 105303475Sandrew sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, 106303475Sandrew RF_ACTIVE); 107303475Sandrew if (!sc->sc_io_res) { 108303475Sandrew device_printf(self, "Could not map memory\n"); 109303475Sandrew goto error; 110303475Sandrew } 111303475Sandrew 112303475Sandrew sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 113303475Sandrew sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 114303475Sandrew sc->sc_io_size = rman_get_size(sc->sc_io_res); 115303475Sandrew 116303475Sandrew rid = 0; 117303475Sandrew sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 118303475Sandrew RF_SHAREABLE | RF_ACTIVE); 119303475Sandrew if (sc->sc_irq_res == NULL) { 120303475Sandrew device_printf(self, "Could not allocate irq\n"); 121303475Sandrew goto error; 122303475Sandrew } 123303475Sandrew sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 124303475Sandrew if (!sc->sc_bus.bdev) { 125303475Sandrew device_printf(self, "Could not add USB device\n"); 126303475Sandrew goto error; 127303475Sandrew } 128303475Sandrew device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 129303475Sandrew 130303475Sandrew strlcpy(sc->sc_vendor, "Generic", sizeof(sc->sc_vendor)); 131303475Sandrew 132303475Sandrew err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 133303475Sandrew NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); 134303475Sandrew if (err) { 135303475Sandrew device_printf(self, "Could not setup irq, %d\n", err); 136303475Sandrew sc->sc_intr_hdl = NULL; 137303475Sandrew goto error; 138303475Sandrew } 139303475Sandrew 140303475Sandrew sc->sc_flags |= EHCI_SCFLG_DONTRESET; 141303475Sandrew 142303475Sandrew err = ehci_init(sc); 143303475Sandrew if (!err) 144303475Sandrew err = device_probe_and_attach(sc->sc_bus.bdev); 145303475Sandrew if (err) 146303475Sandrew goto error; 147303475Sandrew 148303475Sandrew return (0); 149303475Sandrew 150303475Sandrewerror: 151303475Sandrew generic_ehci_detach(self); 152303475Sandrew return (ENXIO); 153303475Sandrew} 154303475Sandrew 155303475Sandrewstatic int 156303475Sandrewgeneric_ehci_detach(device_t self) 157303475Sandrew{ 158303475Sandrew ehci_softc_t *sc = device_get_softc(self); 159303475Sandrew int err; 160303475Sandrew 161303475Sandrew /* during module unload there are lots of children leftover */ 162303475Sandrew device_delete_children(self); 163303475Sandrew 164303475Sandrew if (sc->sc_irq_res && sc->sc_intr_hdl) { 165303475Sandrew /* 166303475Sandrew * only call ehci_detach() after ehci_init() 167303475Sandrew */ 168303475Sandrew ehci_detach(sc); 169303475Sandrew 170303475Sandrew err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 171303475Sandrew 172303475Sandrew if (err) 173303475Sandrew /* XXX or should we panic? */ 174303475Sandrew device_printf(self, "Could not tear down irq, %d\n", 175303475Sandrew err); 176303475Sandrew sc->sc_intr_hdl = NULL; 177303475Sandrew } 178303475Sandrew 179303475Sandrew if (sc->sc_irq_res) { 180303475Sandrew bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); 181303475Sandrew sc->sc_irq_res = NULL; 182303475Sandrew } 183303475Sandrew if (sc->sc_io_res) { 184303475Sandrew bus_release_resource(self, SYS_RES_MEMORY, 0, 185303475Sandrew sc->sc_io_res); 186303475Sandrew sc->sc_io_res = NULL; 187303475Sandrew } 188303475Sandrew usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); 189303475Sandrew 190303475Sandrew return (0); 191303475Sandrew} 192303475Sandrew 193303475Sandrewstatic device_method_t ehci_methods[] = { 194303475Sandrew /* Device interface */ 195303475Sandrew DEVMETHOD(device_probe, generic_ehci_probe), 196303475Sandrew DEVMETHOD(device_attach, generic_ehci_attach), 197303475Sandrew DEVMETHOD(device_detach, generic_ehci_detach), 198303475Sandrew DEVMETHOD(device_suspend, bus_generic_suspend), 199303475Sandrew DEVMETHOD(device_resume, bus_generic_resume), 200303475Sandrew DEVMETHOD(device_shutdown, bus_generic_shutdown), 201303475Sandrew 202303475Sandrew DEVMETHOD_END 203303475Sandrew}; 204303475Sandrew 205303475Sandrewstatic driver_t ehci_driver = { 206303475Sandrew .name = "ehci", 207303475Sandrew .methods = ehci_methods, 208303475Sandrew .size = sizeof(ehci_softc_t), 209303475Sandrew}; 210303475Sandrew 211303475Sandrewstatic devclass_t ehci_devclass; 212303475Sandrew 213303475SandrewDRIVER_MODULE(ehci, acpi, ehci_driver, ehci_devclass, 0, 0); 214303475SandrewMODULE_DEPEND(ehci, usb, 1, 1, 1); 215