1eda295b9SAndrew Turner /*- 2eda295b9SAndrew Turner * Copyright (c) 2012 Ganbold Tsagaankhuu <ganbold@freebsd.org> 3eda295b9SAndrew Turner * Copyright (c) 2016 The FreeBSD Foundation 4eda295b9SAndrew Turner * All rights reserved. 5eda295b9SAndrew Turner * 6eda295b9SAndrew Turner * This software was developed by Andrew Turner under 7eda295b9SAndrew Turner * sponsorship from the FreeBSD Foundation. 8eda295b9SAndrew Turner * 9eda295b9SAndrew Turner * Redistribution and use in source and binary forms, with or without 10eda295b9SAndrew Turner * modification, are permitted provided that the following conditions 11eda295b9SAndrew Turner * are met: 12eda295b9SAndrew Turner * 1. Redistributions of source code must retain the above copyright 13eda295b9SAndrew Turner * notice, this list of conditions and the following disclaimer. 14eda295b9SAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright 15eda295b9SAndrew Turner * notice, this list of conditions and the following disclaimer in the 16eda295b9SAndrew Turner * documentation and/or other materials provided with the distribution. 17eda295b9SAndrew Turner * 18eda295b9SAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19eda295b9SAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20eda295b9SAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21eda295b9SAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22eda295b9SAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23eda295b9SAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24eda295b9SAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25eda295b9SAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26eda295b9SAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27eda295b9SAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28eda295b9SAndrew Turner * SUCH DAMAGE. 29eda295b9SAndrew Turner */ 30eda295b9SAndrew Turner 31eda295b9SAndrew Turner /* 32eda295b9SAndrew Turner * Generic EHCI driver based on the Allwinner A10 EHCI driver 33eda295b9SAndrew Turner */ 34eda295b9SAndrew Turner 35eda295b9SAndrew Turner #include <sys/cdefs.h> 36eda295b9SAndrew Turner #include "opt_bus.h" 37eda295b9SAndrew Turner 38eda295b9SAndrew Turner #include <sys/param.h> 39eda295b9SAndrew Turner #include <sys/systm.h> 40eda295b9SAndrew Turner #include <sys/bus.h> 41eda295b9SAndrew Turner #include <sys/rman.h> 42eda295b9SAndrew Turner #include <sys/condvar.h> 43eda295b9SAndrew Turner #include <sys/kernel.h> 44eda295b9SAndrew Turner #include <sys/module.h> 45eda295b9SAndrew Turner 46eda295b9SAndrew Turner #include <machine/bus.h> 47eda295b9SAndrew Turner 48eda295b9SAndrew Turner #include <dev/usb/usb.h> 49eda295b9SAndrew Turner #include <dev/usb/usbdi.h> 50eda295b9SAndrew Turner 51eda295b9SAndrew Turner #include <dev/usb/usb_core.h> 52eda295b9SAndrew Turner #include <dev/usb/usb_busdma.h> 53eda295b9SAndrew Turner #include <dev/usb/usb_process.h> 54eda295b9SAndrew Turner #include <dev/usb/usb_util.h> 55eda295b9SAndrew Turner 56eda295b9SAndrew Turner #include <dev/usb/usb_controller.h> 57eda295b9SAndrew Turner #include <dev/usb/usb_bus.h> 58eda295b9SAndrew Turner #include <dev/usb/controller/ehci.h> 59eda295b9SAndrew Turner #include <dev/usb/controller/ehcireg.h> 60eda295b9SAndrew Turner 617a58744fSEmmanuel Vadot #include "generic_ehci.h" 62eda295b9SAndrew Turner 637a58744fSEmmanuel Vadot int 64eda295b9SAndrew Turner generic_ehci_attach(device_t self) 65eda295b9SAndrew Turner { 66eda295b9SAndrew Turner ehci_softc_t *sc = device_get_softc(self); 67eda295b9SAndrew Turner int err; 68eda295b9SAndrew Turner int rid; 69eda295b9SAndrew Turner 70eda295b9SAndrew Turner /* initialise some bus fields */ 71eda295b9SAndrew Turner sc->sc_bus.parent = self; 72eda295b9SAndrew Turner sc->sc_bus.devices = sc->sc_devices; 73eda295b9SAndrew Turner sc->sc_bus.devices_max = EHCI_MAX_DEVICES; 74eda295b9SAndrew Turner sc->sc_bus.dma_bits = 32; 75eda295b9SAndrew Turner 76eda295b9SAndrew Turner /* get all DMA memory */ 77eda295b9SAndrew Turner if (usb_bus_mem_alloc_all(&sc->sc_bus, 78eda295b9SAndrew Turner USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { 79eda295b9SAndrew Turner return (ENOMEM); 80eda295b9SAndrew Turner } 81eda295b9SAndrew Turner 82eda295b9SAndrew Turner sc->sc_bus.usbrev = USB_REV_2_0; 83eda295b9SAndrew Turner 84eda295b9SAndrew Turner rid = 0; 85eda295b9SAndrew Turner sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, 86eda295b9SAndrew Turner RF_ACTIVE); 87eda295b9SAndrew Turner if (!sc->sc_io_res) { 88eda295b9SAndrew Turner device_printf(self, "Could not map memory\n"); 89eda295b9SAndrew Turner goto error; 90eda295b9SAndrew Turner } 91eda295b9SAndrew Turner 92eda295b9SAndrew Turner sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 93eda295b9SAndrew Turner sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 94eda295b9SAndrew Turner sc->sc_io_size = rman_get_size(sc->sc_io_res); 95eda295b9SAndrew Turner 96eda295b9SAndrew Turner rid = 0; 97eda295b9SAndrew Turner sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 98eda295b9SAndrew Turner RF_SHAREABLE | RF_ACTIVE); 99eda295b9SAndrew Turner if (sc->sc_irq_res == NULL) { 100eda295b9SAndrew Turner device_printf(self, "Could not allocate irq\n"); 101eda295b9SAndrew Turner goto error; 102eda295b9SAndrew Turner } 1035b56413dSWarner Losh sc->sc_bus.bdev = device_add_child(self, "usbus", DEVICE_UNIT_ANY); 104eda295b9SAndrew Turner if (!sc->sc_bus.bdev) { 105eda295b9SAndrew Turner device_printf(self, "Could not add USB device\n"); 106eda295b9SAndrew Turner goto error; 107eda295b9SAndrew Turner } 108eda295b9SAndrew Turner device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 109eda295b9SAndrew Turner 110eda295b9SAndrew Turner strlcpy(sc->sc_vendor, "Generic", sizeof(sc->sc_vendor)); 111eda295b9SAndrew Turner 112eda295b9SAndrew Turner err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 113eda295b9SAndrew Turner NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); 114eda295b9SAndrew Turner if (err) { 115eda295b9SAndrew Turner device_printf(self, "Could not setup irq, %d\n", err); 116eda295b9SAndrew Turner sc->sc_intr_hdl = NULL; 117eda295b9SAndrew Turner goto error; 118eda295b9SAndrew Turner } 119eda295b9SAndrew Turner 120eda295b9SAndrew Turner sc->sc_flags |= EHCI_SCFLG_DONTRESET; 121eda295b9SAndrew Turner 122eda295b9SAndrew Turner err = ehci_init(sc); 123eda295b9SAndrew Turner if (!err) 124eda295b9SAndrew Turner err = device_probe_and_attach(sc->sc_bus.bdev); 125eda295b9SAndrew Turner if (err) 126eda295b9SAndrew Turner goto error; 127eda295b9SAndrew Turner 128eda295b9SAndrew Turner return (0); 129eda295b9SAndrew Turner 130eda295b9SAndrew Turner error: 131eda295b9SAndrew Turner generic_ehci_detach(self); 132eda295b9SAndrew Turner return (ENXIO); 133eda295b9SAndrew Turner } 134eda295b9SAndrew Turner 1357a58744fSEmmanuel Vadot int 136eda295b9SAndrew Turner generic_ehci_detach(device_t self) 137eda295b9SAndrew Turner { 138eda295b9SAndrew Turner ehci_softc_t *sc = device_get_softc(self); 139eda295b9SAndrew Turner int err; 140eda295b9SAndrew Turner 141eda295b9SAndrew Turner /* during module unload there are lots of children leftover */ 142*3ddaf820SJohn Baldwin err = bus_generic_detach(self); 143*3ddaf820SJohn Baldwin if (err != 0) 144*3ddaf820SJohn Baldwin return (err); 145eda295b9SAndrew Turner 146eda295b9SAndrew Turner if (sc->sc_irq_res && sc->sc_intr_hdl) { 147eda295b9SAndrew Turner /* 148eda295b9SAndrew Turner * only call ehci_detach() after ehci_init() 149eda295b9SAndrew Turner */ 150eda295b9SAndrew Turner ehci_detach(sc); 151eda295b9SAndrew Turner 152eda295b9SAndrew Turner err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 153eda295b9SAndrew Turner 154eda295b9SAndrew Turner if (err) 155eda295b9SAndrew Turner /* XXX or should we panic? */ 156eda295b9SAndrew Turner device_printf(self, "Could not tear down irq, %d\n", 157eda295b9SAndrew Turner err); 158eda295b9SAndrew Turner sc->sc_intr_hdl = NULL; 159eda295b9SAndrew Turner } 160eda295b9SAndrew Turner 161eda295b9SAndrew Turner if (sc->sc_irq_res) { 162eda295b9SAndrew Turner bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); 163eda295b9SAndrew Turner sc->sc_irq_res = NULL; 164eda295b9SAndrew Turner } 165eda295b9SAndrew Turner if (sc->sc_io_res) { 166eda295b9SAndrew Turner bus_release_resource(self, SYS_RES_MEMORY, 0, 167eda295b9SAndrew Turner sc->sc_io_res); 168eda295b9SAndrew Turner sc->sc_io_res = NULL; 169eda295b9SAndrew Turner } 170eda295b9SAndrew Turner usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); 171eda295b9SAndrew Turner 172eda295b9SAndrew Turner return (0); 173eda295b9SAndrew Turner } 174eda295b9SAndrew Turner 175eda295b9SAndrew Turner static device_method_t ehci_methods[] = { 176eda295b9SAndrew Turner /* Device interface */ 177eda295b9SAndrew Turner DEVMETHOD(device_attach, generic_ehci_attach), 178eda295b9SAndrew Turner DEVMETHOD(device_detach, generic_ehci_detach), 179eda295b9SAndrew Turner DEVMETHOD(device_suspend, bus_generic_suspend), 180eda295b9SAndrew Turner DEVMETHOD(device_resume, bus_generic_resume), 181eda295b9SAndrew Turner DEVMETHOD(device_shutdown, bus_generic_shutdown), 182eda295b9SAndrew Turner 183eda295b9SAndrew Turner DEVMETHOD_END 184eda295b9SAndrew Turner }; 185eda295b9SAndrew Turner 1867a58744fSEmmanuel Vadot driver_t generic_ehci_driver = { 187eda295b9SAndrew Turner .name = "ehci", 188eda295b9SAndrew Turner .methods = ehci_methods, 189eda295b9SAndrew Turner .size = sizeof(ehci_softc_t), 190eda295b9SAndrew Turner }; 191