• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
hiehci_post_reset(struct ehci_softc * sc)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 *
ehci_pci_match(device_t self)72 ehci_pci_match(device_t self)
73 {
74 	return ("EHCI (generic) USB 2.0 controller");
75 }
76 
77 static int
ehci_pci_probe(device_t self)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
ehci_pci_attach(device_t self)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
ehci_pci_detach(device_t self)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
ehci_pci_take_controller(device_t self)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
hiehci_init(void)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
hiehci_exit(void)251 hiehci_exit(void)
252 {
253 	DPRINTF("hiehci_exit");
254 	(void)driver_module_handler(NULL, MOD_UNLOAD, &ehci_nexus_driver_mod);
255 }
256