• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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