1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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 /*
35 * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller.
36 *
37 * The EHCI 1.0 spec can be found at
38 * http://developer.intel.com/technology/usb/download/ehci-r10.pdf
39 * and the USB 2.0 spec at
40 * http://www.usb.org/developers/docs/usb_20.zip
41 */
42
43 /* The low level controller code for EHCI has been split into
44 * PCI probes and EHCI specific code. This was done to facilitate the
45 * sharing of code between *BSD's
46 */
47
48 #include "implementation/global_implementation.h"
49 #include "controller/ehci.h"
50 #include "controller/ehcireg.h"
51
52 static device_probe_t ehci_pci_probe;
53 static device_attach_t ehci_pci_attach;
54 static device_detach_t ehci_pci_detach;
55 static usb_take_controller_t ehci_pci_take_controller;
56
57 static void
hiehci_post_reset(struct ehci_softc * sc)58 hiehci_post_reset(struct ehci_softc *sc)
59 {
60 uint32_t usb_mode;
61
62 /* Force HOST mode */
63 usb_mode = EOREAD4(sc, EHCI_USBMODE_NOLPM);
64 usb_mode &= ~EHCI_UM_CM;
65 usb_mode |= EHCI_UM_CM_HOST;
66 EOWRITE4(sc, EHCI_USBMODE_NOLPM, usb_mode);
67 }
68
69 static const char *
ehci_pci_match(device_t self)70 ehci_pci_match(device_t self)
71 {
72 return ("EHCI (generic) USB 2.0 controller");
73 }
74
75 static int
ehci_pci_probe(device_t self)76 ehci_pci_probe(device_t self)
77 {
78 const char *desc = ehci_pci_match(self);
79
80 if (desc) {
81 device_set_desc(self, desc);
82 return (BUS_PROBE_DEFAULT);
83 } else {
84 return (ENXIO);
85 }
86 }
87
88 static int
ehci_pci_attach(device_t self)89 ehci_pci_attach(device_t self)
90 {
91 struct resource *res;
92 ehci_softc_t *sc = device_get_softc(self);
93 int err = ENXIO;
94
95 /* initialise some bus fields */
96 sc->sc_bus.parent = self;
97 sc->sc_bus.devices = sc->sc_devices;
98 sc->sc_bus.devices_max = EHCI_MAX_DEVICES;
99 sc->sc_bus.dma_bits = 32;
100 sc->sc_bus.dma_parent_tag[0].dma_bits = 32;
101
102 /* get all DMA memory */
103 if (usb_bus_mem_alloc_all(&sc->sc_bus,
104 USB_GET_DMA_TAG(dev), &ehci_iterate_hw_softc)) {
105 err = ENOMEM;
106 goto error0;
107 }
108
109 res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &unit, 0);
110 if (res == NULL) {
111 goto error;
112 }
113
114 sc->sc_io_res = ioremap(res->start, res->count);
115 if (!sc->sc_io_res) {
116 goto error1;
117 }
118
119 sc->sc_io_tag = (void *)sc->sc_io_res;
120 sc->sc_io_hdl = (bus_space_handle_t)sc->sc_io_res;
121 sc->sc_io_size = res->count;
122
123 sc->sc_flags |= EHCI_SCFLG_DONTRESET;
124
125 /* Setup callbacks. */
126 sc->sc_vendor_post_reset = hiehci_post_reset;
127 sc->sc_vendor_get_port_speed = ehci_get_port_speed_portsc;
128
129 sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
130 if (!sc->sc_bus.bdev) {
131 device_printf(self, "Could not add USB device\n");
132 goto error1;
133 }
134 device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
135
136 /*
137 * ehci_pci_match will never return NULL if ehci_pci_probe
138 * succeeded
139 */
140 device_set_desc(sc->sc_bus.bdev, ehci_pci_match(self));
141
142 res = bus_alloc_resource_any(self, SYS_RES_IRQ, &unit, 0);
143 if (res == NULL) {
144 goto error;
145 }
146 sc->sc_irq_res = res;
147 err = bus_setup_intr(res->start, 0, ehci_interrupt, sc);
148 if (err) {
149 goto error2;
150 }
151
152 ehci_pci_take_controller(self);
153
154 hiusb_start_hcd();
155 hiusb_device2host();
156
157 err = ehci_init(sc);
158 if (!err) {
159 err = device_probe_and_attach(sc->sc_bus.bdev);
160 }
161 if (err) {
162 device_printf(self, "ehci init failed err=%d\n", err);
163 goto error;
164 }
165
166 return (0);
167
168 error:
169 device_printf(self, "ehci attach failed err=%d\n", err);
170 (void)ehci_pci_detach(self);
171 return (err);
172 error2:
173 if (sc->sc_io_res != NULL) {
174 iounmap((void *)sc->sc_io_res);
175 sc->sc_io_res = NULL;
176 }
177 error1:
178 (void)bus_teardown_intr(NUM_HAL_INTERRUPT_USB_EHCI, sc);
179 error0:
180 usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
181 device_printf(self, "ehci attach failed err=%d\n", err);
182 return (err);
183 }
184
185 static int
ehci_pci_detach(device_t self)186 ehci_pci_detach(device_t self)
187 {
188 ehci_softc_t *sc = device_get_softc(self);
189
190 /* during module unload there are lots of children leftover */
191 (void)device_delete_children(dev);
192
193 ehci_detach(sc);
194 hiusb_stop_hcd();
195
196 if (sc->sc_irq_res != NULL) {
197 (void)bus_teardown_intr(sc->sc_irq_res->start, sc);
198 sc->sc_irq_res = NULL;
199 }
200 if (sc->sc_io_res != NULL) {
201 iounmap((void *)sc->sc_io_res);
202 sc->sc_io_res = NULL;
203 sc->sc_io_tag = NULL;
204 sc->sc_io_hdl = (uintptr_t)NULL;
205 sc->sc_io_size = 0;
206 }
207 usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
208
209 return (0);
210 }
211
212 static int
ehci_pci_take_controller(device_t self)213 ehci_pci_take_controller(device_t self)
214 {
215 return (0);
216 }
217
218 static device_method_t ehci_pci_methods[] = {
219 /* Device interface */
220 DEVMETHOD(device_probe, ehci_pci_probe),
221 DEVMETHOD(device_attach, ehci_pci_attach),
222 DEVMETHOD(device_detach, ehci_pci_detach),
223 DEVMETHOD(device_suspend, bus_generic_suspend),
224 DEVMETHOD(device_resume, bus_generic_resume),
225 DEVMETHOD(device_shutdown, bus_generic_shutdown),
226 DEVMETHOD(usb_take_controller, ehci_pci_take_controller),
227
228 DEVMETHOD_END
229 };
230
231 static driver_t ehci_driver = {
232 .name = "ehci",
233 .methods = ehci_pci_methods,
234 .size = sizeof(struct ehci_softc),
235 };
236
237 static devclass_t ehci_devclass;
238
239 DRIVER_MODULE(ehci, nexus, ehci_driver, ehci_devclass, 0, 0);
240
241 int
hiehci_init(void)242 hiehci_init(void)
243 {
244 DPRINTF("hiehci_init");
245 return driver_module_handler(NULL, MOD_LOAD, &ehci_nexus_driver_mod);
246 }
247
248 void
hiehci_exit(void)249 hiehci_exit(void)
250 {
251 DPRINTF("hiehci_exit");
252 (void)driver_module_handler(NULL, MOD_UNLOAD, &ehci_nexus_driver_mod);
253 }
254