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