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