xref: /freebsd/sys/dev/usb/controller/ehci_mv.c (revision ca48e43ba9ee73a07cdbad8365117793b01273bb)
1db5ef4fcSRafal Jaworowski /*-
27282444bSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
37282444bSPedro F. Giffuni  *
4db5ef4fcSRafal Jaworowski  * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
5db5ef4fcSRafal Jaworowski  * All rights reserved.
6db5ef4fcSRafal Jaworowski  *
7db5ef4fcSRafal Jaworowski  * Developed by Semihalf.
8db5ef4fcSRafal Jaworowski  *
9db5ef4fcSRafal Jaworowski  * Redistribution and use in source and binary forms, with or without
10db5ef4fcSRafal Jaworowski  * modification, are permitted provided that the following conditions
11db5ef4fcSRafal Jaworowski  * are met:
12db5ef4fcSRafal Jaworowski  * 1. Redistributions of source code must retain the above copyright
13db5ef4fcSRafal Jaworowski  *    notice, this list of conditions and the following disclaimer.
14db5ef4fcSRafal Jaworowski  * 2. Redistributions in binary form must reproduce the above copyright
15db5ef4fcSRafal Jaworowski  *    notice, this list of conditions and the following disclaimer in the
16db5ef4fcSRafal Jaworowski  *    documentation and/or other materials provided with the distribution.
17db5ef4fcSRafal Jaworowski  * 3. Neither the name of MARVELL nor the names of contributors
18db5ef4fcSRafal Jaworowski  *    may be used to endorse or promote products derived from this software
19db5ef4fcSRafal Jaworowski  *    without specific prior written permission.
20db5ef4fcSRafal Jaworowski  *
21db5ef4fcSRafal Jaworowski  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22db5ef4fcSRafal Jaworowski  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23db5ef4fcSRafal Jaworowski  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24db5ef4fcSRafal Jaworowski  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
25db5ef4fcSRafal Jaworowski  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26db5ef4fcSRafal Jaworowski  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27db5ef4fcSRafal Jaworowski  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28db5ef4fcSRafal Jaworowski  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29db5ef4fcSRafal Jaworowski  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30db5ef4fcSRafal Jaworowski  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31db5ef4fcSRafal Jaworowski  * SUCH DAMAGE.
32db5ef4fcSRafal Jaworowski  */
33db5ef4fcSRafal Jaworowski 
34db5ef4fcSRafal Jaworowski /*
35db5ef4fcSRafal Jaworowski  * FDT attachment driver for the USB Enhanced Host Controller.
36db5ef4fcSRafal Jaworowski  */
37db5ef4fcSRafal Jaworowski 
38db5ef4fcSRafal Jaworowski #include "opt_bus.h"
39db5ef4fcSRafal Jaworowski 
40db5ef4fcSRafal Jaworowski #include <sys/stdint.h>
41db5ef4fcSRafal Jaworowski #include <sys/stddef.h>
42db5ef4fcSRafal Jaworowski #include <sys/param.h>
43db5ef4fcSRafal Jaworowski #include <sys/queue.h>
44db5ef4fcSRafal Jaworowski #include <sys/types.h>
45db5ef4fcSRafal Jaworowski #include <sys/systm.h>
46db5ef4fcSRafal Jaworowski #include <sys/kernel.h>
47db5ef4fcSRafal Jaworowski #include <sys/bus.h>
48db5ef4fcSRafal Jaworowski #include <sys/module.h>
49db5ef4fcSRafal Jaworowski #include <sys/lock.h>
50db5ef4fcSRafal Jaworowski #include <sys/mutex.h>
51db5ef4fcSRafal Jaworowski #include <sys/condvar.h>
52db5ef4fcSRafal Jaworowski #include <sys/sysctl.h>
53db5ef4fcSRafal Jaworowski #include <sys/sx.h>
54db5ef4fcSRafal Jaworowski #include <sys/unistd.h>
55db5ef4fcSRafal Jaworowski #include <sys/callout.h>
56db5ef4fcSRafal Jaworowski #include <sys/malloc.h>
57db5ef4fcSRafal Jaworowski #include <sys/priv.h>
58db5ef4fcSRafal Jaworowski 
59db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus.h>
60db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h>
61db5ef4fcSRafal Jaworowski 
62db5ef4fcSRafal Jaworowski #include <dev/usb/usb.h>
63db5ef4fcSRafal Jaworowski #include <dev/usb/usbdi.h>
64db5ef4fcSRafal Jaworowski 
65db5ef4fcSRafal Jaworowski #include <dev/usb/usb_core.h>
66db5ef4fcSRafal Jaworowski #include <dev/usb/usb_busdma.h>
67db5ef4fcSRafal Jaworowski #include <dev/usb/usb_process.h>
68db5ef4fcSRafal Jaworowski #include <dev/usb/usb_util.h>
69db5ef4fcSRafal Jaworowski 
70db5ef4fcSRafal Jaworowski #include <dev/usb/usb_controller.h>
71db5ef4fcSRafal Jaworowski #include <dev/usb/usb_bus.h>
72db5ef4fcSRafal Jaworowski #include <dev/usb/controller/ehci.h>
73db5ef4fcSRafal Jaworowski #include <dev/usb/controller/ehcireg.h>
74db5ef4fcSRafal Jaworowski 
756c2c6106SMarcin Wojtas #if !defined(__aarch64__)
76db5ef4fcSRafal Jaworowski #include <arm/mv/mvreg.h>
776c2c6106SMarcin Wojtas #endif
78db5ef4fcSRafal Jaworowski #include <arm/mv/mvvar.h>
79db5ef4fcSRafal Jaworowski 
80db5ef4fcSRafal Jaworowski #define	EHCI_VENDORID_MRVL	0x1286
81db5ef4fcSRafal Jaworowski #define	EHCI_HC_DEVSTR		"Marvell Integrated USB 2.0 controller"
82db5ef4fcSRafal Jaworowski 
83db5ef4fcSRafal Jaworowski static device_attach_t mv_ehci_attach;
84db5ef4fcSRafal Jaworowski static device_detach_t mv_ehci_detach;
85db5ef4fcSRafal Jaworowski 
86db5ef4fcSRafal Jaworowski static int err_intr(void *arg);
87db5ef4fcSRafal Jaworowski 
88db5ef4fcSRafal Jaworowski static struct resource *irq_err;
89db5ef4fcSRafal Jaworowski static void *ih_err;
90db5ef4fcSRafal Jaworowski 
91db5ef4fcSRafal Jaworowski /* EHCI HC regs start at this offset within USB range */
92db5ef4fcSRafal Jaworowski #define	MV_USB_HOST_OFST	0x0100
93db5ef4fcSRafal Jaworowski 
94db5ef4fcSRafal Jaworowski #define	USB_BRIDGE_INTR_CAUSE	0x210
95db5ef4fcSRafal Jaworowski #define	USB_BRIDGE_INTR_MASK	0x214
966a9f4949SMarcel Moolenaar #define	USB_BRIDGE_ERR_ADDR	0x21C
97db5ef4fcSRafal Jaworowski 
98db5ef4fcSRafal Jaworowski #define	MV_USB_ADDR_DECODE_ERR (1 << 0)
99db5ef4fcSRafal Jaworowski #define	MV_USB_HOST_UNDERFLOW  (1 << 1)
100db5ef4fcSRafal Jaworowski #define	MV_USB_HOST_OVERFLOW   (1 << 2)
101db5ef4fcSRafal Jaworowski #define	MV_USB_DEVICE_UNDERFLOW (1 << 3)
102db5ef4fcSRafal Jaworowski 
103be2d15eaSMarcin Wojtas enum mv_ehci_hwtype {
104be2d15eaSMarcin Wojtas 	HWTYPE_NONE = 0,
105be2d15eaSMarcin Wojtas 	HWTYPE_MV_EHCI_V1,
106be2d15eaSMarcin Wojtas 	HWTYPE_MV_EHCI_V2,
107be2d15eaSMarcin Wojtas };
108be2d15eaSMarcin Wojtas 
1095c8fae40SZbigniew Bodek static struct ofw_compat_data compat_data[] = {
110be2d15eaSMarcin Wojtas 	{"mrvl,usb-ehci",		HWTYPE_MV_EHCI_V1},
111be2d15eaSMarcin Wojtas 	{"marvell,orion-ehci",		HWTYPE_MV_EHCI_V2},
112be2d15eaSMarcin Wojtas 	{"marvell,armada-3700-ehci",	HWTYPE_MV_EHCI_V2},
113be2d15eaSMarcin Wojtas 	{NULL,				HWTYPE_NONE}
1145c8fae40SZbigniew Bodek };
1155c8fae40SZbigniew Bodek 
116cdf4ec68SMichal Meloun static void
mv_ehci_post_reset(struct ehci_softc * ehci_softc)117cdf4ec68SMichal Meloun mv_ehci_post_reset(struct ehci_softc *ehci_softc)
118cdf4ec68SMichal Meloun {
119cdf4ec68SMichal Meloun 	uint32_t usbmode;
120cdf4ec68SMichal Meloun 
121cdf4ec68SMichal Meloun 	/* Force HOST mode */
122cdf4ec68SMichal Meloun 	usbmode = EOREAD4(ehci_softc, EHCI_USBMODE_NOLPM);
123cdf4ec68SMichal Meloun 	usbmode &= ~EHCI_UM_CM;
124cdf4ec68SMichal Meloun 	usbmode |= EHCI_UM_CM_HOST;
125cdf4ec68SMichal Meloun 	EOWRITE4(ehci_softc, EHCI_USBMODE_NOLPM, usbmode);
126cdf4ec68SMichal Meloun }
127cdf4ec68SMichal Meloun 
128db5ef4fcSRafal Jaworowski static int
mv_ehci_probe(device_t self)129db5ef4fcSRafal Jaworowski mv_ehci_probe(device_t self)
130db5ef4fcSRafal Jaworowski {
131db5ef4fcSRafal Jaworowski 
132add35ed5SIan Lepore 	if (!ofw_bus_status_okay(self))
133add35ed5SIan Lepore 		return (ENXIO);
134add35ed5SIan Lepore 
1355c8fae40SZbigniew Bodek 	if (!ofw_bus_search_compatible(self, compat_data)->ocd_data)
136db5ef4fcSRafal Jaworowski 		return (ENXIO);
137db5ef4fcSRafal Jaworowski 
138db5ef4fcSRafal Jaworowski 	device_set_desc(self, EHCI_HC_DEVSTR);
139db5ef4fcSRafal Jaworowski 
140db5ef4fcSRafal Jaworowski 	return (BUS_PROBE_DEFAULT);
141db5ef4fcSRafal Jaworowski }
142db5ef4fcSRafal Jaworowski 
143db5ef4fcSRafal Jaworowski static int
mv_ehci_attach(device_t self)144db5ef4fcSRafal Jaworowski mv_ehci_attach(device_t self)
145db5ef4fcSRafal Jaworowski {
146db5ef4fcSRafal Jaworowski 	ehci_softc_t *sc = device_get_softc(self);
147be2d15eaSMarcin Wojtas 	enum mv_ehci_hwtype hwtype;
148db5ef4fcSRafal Jaworowski 	bus_space_handle_t bsh;
149db5ef4fcSRafal Jaworowski 	int err;
150db5ef4fcSRafal Jaworowski 	int rid;
151db5ef4fcSRafal Jaworowski 
152db5ef4fcSRafal Jaworowski 	/* initialise some bus fields */
153db5ef4fcSRafal Jaworowski 	sc->sc_bus.parent = self;
154db5ef4fcSRafal Jaworowski 	sc->sc_bus.devices = sc->sc_devices;
155db5ef4fcSRafal Jaworowski 	sc->sc_bus.devices_max = EHCI_MAX_DEVICES;
156b217d184SHans Petter Selasky 	sc->sc_bus.dma_bits = 32;
157db5ef4fcSRafal Jaworowski 
158be2d15eaSMarcin Wojtas 	hwtype = ofw_bus_search_compatible(self, compat_data)->ocd_data;
159be2d15eaSMarcin Wojtas 	if (hwtype == HWTYPE_NONE) {
160be2d15eaSMarcin Wojtas 		device_printf(self, "Wrong HW type flag detected\n");
161be2d15eaSMarcin Wojtas 		return (ENXIO);
162be2d15eaSMarcin Wojtas 	}
163be2d15eaSMarcin Wojtas 
164db5ef4fcSRafal Jaworowski 	/* get all DMA memory */
165db5ef4fcSRafal Jaworowski 	if (usb_bus_mem_alloc_all(&sc->sc_bus,
166db5ef4fcSRafal Jaworowski 	    USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) {
167db5ef4fcSRafal Jaworowski 		return (ENOMEM);
168db5ef4fcSRafal Jaworowski 	}
169db5ef4fcSRafal Jaworowski 
170db5ef4fcSRafal Jaworowski 	rid = 0;
171db5ef4fcSRafal Jaworowski 	sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE);
172db5ef4fcSRafal Jaworowski 	if (!sc->sc_io_res) {
173db5ef4fcSRafal Jaworowski 		device_printf(self, "Could not map memory\n");
174db5ef4fcSRafal Jaworowski 		goto error;
175db5ef4fcSRafal Jaworowski 	}
176db5ef4fcSRafal Jaworowski 	sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
177db5ef4fcSRafal Jaworowski 	bsh = rman_get_bushandle(sc->sc_io_res);
178db5ef4fcSRafal Jaworowski 	sc->sc_io_size = rman_get_size(sc->sc_io_res) - MV_USB_HOST_OFST;
179db5ef4fcSRafal Jaworowski 
180db5ef4fcSRafal Jaworowski 	/*
181db5ef4fcSRafal Jaworowski 	 * Marvell EHCI host controller registers start at certain offset
182db5ef4fcSRafal Jaworowski 	 * within the whole USB registers range, so create a subregion for the
183db5ef4fcSRafal Jaworowski 	 * host mode configuration purposes.
184db5ef4fcSRafal Jaworowski 	 */
185db5ef4fcSRafal Jaworowski 
186db5ef4fcSRafal Jaworowski 	if (bus_space_subregion(sc->sc_io_tag, bsh, MV_USB_HOST_OFST,
187db5ef4fcSRafal Jaworowski 	    sc->sc_io_size, &sc->sc_io_hdl) != 0)
188db5ef4fcSRafal Jaworowski 		panic("%s: unable to subregion USB host registers",
189db5ef4fcSRafal Jaworowski 		    device_get_name(self));
190db5ef4fcSRafal Jaworowski 
191db5ef4fcSRafal Jaworowski 	rid = 0;
192be2d15eaSMarcin Wojtas 	if (hwtype == HWTYPE_MV_EHCI_V1) {
193db5ef4fcSRafal Jaworowski 		irq_err = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
194db5ef4fcSRafal Jaworowski 		    RF_SHAREABLE | RF_ACTIVE);
195db5ef4fcSRafal Jaworowski 		if (irq_err == NULL) {
196db5ef4fcSRafal Jaworowski 			device_printf(self, "Could not allocate error irq\n");
197db5ef4fcSRafal Jaworowski 			mv_ehci_detach(self);
198db5ef4fcSRafal Jaworowski 			return (ENXIO);
199db5ef4fcSRafal Jaworowski 		}
2005c8fae40SZbigniew Bodek 		rid = 1;
2015c8fae40SZbigniew Bodek 	}
202db5ef4fcSRafal Jaworowski 
203db5ef4fcSRafal Jaworowski 	/*
204db5ef4fcSRafal Jaworowski 	 * Notice: Marvell EHCI controller has TWO interrupt lines, so make
205db5ef4fcSRafal Jaworowski 	 * sure to use the correct rid for the main one (controller interrupt)
206db5ef4fcSRafal Jaworowski 	 * -- refer to DTS for the right resource number to use here.
207db5ef4fcSRafal Jaworowski 	 */
208db5ef4fcSRafal Jaworowski 	sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
209db5ef4fcSRafal Jaworowski 	    RF_SHAREABLE | RF_ACTIVE);
210db5ef4fcSRafal Jaworowski 	if (sc->sc_irq_res == NULL) {
211db5ef4fcSRafal Jaworowski 		device_printf(self, "Could not allocate irq\n");
212db5ef4fcSRafal Jaworowski 		goto error;
213db5ef4fcSRafal Jaworowski 	}
214db5ef4fcSRafal Jaworowski 
2155b56413dSWarner Losh 	sc->sc_bus.bdev = device_add_child(self, "usbus", DEVICE_UNIT_ANY);
216db5ef4fcSRafal Jaworowski 	if (!sc->sc_bus.bdev) {
217db5ef4fcSRafal Jaworowski 		device_printf(self, "Could not add USB device\n");
218db5ef4fcSRafal Jaworowski 		goto error;
219db5ef4fcSRafal Jaworowski 	}
220db5ef4fcSRafal Jaworowski 	device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
221db5ef4fcSRafal Jaworowski 	device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR);
222db5ef4fcSRafal Jaworowski 
223db5ef4fcSRafal Jaworowski 	sprintf(sc->sc_vendor, "Marvell");
224db5ef4fcSRafal Jaworowski 
225be2d15eaSMarcin Wojtas 	if (hwtype == HWTYPE_MV_EHCI_V1) {
226c305730dSJohn Baldwin 		err = bus_setup_intr(self, irq_err, INTR_TYPE_BIO,
227db5ef4fcSRafal Jaworowski 		    err_intr, NULL, sc, &ih_err);
228db5ef4fcSRafal Jaworowski 		if (err) {
229db5ef4fcSRafal Jaworowski 			device_printf(self, "Could not setup error irq, %d\n", err);
230db5ef4fcSRafal Jaworowski 			ih_err = NULL;
231db5ef4fcSRafal Jaworowski 			goto error;
232db5ef4fcSRafal Jaworowski 		}
2335c8fae40SZbigniew Bodek 	}
234db5ef4fcSRafal Jaworowski 
235db5ef4fcSRafal Jaworowski 	EWRITE4(sc, USB_BRIDGE_INTR_MASK, MV_USB_ADDR_DECODE_ERR |
236db5ef4fcSRafal Jaworowski 	    MV_USB_HOST_UNDERFLOW | MV_USB_HOST_OVERFLOW |
237db5ef4fcSRafal Jaworowski 	    MV_USB_DEVICE_UNDERFLOW);
238db5ef4fcSRafal Jaworowski 
239db5ef4fcSRafal Jaworowski 	err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
240db5ef4fcSRafal Jaworowski 	    NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
241db5ef4fcSRafal Jaworowski 	if (err) {
242db5ef4fcSRafal Jaworowski 		device_printf(self, "Could not setup irq, %d\n", err);
243db5ef4fcSRafal Jaworowski 		sc->sc_intr_hdl = NULL;
244db5ef4fcSRafal Jaworowski 		goto error;
245db5ef4fcSRafal Jaworowski 	}
246db5ef4fcSRafal Jaworowski 
247db5ef4fcSRafal Jaworowski 	/*
248db5ef4fcSRafal Jaworowski 	 * Workaround for Marvell integrated EHCI controller: reset of
249db5ef4fcSRafal Jaworowski 	 * the EHCI core clears the USBMODE register, which sets the core in
250db5ef4fcSRafal Jaworowski 	 * an undefined state (neither host nor agent), so it needs to be set
251db5ef4fcSRafal Jaworowski 	 * again for proper operation.
252db5ef4fcSRafal Jaworowski 	 *
253db5ef4fcSRafal Jaworowski 	 * Refer to errata document MV-S500832-00D.pdf (p. 5.24 GL USB-2) for
254db5ef4fcSRafal Jaworowski 	 * details.
255db5ef4fcSRafal Jaworowski 	 */
256cdf4ec68SMichal Meloun 	sc->sc_vendor_post_reset = mv_ehci_post_reset;
257db5ef4fcSRafal Jaworowski 	if (bootverbose)
258db5ef4fcSRafal Jaworowski 		device_printf(self, "5.24 GL USB-2 workaround enabled\n");
259db5ef4fcSRafal Jaworowski 
260db5ef4fcSRafal Jaworowski 	/* XXX all MV chips need it? */
261cdf4ec68SMichal Meloun 	sc->sc_flags |= EHCI_SCFLG_TT | EHCI_SCFLG_NORESTERM;
262cdf4ec68SMichal Meloun 	sc->sc_vendor_get_port_speed = ehci_get_port_speed_portsc;
263db5ef4fcSRafal Jaworowski 	err = ehci_init(sc);
264db5ef4fcSRafal Jaworowski 	if (!err) {
265db5ef4fcSRafal Jaworowski 		err = device_probe_and_attach(sc->sc_bus.bdev);
266db5ef4fcSRafal Jaworowski 	}
267db5ef4fcSRafal Jaworowski 	if (err) {
268db5ef4fcSRafal Jaworowski 		device_printf(self, "USB init failed err=%d\n", err);
269db5ef4fcSRafal Jaworowski 		goto error;
270db5ef4fcSRafal Jaworowski 	}
271db5ef4fcSRafal Jaworowski 	return (0);
272db5ef4fcSRafal Jaworowski 
273db5ef4fcSRafal Jaworowski error:
274db5ef4fcSRafal Jaworowski 	mv_ehci_detach(self);
275db5ef4fcSRafal Jaworowski 	return (ENXIO);
276db5ef4fcSRafal Jaworowski }
277db5ef4fcSRafal Jaworowski 
278db5ef4fcSRafal Jaworowski static int
mv_ehci_detach(device_t self)279db5ef4fcSRafal Jaworowski mv_ehci_detach(device_t self)
280db5ef4fcSRafal Jaworowski {
281db5ef4fcSRafal Jaworowski 	ehci_softc_t *sc = device_get_softc(self);
282db5ef4fcSRafal Jaworowski 	int err;
283db5ef4fcSRafal Jaworowski 
284db5ef4fcSRafal Jaworowski 	/* during module unload there are lots of children leftover */
285*3ddaf820SJohn Baldwin 	err = bus_generic_detach(self);
286*3ddaf820SJohn Baldwin 	if (err != 0)
287*3ddaf820SJohn Baldwin 		return (err);
288db5ef4fcSRafal Jaworowski 
289db5ef4fcSRafal Jaworowski 	/*
290b0a5e05fSHans Petter Selasky 	 * disable interrupts that might have been switched on in mv_ehci_attach
291db5ef4fcSRafal Jaworowski 	 */
292db5ef4fcSRafal Jaworowski 	if (sc->sc_io_res) {
293db5ef4fcSRafal Jaworowski 		EWRITE4(sc, USB_BRIDGE_INTR_MASK, 0);
294db5ef4fcSRafal Jaworowski 	}
295db5ef4fcSRafal Jaworowski 	if (sc->sc_irq_res && sc->sc_intr_hdl) {
296db5ef4fcSRafal Jaworowski 		/*
297db5ef4fcSRafal Jaworowski 		 * only call ehci_detach() after ehci_init()
298db5ef4fcSRafal Jaworowski 		 */
299db5ef4fcSRafal Jaworowski 		ehci_detach(sc);
300db5ef4fcSRafal Jaworowski 
301db5ef4fcSRafal Jaworowski 		err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl);
302db5ef4fcSRafal Jaworowski 
303db5ef4fcSRafal Jaworowski 		if (err)
304db5ef4fcSRafal Jaworowski 			/* XXX or should we panic? */
305db5ef4fcSRafal Jaworowski 			device_printf(self, "Could not tear down irq, %d\n",
306db5ef4fcSRafal Jaworowski 			    err);
307db5ef4fcSRafal Jaworowski 		sc->sc_intr_hdl = NULL;
308db5ef4fcSRafal Jaworowski 	}
309db5ef4fcSRafal Jaworowski 	if (irq_err && ih_err) {
310db5ef4fcSRafal Jaworowski 		err = bus_teardown_intr(self, irq_err, ih_err);
311db5ef4fcSRafal Jaworowski 
312db5ef4fcSRafal Jaworowski 		if (err)
313db5ef4fcSRafal Jaworowski 			device_printf(self, "Could not tear down irq, %d\n",
314db5ef4fcSRafal Jaworowski 			    err);
315db5ef4fcSRafal Jaworowski 		ih_err = NULL;
316db5ef4fcSRafal Jaworowski 	}
317db5ef4fcSRafal Jaworowski 	if (irq_err) {
318db5ef4fcSRafal Jaworowski 		bus_release_resource(self, SYS_RES_IRQ, 0, irq_err);
319db5ef4fcSRafal Jaworowski 		irq_err = NULL;
320db5ef4fcSRafal Jaworowski 	}
321db5ef4fcSRafal Jaworowski 	if (sc->sc_irq_res) {
322db5ef4fcSRafal Jaworowski 		bus_release_resource(self, SYS_RES_IRQ, 1, sc->sc_irq_res);
323db5ef4fcSRafal Jaworowski 		sc->sc_irq_res = NULL;
324db5ef4fcSRafal Jaworowski 	}
325db5ef4fcSRafal Jaworowski 	if (sc->sc_io_res) {
326db5ef4fcSRafal Jaworowski 		bus_release_resource(self, SYS_RES_MEMORY, 0,
327db5ef4fcSRafal Jaworowski 		    sc->sc_io_res);
328db5ef4fcSRafal Jaworowski 		sc->sc_io_res = NULL;
329db5ef4fcSRafal Jaworowski 	}
330db5ef4fcSRafal Jaworowski 	usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
331db5ef4fcSRafal Jaworowski 
332db5ef4fcSRafal Jaworowski 	return (0);
333db5ef4fcSRafal Jaworowski }
334db5ef4fcSRafal Jaworowski 
335db5ef4fcSRafal Jaworowski static int
err_intr(void * arg)336db5ef4fcSRafal Jaworowski err_intr(void *arg)
337db5ef4fcSRafal Jaworowski {
338db5ef4fcSRafal Jaworowski 	ehci_softc_t *sc = arg;
33962d42655SHans Petter Selasky 	unsigned cause;
340db5ef4fcSRafal Jaworowski 
341db5ef4fcSRafal Jaworowski 	cause = EREAD4(sc, USB_BRIDGE_INTR_CAUSE);
342db5ef4fcSRafal Jaworowski 	if (cause) {
3436a9f4949SMarcel Moolenaar 		printf("USB error: ");
3446a9f4949SMarcel Moolenaar 		if (cause & MV_USB_ADDR_DECODE_ERR) {
3456a9f4949SMarcel Moolenaar 			uint32_t addr;
3466a9f4949SMarcel Moolenaar 
3476a9f4949SMarcel Moolenaar 			addr = EREAD4(sc, USB_BRIDGE_ERR_ADDR);
3486a9f4949SMarcel Moolenaar 			printf("address decoding error (addr=%#x)\n", addr);
3496a9f4949SMarcel Moolenaar 		}
350db5ef4fcSRafal Jaworowski 		if (cause & MV_USB_HOST_UNDERFLOW)
3516a9f4949SMarcel Moolenaar 			printf("host underflow\n");
352db5ef4fcSRafal Jaworowski 		if (cause & MV_USB_HOST_OVERFLOW)
3536a9f4949SMarcel Moolenaar 			printf("host overflow\n");
354db5ef4fcSRafal Jaworowski 		if (cause & MV_USB_DEVICE_UNDERFLOW)
3556a9f4949SMarcel Moolenaar 			printf("device underflow\n");
356db5ef4fcSRafal Jaworowski 		if (cause & ~(MV_USB_ADDR_DECODE_ERR | MV_USB_HOST_UNDERFLOW |
357db5ef4fcSRafal Jaworowski 		    MV_USB_HOST_OVERFLOW | MV_USB_DEVICE_UNDERFLOW))
3586a9f4949SMarcel Moolenaar 			printf("unknown cause (cause=%#x)\n", cause);
359db5ef4fcSRafal Jaworowski 
360db5ef4fcSRafal Jaworowski 		EWRITE4(sc, USB_BRIDGE_INTR_CAUSE, 0);
361db5ef4fcSRafal Jaworowski 	}
362db5ef4fcSRafal Jaworowski 	return (FILTER_HANDLED);
363db5ef4fcSRafal Jaworowski }
364db5ef4fcSRafal Jaworowski 
365db5ef4fcSRafal Jaworowski static device_method_t ehci_methods[] = {
366db5ef4fcSRafal Jaworowski 	/* Device interface */
367db5ef4fcSRafal Jaworowski 	DEVMETHOD(device_probe, mv_ehci_probe),
368db5ef4fcSRafal Jaworowski 	DEVMETHOD(device_attach, mv_ehci_attach),
369db5ef4fcSRafal Jaworowski 	DEVMETHOD(device_detach, mv_ehci_detach),
3702e141748SHans Petter Selasky 	DEVMETHOD(device_suspend, bus_generic_suspend),
3712e141748SHans Petter Selasky 	DEVMETHOD(device_resume, bus_generic_resume),
3722e141748SHans Petter Selasky 	DEVMETHOD(device_shutdown, bus_generic_shutdown),
373db5ef4fcSRafal Jaworowski 
3744b7ec270SMarius Strobl 	DEVMETHOD_END
375db5ef4fcSRafal Jaworowski };
376db5ef4fcSRafal Jaworowski 
377db5ef4fcSRafal Jaworowski static driver_t ehci_driver = {
378db5ef4fcSRafal Jaworowski 	"ehci",
379db5ef4fcSRafal Jaworowski 	ehci_methods,
380db5ef4fcSRafal Jaworowski 	sizeof(ehci_softc_t),
381db5ef4fcSRafal Jaworowski };
382db5ef4fcSRafal Jaworowski 
383bc9372d7SJohn Baldwin DRIVER_MODULE(ehci_mv, simplebus, ehci_driver, 0, 0);
3846c2c6106SMarcin Wojtas MODULE_DEPEND(ehci_mv, usb, 1, 1, 1);
385