1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2010-2012 Semihalf
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include "opt_bus.h"
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/bus.h>
39 #include <sys/queue.h>
40 #include <sys/lock.h>
41 #include <sys/lockmgr.h>
42 #include <sys/condvar.h>
43 #include <sys/rman.h>
44
45 #include <dev/ofw/ofw_bus.h>
46 #include <dev/ofw/ofw_bus_subr.h>
47
48 #include <dev/usb/usb.h>
49 #include <dev/usb/usbdi.h>
50 #include <dev/usb/usb_core.h>
51 #include <dev/usb/usb_busdma.h>
52 #include <dev/usb/usb_process.h>
53 #include <dev/usb/usb_util.h>
54 #include <dev/usb/usb_controller.h>
55 #include <dev/usb/usb_bus.h>
56 #include <dev/usb/controller/ehci.h>
57 #include <dev/usb/controller/ehcireg.h>
58
59 #include <machine/bus.h>
60 #include <machine/clock.h>
61 #include <machine/resource.h>
62
63 #include <powerpc/include/tlb.h>
64
65 #include "opt_platform.h"
66
67 /*
68 * Register the driver
69 */
70 /* Forward declarations */
71 static int fsl_ehci_attach(device_t self);
72 static int fsl_ehci_detach(device_t self);
73 static int fsl_ehci_probe(device_t self);
74
75 static device_method_t ehci_methods[] = {
76 /* Device interface */
77 DEVMETHOD(device_probe, fsl_ehci_probe),
78 DEVMETHOD(device_attach, fsl_ehci_attach),
79 DEVMETHOD(device_detach, fsl_ehci_detach),
80 DEVMETHOD(device_suspend, bus_generic_suspend),
81 DEVMETHOD(device_resume, bus_generic_resume),
82 DEVMETHOD(device_shutdown, bus_generic_shutdown),
83
84 /* Bus interface */
85 DEVMETHOD(bus_print_child, bus_generic_print_child),
86 { 0, 0 }
87 };
88
89 /* kobj_class definition */
90 static driver_t ehci_driver = {
91 "ehci",
92 ehci_methods,
93 sizeof(struct ehci_softc)
94 };
95
96 static devclass_t ehci_devclass;
97
98 DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0);
99 MODULE_DEPEND(ehci, usb, 1, 1, 1);
100
101 /*
102 * Private defines
103 */
104 #define FSL_EHCI_REG_OFF 0x100
105 #define FSL_EHCI_REG_SIZE 0x300
106
107 /*
108 * Internal interface registers' offsets.
109 * Offsets from 0x000 ehci dev space, big-endian access.
110 */
111 enum internal_reg {
112 SNOOP1 = 0x400,
113 SNOOP2 = 0x404,
114 AGE_CNT_THRESH = 0x408,
115 SI_CTRL = 0x410,
116 CONTROL = 0x500
117 };
118
119 /* CONTROL register bit flags */
120 enum control_flags {
121 USB_EN = 0x00000004,
122 UTMI_PHY_EN = 0x00000200,
123 ULPI_INT_EN = 0x00000001
124 };
125
126 /* SI_CTRL register bit flags */
127 enum si_ctrl_flags {
128 FETCH_32 = 1,
129 FETCH_64 = 0
130 };
131
132 #define SNOOP_RANGE_2GB 0x1E
133
134 /*
135 * Operational registers' offsets.
136 * Offsets from USBCMD register, little-endian access.
137 */
138 enum special_op_reg {
139 USBMODE = 0x0A8,
140 PORTSC = 0x084,
141 ULPI_VIEWPORT = 0x70
142 };
143
144 /* USBMODE register bit flags */
145 enum usbmode_flags {
146 HOST_MODE = 0x3,
147 DEVICE_MODE = 0x2
148 };
149
150 #define PORT_POWER_MASK 0x00001000
151
152 /*
153 * Private methods
154 */
155
156 static void
set_to_host_mode(ehci_softc_t * sc)157 set_to_host_mode(ehci_softc_t *sc)
158 {
159 int tmp;
160
161 tmp = bus_space_read_4(sc->sc_io_tag, sc->sc_io_hdl, USBMODE);
162 bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, USBMODE, tmp | HOST_MODE);
163 }
164
165 static void
enable_usb(device_t dev,bus_space_tag_t iot,bus_space_handle_t ioh)166 enable_usb(device_t dev, bus_space_tag_t iot, bus_space_handle_t ioh)
167 {
168 int tmp;
169 phandle_t node;
170 char *phy_type;
171
172 phy_type = NULL;
173 tmp = bus_space_read_4(iot, ioh, CONTROL) | USB_EN;
174
175 node = ofw_bus_get_node(dev);
176 if ((node != 0) &&
177 (OF_getprop_alloc(node, "phy_type", (void **)&phy_type) > 0)) {
178 if (strncasecmp(phy_type, "utmi", strlen("utmi")) == 0)
179 tmp |= UTMI_PHY_EN;
180 OF_prop_free(phy_type);
181 }
182 bus_space_write_4(iot, ioh, CONTROL, tmp);
183 }
184
185 static void
set_32b_prefetch(bus_space_tag_t iot,bus_space_handle_t ioh)186 set_32b_prefetch(bus_space_tag_t iot, bus_space_handle_t ioh)
187 {
188
189 bus_space_write_4(iot, ioh, SI_CTRL, FETCH_32);
190 }
191
192 static void
set_snooping(bus_space_tag_t iot,bus_space_handle_t ioh)193 set_snooping(bus_space_tag_t iot, bus_space_handle_t ioh)
194 {
195
196 bus_space_write_4(iot, ioh, SNOOP1, SNOOP_RANGE_2GB);
197 bus_space_write_4(iot, ioh, SNOOP2, 0x80000000 | SNOOP_RANGE_2GB);
198 }
199
200 static void
clear_port_power(ehci_softc_t * sc)201 clear_port_power(ehci_softc_t *sc)
202 {
203 int tmp;
204
205 tmp = bus_space_read_4(sc->sc_io_tag, sc->sc_io_hdl, PORTSC);
206 bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, PORTSC, tmp & ~PORT_POWER_MASK);
207 }
208
209 /*
210 * Public methods
211 */
212 static int
fsl_ehci_probe(device_t dev)213 fsl_ehci_probe(device_t dev)
214 {
215
216 if (!ofw_bus_status_okay(dev))
217 return (ENXIO);
218
219 if (((ofw_bus_is_compatible(dev, "fsl-usb2-dr")) == 0) &&
220 ((ofw_bus_is_compatible(dev, "fsl-usb2-mph")) == 0))
221 return (ENXIO);
222
223 device_set_desc(dev, "Freescale integrated EHCI controller");
224
225 return (BUS_PROBE_DEFAULT);
226 }
227
228 static int
fsl_ehci_attach(device_t self)229 fsl_ehci_attach(device_t self)
230 {
231 ehci_softc_t *sc;
232 int rid;
233 int err;
234 bus_space_handle_t ioh;
235 bus_space_tag_t iot;
236
237 sc = device_get_softc(self);
238 rid = 0;
239
240 sc->sc_bus.parent = self;
241 sc->sc_bus.devices = sc->sc_devices;
242 sc->sc_bus.devices_max = EHCI_MAX_DEVICES;
243 sc->sc_bus.dma_bits = 32;
244
245 if (usb_bus_mem_alloc_all(&sc->sc_bus,
246 USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc))
247 return (ENOMEM);
248
249 /* Allocate io resource for EHCI */
250 sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid,
251 RF_ACTIVE);
252 if (sc->sc_io_res == NULL) {
253 err = fsl_ehci_detach(self);
254 if (err) {
255 device_printf(self,
256 "Detach of the driver failed with error %d\n",
257 err);
258 }
259 return (ENXIO);
260 }
261 iot = rman_get_bustag(sc->sc_io_res);
262
263 /*
264 * Set handle to USB related registers subregion used by generic
265 * EHCI driver
266 */
267 ioh = rman_get_bushandle(sc->sc_io_res);
268
269 err = bus_space_subregion(iot, ioh, FSL_EHCI_REG_OFF, FSL_EHCI_REG_SIZE,
270 &sc->sc_io_hdl);
271 if (err != 0) {
272 err = fsl_ehci_detach(self);
273 if (err) {
274 device_printf(self,
275 "Detach of the driver failed with error %d\n",
276 err);
277 }
278 return (ENXIO);
279 }
280
281 /* Set little-endian tag for use by the generic EHCI driver */
282 sc->sc_io_tag = &bs_le_tag;
283
284 /* Allocate irq */
285 sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
286 RF_ACTIVE);
287 if (sc->sc_irq_res == NULL) {
288 err = fsl_ehci_detach(self);
289 if (err) {
290 device_printf(self,
291 "Detach of the driver failed with error %d\n",
292 err);
293 }
294 return (ENXIO);
295 }
296
297 /* Setup interrupt handler */
298 err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
299 NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
300 if (err) {
301 device_printf(self, "Could not setup irq, %d\n", err);
302 sc->sc_intr_hdl = NULL;
303 err = fsl_ehci_detach(self);
304 if (err) {
305 device_printf(self,
306 "Detach of the driver failed with error %d\n",
307 err);
308 }
309 return (ENXIO);
310 }
311
312 /* Add USB device */
313 sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
314 if (!sc->sc_bus.bdev) {
315 device_printf(self, "Could not add USB device\n");
316 err = fsl_ehci_detach(self);
317 if (err) {
318 device_printf(self,
319 "Detach of the driver failed with error %d\n",
320 err);
321 }
322 return (ENOMEM);
323 }
324 device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
325
326 sc->sc_id_vendor = 0x1234;
327 strlcpy(sc->sc_vendor, "Freescale", sizeof(sc->sc_vendor));
328
329 /* Enable USB */
330 err = ehci_reset(sc);
331 if (err) {
332 device_printf(self, "Could not reset the controller\n");
333 err = fsl_ehci_detach(self);
334 if (err) {
335 device_printf(self,
336 "Detach of the driver failed with error %d\n",
337 err);
338 }
339 return (ENXIO);
340 }
341
342 enable_usb(self, iot, ioh);
343 set_snooping(iot, ioh);
344 set_to_host_mode(sc);
345 set_32b_prefetch(iot, ioh);
346
347 /*
348 * If usb subsystem is enabled in U-Boot, port power has to be turned
349 * off to allow proper discovery of devices during boot up.
350 */
351 clear_port_power(sc);
352
353 /* Set flags */
354 sc->sc_flags |= EHCI_SCFLG_DONTRESET | EHCI_SCFLG_NORESTERM;
355
356 err = ehci_init(sc);
357 if (!err) {
358 sc->sc_flags |= EHCI_SCFLG_DONEINIT;
359 err = device_probe_and_attach(sc->sc_bus.bdev);
360 }
361
362 if (err) {
363 device_printf(self, "USB init failed err=%d\n", err);
364 err = fsl_ehci_detach(self);
365 if (err) {
366 device_printf(self,
367 "Detach of the driver failed with error %d\n",
368 err);
369 }
370 return (EIO);
371 }
372
373 return (0);
374 }
375
376 static int
fsl_ehci_detach(device_t self)377 fsl_ehci_detach(device_t self)
378 {
379
380 int err;
381 ehci_softc_t *sc;
382
383 sc = device_get_softc(self);
384 /*
385 * only call ehci_detach() after ehci_init()
386 */
387 if (sc->sc_flags & EHCI_SCFLG_DONEINIT) {
388 ehci_detach(sc);
389 sc->sc_flags &= ~EHCI_SCFLG_DONEINIT;
390 }
391
392 /* Disable interrupts that might have been switched on in ehci_init */
393 if (sc->sc_io_tag && sc->sc_io_hdl)
394 bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, EHCI_USBINTR, 0);
395
396 if (sc->sc_irq_res && sc->sc_intr_hdl) {
397 err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl);
398 if (err) {
399 device_printf(self, "Could not tear down irq, %d\n",
400 err);
401 return (err);
402 }
403 sc->sc_intr_hdl = NULL;
404 }
405
406 if (sc->sc_bus.bdev) {
407 device_delete_child(self, sc->sc_bus.bdev);
408 sc->sc_bus.bdev = NULL;
409 }
410
411 /* During module unload there are lots of children leftover */
412 device_delete_children(self);
413
414 if (sc->sc_irq_res) {
415 bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res);
416 sc->sc_irq_res = NULL;
417 }
418
419 if (sc->sc_io_res) {
420 bus_release_resource(self, SYS_RES_MEMORY, 0, sc->sc_io_res);
421 sc->sc_io_res = NULL;
422 sc->sc_io_tag = 0;
423 sc->sc_io_hdl = 0;
424 }
425
426 return (0);
427 }
428