1f9f848faSopenharmony_ci/*- 2f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause 3f9f848faSopenharmony_ci * 4f9f848faSopenharmony_ci * Copyright (c) 1998 The NetBSD Foundation, Inc. 5f9f848faSopenharmony_ci * All rights reserved. 6f9f848faSopenharmony_ci * 7f9f848faSopenharmony_ci * This code is derived from software contributed to The NetBSD Foundation 8f9f848faSopenharmony_ci * by Lennart Augustsson (augustss@carlstedt.se) at 9f9f848faSopenharmony_ci * Carlstedt Research & Technology. 10f9f848faSopenharmony_ci * 11f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without 12f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions 13f9f848faSopenharmony_ci * are met: 14f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright 15f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer. 16f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 17f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer in the 18f9f848faSopenharmony_ci * documentation and/or other materials provided with the distribution. 19f9f848faSopenharmony_ci * 20f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21f9f848faSopenharmony_ci * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22f9f848faSopenharmony_ci * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23f9f848faSopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24f9f848faSopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25f9f848faSopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26f9f848faSopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27f9f848faSopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28f9f848faSopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29f9f848faSopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30f9f848faSopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 31f9f848faSopenharmony_ci */ 32f9f848faSopenharmony_ci 33f9f848faSopenharmony_ci#include <sys/cdefs.h> 34f9f848faSopenharmony_ci/* 35f9f848faSopenharmony_ci * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller. 36f9f848faSopenharmony_ci * 37f9f848faSopenharmony_ci * The EHCI 1.0 spec can be found at 38f9f848faSopenharmony_ci * http://developer.intel.com/technology/usb/download/ehci-r10.pdf 39f9f848faSopenharmony_ci * and the USB 2.0 spec at 40f9f848faSopenharmony_ci * http://www.usb.org/developers/docs/usb_20.zip 41f9f848faSopenharmony_ci */ 42f9f848faSopenharmony_ci 43f9f848faSopenharmony_ci/* The low level controller code for EHCI has been split into 44f9f848faSopenharmony_ci * PCI probes and EHCI specific code. This was done to facilitate the 45f9f848faSopenharmony_ci * sharing of code between *BSD's 46f9f848faSopenharmony_ci */ 47f9f848faSopenharmony_ci 48f9f848faSopenharmony_ci#include "implementation/global_implementation.h" 49f9f848faSopenharmony_ci#include "controller/ehci.h" 50f9f848faSopenharmony_ci#include "controller/ehcireg.h" 51f9f848faSopenharmony_ci 52f9f848faSopenharmony_cistatic device_probe_t ehci_pci_probe; 53f9f848faSopenharmony_cistatic device_attach_t ehci_pci_attach; 54f9f848faSopenharmony_cistatic device_detach_t ehci_pci_detach; 55f9f848faSopenharmony_cistatic usb_take_controller_t ehci_pci_take_controller; 56f9f848faSopenharmony_ci 57f9f848faSopenharmony_cistatic void 58f9f848faSopenharmony_cihiehci_post_reset(struct ehci_softc *sc) 59f9f848faSopenharmony_ci{ 60f9f848faSopenharmony_ci uint32_t usb_mode; 61f9f848faSopenharmony_ci 62f9f848faSopenharmony_ci /* Force HOST mode */ 63f9f848faSopenharmony_ci usb_mode = EOREAD4(sc, EHCI_USBMODE_NOLPM); 64f9f848faSopenharmony_ci usb_mode &= ~EHCI_UM_CM; 65f9f848faSopenharmony_ci usb_mode |= EHCI_UM_CM_HOST; 66f9f848faSopenharmony_ci EOWRITE4(sc, EHCI_USBMODE_NOLPM, usb_mode); 67f9f848faSopenharmony_ci} 68f9f848faSopenharmony_ci 69f9f848faSopenharmony_cistatic const char * 70f9f848faSopenharmony_ciehci_pci_match(device_t self) 71f9f848faSopenharmony_ci{ 72f9f848faSopenharmony_ci return ("EHCI (generic) USB 2.0 controller"); 73f9f848faSopenharmony_ci} 74f9f848faSopenharmony_ci 75f9f848faSopenharmony_cistatic int 76f9f848faSopenharmony_ciehci_pci_probe(device_t self) 77f9f848faSopenharmony_ci{ 78f9f848faSopenharmony_ci const char *desc = ehci_pci_match(self); 79f9f848faSopenharmony_ci 80f9f848faSopenharmony_ci if (desc) { 81f9f848faSopenharmony_ci device_set_desc(self, desc); 82f9f848faSopenharmony_ci return (BUS_PROBE_DEFAULT); 83f9f848faSopenharmony_ci } else { 84f9f848faSopenharmony_ci return (ENXIO); 85f9f848faSopenharmony_ci } 86f9f848faSopenharmony_ci} 87f9f848faSopenharmony_ci 88f9f848faSopenharmony_cistatic int 89f9f848faSopenharmony_ciehci_pci_attach(device_t self) 90f9f848faSopenharmony_ci{ 91f9f848faSopenharmony_ci struct resource *res; 92f9f848faSopenharmony_ci ehci_softc_t *sc = device_get_softc(self); 93f9f848faSopenharmony_ci int err = ENXIO; 94f9f848faSopenharmony_ci 95f9f848faSopenharmony_ci /* initialise some bus fields */ 96f9f848faSopenharmony_ci sc->sc_bus.parent = self; 97f9f848faSopenharmony_ci sc->sc_bus.devices = sc->sc_devices; 98f9f848faSopenharmony_ci sc->sc_bus.devices_max = EHCI_MAX_DEVICES; 99f9f848faSopenharmony_ci sc->sc_bus.dma_bits = 32; 100f9f848faSopenharmony_ci sc->sc_bus.dma_parent_tag[0].dma_bits = 32; 101f9f848faSopenharmony_ci 102f9f848faSopenharmony_ci /* get all DMA memory */ 103f9f848faSopenharmony_ci if (usb_bus_mem_alloc_all(&sc->sc_bus, 104f9f848faSopenharmony_ci USB_GET_DMA_TAG(dev), &ehci_iterate_hw_softc)) { 105f9f848faSopenharmony_ci err = ENOMEM; 106f9f848faSopenharmony_ci goto error0; 107f9f848faSopenharmony_ci } 108f9f848faSopenharmony_ci 109f9f848faSopenharmony_ci res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &unit, 0); 110f9f848faSopenharmony_ci if (res == NULL) { 111f9f848faSopenharmony_ci goto error; 112f9f848faSopenharmony_ci } 113f9f848faSopenharmony_ci 114f9f848faSopenharmony_ci sc->sc_io_res = ioremap(res->start, res->count); 115f9f848faSopenharmony_ci if (!sc->sc_io_res) { 116f9f848faSopenharmony_ci goto error1; 117f9f848faSopenharmony_ci } 118f9f848faSopenharmony_ci 119f9f848faSopenharmony_ci sc->sc_io_tag = (void *)sc->sc_io_res; 120f9f848faSopenharmony_ci sc->sc_io_hdl = (bus_space_handle_t)sc->sc_io_res; 121f9f848faSopenharmony_ci sc->sc_io_size = res->count; 122f9f848faSopenharmony_ci 123f9f848faSopenharmony_ci sc->sc_flags |= EHCI_SCFLG_DONTRESET; 124f9f848faSopenharmony_ci 125f9f848faSopenharmony_ci /* Setup callbacks. */ 126f9f848faSopenharmony_ci sc->sc_vendor_post_reset = hiehci_post_reset; 127f9f848faSopenharmony_ci sc->sc_vendor_get_port_speed = ehci_get_port_speed_portsc; 128f9f848faSopenharmony_ci 129f9f848faSopenharmony_ci sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 130f9f848faSopenharmony_ci if (!sc->sc_bus.bdev) { 131f9f848faSopenharmony_ci device_printf(self, "Could not add USB device\n"); 132f9f848faSopenharmony_ci goto error1; 133f9f848faSopenharmony_ci } 134f9f848faSopenharmony_ci device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 135f9f848faSopenharmony_ci 136f9f848faSopenharmony_ci /* 137f9f848faSopenharmony_ci * ehci_pci_match will never return NULL if ehci_pci_probe 138f9f848faSopenharmony_ci * succeeded 139f9f848faSopenharmony_ci */ 140f9f848faSopenharmony_ci device_set_desc(sc->sc_bus.bdev, ehci_pci_match(self)); 141f9f848faSopenharmony_ci 142f9f848faSopenharmony_ci res = bus_alloc_resource_any(self, SYS_RES_IRQ, &unit, 0); 143f9f848faSopenharmony_ci if (res == NULL) { 144f9f848faSopenharmony_ci goto error; 145f9f848faSopenharmony_ci } 146f9f848faSopenharmony_ci sc->sc_irq_res = res; 147f9f848faSopenharmony_ci err = bus_setup_intr(res->start, 0, ehci_interrupt, sc); 148f9f848faSopenharmony_ci if (err) { 149f9f848faSopenharmony_ci goto error2; 150f9f848faSopenharmony_ci } 151f9f848faSopenharmony_ci 152f9f848faSopenharmony_ci ehci_pci_take_controller(self); 153f9f848faSopenharmony_ci 154f9f848faSopenharmony_ci hiusb_start_hcd(); 155f9f848faSopenharmony_ci hiusb_device2host(); 156f9f848faSopenharmony_ci 157f9f848faSopenharmony_ci err = ehci_init(sc); 158f9f848faSopenharmony_ci if (!err) { 159f9f848faSopenharmony_ci err = device_probe_and_attach(sc->sc_bus.bdev); 160f9f848faSopenharmony_ci } 161f9f848faSopenharmony_ci if (err) { 162f9f848faSopenharmony_ci device_printf(self, "ehci init failed err=%d\n", err); 163f9f848faSopenharmony_ci goto error; 164f9f848faSopenharmony_ci } 165f9f848faSopenharmony_ci 166f9f848faSopenharmony_ci return (0); 167f9f848faSopenharmony_ci 168f9f848faSopenharmony_cierror: 169f9f848faSopenharmony_ci device_printf(self, "ehci attach failed err=%d\n", err); 170f9f848faSopenharmony_ci (void)ehci_pci_detach(self); 171f9f848faSopenharmony_ci return (err); 172f9f848faSopenharmony_cierror2: 173f9f848faSopenharmony_ci if (sc->sc_io_res != NULL) { 174f9f848faSopenharmony_ci iounmap((void *)sc->sc_io_res); 175f9f848faSopenharmony_ci sc->sc_io_res = NULL; 176f9f848faSopenharmony_ci } 177f9f848faSopenharmony_cierror1: 178f9f848faSopenharmony_ci (void)bus_teardown_intr(NUM_HAL_INTERRUPT_USB_EHCI, sc); 179f9f848faSopenharmony_cierror0: 180f9f848faSopenharmony_ci usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); 181f9f848faSopenharmony_ci device_printf(self, "ehci attach failed err=%d\n", err); 182f9f848faSopenharmony_ci return (err); 183f9f848faSopenharmony_ci} 184f9f848faSopenharmony_ci 185f9f848faSopenharmony_cistatic int 186f9f848faSopenharmony_ciehci_pci_detach(device_t self) 187f9f848faSopenharmony_ci{ 188f9f848faSopenharmony_ci ehci_softc_t *sc = device_get_softc(self); 189f9f848faSopenharmony_ci 190f9f848faSopenharmony_ci /* during module unload there are lots of children leftover */ 191f9f848faSopenharmony_ci (void)device_delete_children(dev); 192f9f848faSopenharmony_ci 193f9f848faSopenharmony_ci ehci_detach(sc); 194f9f848faSopenharmony_ci hiusb_stop_hcd(); 195f9f848faSopenharmony_ci 196f9f848faSopenharmony_ci if (sc->sc_irq_res != NULL) { 197f9f848faSopenharmony_ci (void)bus_teardown_intr(sc->sc_irq_res->start, sc); 198f9f848faSopenharmony_ci sc->sc_irq_res = NULL; 199f9f848faSopenharmony_ci } 200f9f848faSopenharmony_ci if (sc->sc_io_res != NULL) { 201f9f848faSopenharmony_ci iounmap((void *)sc->sc_io_res); 202f9f848faSopenharmony_ci sc->sc_io_res = NULL; 203f9f848faSopenharmony_ci sc->sc_io_tag = NULL; 204f9f848faSopenharmony_ci sc->sc_io_hdl = (uintptr_t)NULL; 205f9f848faSopenharmony_ci sc->sc_io_size = 0; 206f9f848faSopenharmony_ci } 207f9f848faSopenharmony_ci usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); 208f9f848faSopenharmony_ci 209f9f848faSopenharmony_ci return (0); 210f9f848faSopenharmony_ci} 211f9f848faSopenharmony_ci 212f9f848faSopenharmony_cistatic int 213f9f848faSopenharmony_ciehci_pci_take_controller(device_t self) 214f9f848faSopenharmony_ci{ 215f9f848faSopenharmony_ci return (0); 216f9f848faSopenharmony_ci} 217f9f848faSopenharmony_ci 218f9f848faSopenharmony_cistatic device_method_t ehci_pci_methods[] = { 219f9f848faSopenharmony_ci /* Device interface */ 220f9f848faSopenharmony_ci DEVMETHOD(device_probe, ehci_pci_probe), 221f9f848faSopenharmony_ci DEVMETHOD(device_attach, ehci_pci_attach), 222f9f848faSopenharmony_ci DEVMETHOD(device_detach, ehci_pci_detach), 223f9f848faSopenharmony_ci DEVMETHOD(device_suspend, bus_generic_suspend), 224f9f848faSopenharmony_ci DEVMETHOD(device_resume, bus_generic_resume), 225f9f848faSopenharmony_ci DEVMETHOD(device_shutdown, bus_generic_shutdown), 226f9f848faSopenharmony_ci DEVMETHOD(usb_take_controller, ehci_pci_take_controller), 227f9f848faSopenharmony_ci 228f9f848faSopenharmony_ci DEVMETHOD_END 229f9f848faSopenharmony_ci}; 230f9f848faSopenharmony_ci 231f9f848faSopenharmony_cistatic driver_t ehci_driver = { 232f9f848faSopenharmony_ci .name = "ehci", 233f9f848faSopenharmony_ci .methods = ehci_pci_methods, 234f9f848faSopenharmony_ci .size = sizeof(struct ehci_softc), 235f9f848faSopenharmony_ci}; 236f9f848faSopenharmony_ci 237f9f848faSopenharmony_cistatic devclass_t ehci_devclass; 238f9f848faSopenharmony_ci 239f9f848faSopenharmony_ciDRIVER_MODULE(ehci, nexus, ehci_driver, ehci_devclass, 0, 0); 240f9f848faSopenharmony_ci 241f9f848faSopenharmony_ciint 242f9f848faSopenharmony_cihiehci_init(void) 243f9f848faSopenharmony_ci{ 244f9f848faSopenharmony_ci DPRINTF("hiehci_init"); 245f9f848faSopenharmony_ci return driver_module_handler(NULL, MOD_LOAD, &ehci_nexus_driver_mod); 246f9f848faSopenharmony_ci} 247f9f848faSopenharmony_ci 248f9f848faSopenharmony_civoid 249f9f848faSopenharmony_cihiehci_exit(void) 250f9f848faSopenharmony_ci{ 251f9f848faSopenharmony_ci DPRINTF("hiehci_exit"); 252f9f848faSopenharmony_ci (void)driver_module_handler(NULL, MOD_UNLOAD, &ehci_nexus_driver_mod); 253f9f848faSopenharmony_ci} 254