xref: /netbsd-src/sys/arch/arm/imx/imxusb.c (revision 1b53f8867012b6c9584d633cbb812d3af7e001ea)
1*1b53f886Sbouyer /*	$NetBSD: imxusb.c,v 1.19 2023/05/04 17:09:44 bouyer Exp $	*/
2c1719a03Sbsh /*
3c1719a03Sbsh  * Copyright (c) 2009, 2010  Genetec Corporation.  All rights reserved.
4c1719a03Sbsh  * Written by Hashimoto Kenichi and Hiroyuki Bessho for Genetec Corporation.
5c1719a03Sbsh  *
6c1719a03Sbsh  * Redistribution and use in source and binary forms, with or without
7c1719a03Sbsh  * modification, are permitted provided that the following conditions
8c1719a03Sbsh  * are met:
9c1719a03Sbsh  * 1. Redistributions of source code must retain the above copyright
10c1719a03Sbsh  *    notice, this list of conditions and the following disclaimer.
11c1719a03Sbsh  * 2. Redistributions in binary form must reproduce the above copyright
12c1719a03Sbsh  *    notice, this list of conditions and the following disclaimer in the
13c1719a03Sbsh  *    documentation and/or other materials provided with the distribution.
14c1719a03Sbsh  *
15c1719a03Sbsh  * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
16c1719a03Sbsh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17c1719a03Sbsh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18c1719a03Sbsh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
19c1719a03Sbsh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20c1719a03Sbsh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21c1719a03Sbsh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22c1719a03Sbsh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23c1719a03Sbsh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24c1719a03Sbsh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25c1719a03Sbsh  * POSSIBILITY OF SUCH DAMAGE.
26c1719a03Sbsh  */
27c1719a03Sbsh #include <sys/cdefs.h>
28*1b53f886Sbouyer __KERNEL_RCSID(0, "$NetBSD: imxusb.c,v 1.19 2023/05/04 17:09:44 bouyer Exp $");
292868f5bcShkenken 
3005ac7a10Shkenken #include "locators.h"
318644267aSskrll #include "opt_imx.h"
32c1719a03Sbsh 
33c1719a03Sbsh #include <sys/param.h>
34c1719a03Sbsh #include <sys/systm.h>
35c1719a03Sbsh #include <sys/conf.h>
36c1719a03Sbsh #include <sys/kernel.h>
37c1719a03Sbsh #include <sys/device.h>
38c1719a03Sbsh #include <sys/intr.h>
39c1719a03Sbsh #include <sys/bus.h>
40c1719a03Sbsh 
41c1719a03Sbsh #include <dev/usb/usb.h>
42c1719a03Sbsh #include <dev/usb/usbdi.h>
43c1719a03Sbsh #include <dev/usb/usbdivar.h>
44c1719a03Sbsh #include <dev/usb/usb_mem.h>
45c1719a03Sbsh 
46c1719a03Sbsh #include <dev/usb/ehcireg.h>
47c1719a03Sbsh #include <dev/usb/ehcivar.h>
48c1719a03Sbsh 
4994de0730Smatt #include <arm/pic/picvar.h>	/* XXX: for intr_establish! */
5094de0730Smatt 
51c1719a03Sbsh #include <arm/imx/imxusbreg.h>
52c1719a03Sbsh #include <arm/imx/imxusbvar.h>
53c1719a03Sbsh 
54c1719a03Sbsh #include <dev/usb/ulpireg.h>	/* for test */
55c1719a03Sbsh 
56c1719a03Sbsh static int	imxehci_match(device_t, cfdata_t, void *);
57c1719a03Sbsh static void	imxehci_attach(device_t, device_t, void *);
58c1719a03Sbsh 
59c1719a03Sbsh uint8_t imxusb_ulpi_read(struct imxehci_softc *sc, int addr);
60c1719a03Sbsh void imxusb_ulpi_write(struct imxehci_softc *sc, int addr, uint8_t data);
61c1719a03Sbsh static void ulpi_reset(struct imxehci_softc *sc);
62c1719a03Sbsh 
63ebfb0c93Shkenken static void imxehci_select_interface(struct imxehci_softc *, enum imx_usb_if);
64ebfb0c93Shkenken static void imxehci_init(struct ehci_softc *);
65c1719a03Sbsh 
66c1719a03Sbsh /* attach structures */
67c1719a03Sbsh CFATTACH_DECL_NEW(imxehci, sizeof(struct imxehci_softc),
68c1719a03Sbsh     imxehci_match, imxehci_attach, NULL, NULL);
69c1719a03Sbsh 
70c1719a03Sbsh static int
imxehci_match(device_t parent,cfdata_t cf,void * aux)71c1719a03Sbsh imxehci_match(device_t parent, cfdata_t cf, void *aux)
72c1719a03Sbsh {
73c1719a03Sbsh 	struct imxusbc_attach_args *aa = aux;
74c1719a03Sbsh 
7505ac7a10Shkenken 	if (aa->aa_unit < 0 || 3 < aa->aa_unit)
76c1719a03Sbsh 		return 0;
77c1719a03Sbsh 
78c1719a03Sbsh 	return 1;
79c1719a03Sbsh }
80c1719a03Sbsh 
81c1719a03Sbsh static void
imxehci_attach(device_t parent,device_t self,void * aux)82c1719a03Sbsh imxehci_attach(device_t parent, device_t self, void *aux)
83c1719a03Sbsh {
84c1719a03Sbsh 	struct imxusbc_attach_args *aa = aux;
85c1719a03Sbsh 	struct imxusbc_softc *usbc = device_private(parent);
86c1719a03Sbsh 	struct imxehci_softc *sc = device_private(self);
87c1719a03Sbsh 	ehci_softc_t *hsc = &sc->sc_hsc;
88c1719a03Sbsh 	bus_space_tag_t iot;
89c1719a03Sbsh 	uint16_t hcirev;
90c1719a03Sbsh 	uint32_t id, hwhost, hwdevice;
91c1719a03Sbsh 	const char *comma;
92c1719a03Sbsh 
9305ac7a10Shkenken 	iot = aa->aa_iot;
9405ac7a10Shkenken 
9505ac7a10Shkenken 	sc->sc_dev = self;
96c1719a03Sbsh 	sc->sc_unit = aa->aa_unit;
97c1719a03Sbsh 	sc->sc_usbc = usbc;
9805ac7a10Shkenken 	sc->sc_iot = iot;
9905ac7a10Shkenken 
10005ac7a10Shkenken 	hsc->sc_dev = self;
10105ac7a10Shkenken 	hsc->iot = iot;
1024e8e6643Sskrll 	hsc->sc_bus.ub_hcpriv = sc;
10305ac7a10Shkenken 	hsc->sc_bus.ub_dmatag = aa->aa_dmat;
104df86f8ddSmatt 	hsc->sc_flags |= EHCIF_ETTF;
105ebfb0c93Shkenken 	hsc->sc_vendor_init = imxehci_init;
106c1719a03Sbsh 
107a4103ccdSryo 	aprint_naive("\n");
108a4103ccdSryo 	aprint_normal(": i.MX USB Controller\n");
109c1719a03Sbsh 
110ec482321Sryo 	if (usbc->sc_ehci_size == 0)
111ec482321Sryo 		usbc->sc_ehci_size = IMXUSB_EHCI_SIZE;	/* use default */
112ec482321Sryo 
113c1719a03Sbsh 	/* per unit registers */
114c1719a03Sbsh 	if (bus_space_subregion(iot, aa->aa_ioh,
11505ac7a10Shkenken 		sc->sc_unit * usbc->sc_ehci_offset, usbc->sc_ehci_size,
116c1719a03Sbsh 		&sc->sc_ioh) ||
117c1719a03Sbsh 	    bus_space_subregion(iot, aa->aa_ioh,
11805ac7a10Shkenken 		sc->sc_unit * usbc->sc_ehci_offset + IMXUSB_EHCIREGS,
119ec482321Sryo 		usbc->sc_ehci_size - IMXUSB_EHCIREGS,
12005ac7a10Shkenken 		&hsc->ioh)) {
121c1719a03Sbsh 
122c1719a03Sbsh 		aprint_error_dev(self, "can't subregion\n");
123c1719a03Sbsh 		return;
124c1719a03Sbsh 	}
125c1719a03Sbsh 
126c1719a03Sbsh 	id = bus_space_read_4(iot, sc->sc_ioh, IMXUSB_ID);
12705ac7a10Shkenken 	hcirev = bus_space_read_2(iot, hsc->ioh, EHCI_HCIVERSION);
128c1719a03Sbsh 
129c1719a03Sbsh 	aprint_normal_dev(self,
130a4103ccdSryo 	    "id=%d revision=%d HCI revision=0x%x\n",
1312868f5bcShkenken 	    (int)__SHIFTOUT(id, IMXUSB_ID_ID),
1322868f5bcShkenken 	    (int)__SHIFTOUT(id, IMXUSB_ID_REVISION),
133c1719a03Sbsh 	    hcirev);
134c1719a03Sbsh 
135c1719a03Sbsh 	hwhost = bus_space_read_4(iot, sc->sc_ioh, IMXUSB_HWHOST);
136c1719a03Sbsh 	hwdevice = bus_space_read_4(iot, sc->sc_ioh, IMXUSB_HWDEVICE);
137c1719a03Sbsh 
138c1719a03Sbsh 	aprint_normal_dev(self, "");
139c1719a03Sbsh 
140c1719a03Sbsh 	comma = "";
141c1719a03Sbsh 	if (hwhost & HWHOST_HC) {
1422868f5bcShkenken 		int n_ports = 1 + __SHIFTOUT(hwhost, HWHOST_NPORT);
143c1719a03Sbsh 		aprint_normal("%d host port%s",
144c1719a03Sbsh 		    n_ports, n_ports > 1 ? "s" : "");
145c1719a03Sbsh 		comma = ", ";
146c1719a03Sbsh 	}
147c1719a03Sbsh 
148c1719a03Sbsh 	if (hwdevice & HWDEVICE_DC) {
1492868f5bcShkenken 		int n_endpoints = __SHIFTOUT(hwdevice, HWDEVICE_DEVEP);
150c1719a03Sbsh 		aprint_normal("%sdevice capable, %d endpoint%s",
151c1719a03Sbsh 		    comma,
152c1719a03Sbsh 		    n_endpoints, n_endpoints > 1 ? "s" : "");
153c1719a03Sbsh 	}
154c1719a03Sbsh 	aprint_normal("\n");
155c1719a03Sbsh 
15605ac7a10Shkenken 	hsc->sc_offs = bus_space_read_1(iot, hsc->ioh,
157c1719a03Sbsh 	    EHCI_CAPLENGTH);
158c1719a03Sbsh 
159c1719a03Sbsh 	/* Platform dependent setup */
160c1719a03Sbsh 	if (usbc->sc_init_md_hook)
161*1b53f886Sbouyer 		usbc->sc_init_md_hook(sc, usbc->sc_md_hook_data);
162c1719a03Sbsh 
163c1719a03Sbsh 	imxehci_reset(sc);
164c1719a03Sbsh 	imxehci_select_interface(sc, sc->sc_iftype);
165c1719a03Sbsh 
166c1719a03Sbsh 	if (sc->sc_iftype == IMXUSBC_IF_ULPI) {
167c1719a03Sbsh 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUSB_ULPIVIEW, 0);
168c1719a03Sbsh 
169c1719a03Sbsh 		aprint_normal_dev(hsc->sc_dev,
170c1719a03Sbsh 		    "ULPI phy VID 0x%04x PID 0x%04x\n",
171c1719a03Sbsh 		    (imxusb_ulpi_read(sc, ULPI_VENDOR_ID_LOW) |
172c1719a03Sbsh 			imxusb_ulpi_read(sc, ULPI_VENDOR_ID_HIGH) << 8),
173c1719a03Sbsh 		    (imxusb_ulpi_read(sc, ULPI_PRODUCT_ID_LOW) |
174c1719a03Sbsh 			imxusb_ulpi_read(sc, ULPI_PRODUCT_ID_HIGH) << 8));
175c1719a03Sbsh 
176c1719a03Sbsh 		ulpi_reset(sc);
177c1719a03Sbsh 
178c1719a03Sbsh 	}
179c1719a03Sbsh 
180c1719a03Sbsh 	if (usbc->sc_setup_md_hook)
181*1b53f886Sbouyer 		usbc->sc_setup_md_hook(sc, IMXUSB_HOST, usbc->sc_md_hook_data);
1822868f5bcShkenken 
1832868f5bcShkenken 	if (sc->sc_iftype == IMXUSBC_IF_ULPI) {
1842868f5bcShkenken #if 0
1854e8e6643Sskrll 		if(hsc->sc_bus.ub_revision == USBREV_2_0)
1862868f5bcShkenken 			ulpi_write(hsc, ULPI_FUNCTION_CONTROL + ULPI_REG_CLEAR, (1 << 0));
1872868f5bcShkenken 		else
1882868f5bcShkenken 			ulpi_write(hsc, ULPI_FUNCTION_CONTROL + ULPI_REG_SET, (1 << 2));
1892868f5bcShkenken #endif
1902868f5bcShkenken 
191c1719a03Sbsh 		imxusb_ulpi_write(sc, ULPI_FUNCTION_CONTROL + ULPI_REG_CLEAR,
192c1719a03Sbsh 		    OTG_CONTROL_IDPULLUP);
193c1719a03Sbsh 
194c1719a03Sbsh 		imxusb_ulpi_write(sc, ULPI_OTG_CONTROL + ULPI_REG_SET,
195c1719a03Sbsh 		    OTG_CONTROL_USEEXTVBUSIND |
196c1719a03Sbsh 		    OTG_CONTROL_DRVVBUSEXT |
197c1719a03Sbsh 		    OTG_CONTROL_DRVVBUS |
19805ac7a10Shkenken 		    OTG_CONTROL_CHRGVBUS);
199c1719a03Sbsh 	}
200c1719a03Sbsh 
201c1719a03Sbsh 	/* Disable interrupts, so we don't get any spurious ones. */
20209fca0b7Smatt 	EOWRITE4(hsc, EHCI_USBINTR, 0);
203c1719a03Sbsh 
20405ac7a10Shkenken 	if (usbc->sc_intr_establish_md_hook)
205*1b53f886Sbouyer 		sc->sc_ih = usbc->sc_intr_establish_md_hook(sc,
206*1b53f886Sbouyer 		    usbc->sc_md_hook_data);
20705ac7a10Shkenken 	else if (aa->aa_irq > 0)
20805ac7a10Shkenken 		sc->sc_ih = intr_establish(aa->aa_irq, IPL_USB, IST_LEVEL, ehci_intr, hsc);
20905ac7a10Shkenken 	KASSERT(sc->sc_ih != NULL);
210c1719a03Sbsh 
2114e8e6643Sskrll 	int err = ehci_init(hsc);
2124e8e6643Sskrll 	if (err) {
2134e8e6643Sskrll 		aprint_error_dev(self, "init failed, error=%d\n", err);
214c1719a03Sbsh 		return;
215c1719a03Sbsh 	}
216c1719a03Sbsh 
217c1719a03Sbsh 	/* Attach usb device. */
2182685996bSthorpej 	hsc->sc_child = config_found(self, &hsc->sc_bus, usbctlprint,
219c7fb772bSthorpej 	    CFARGS_NONE);
220c1719a03Sbsh }
221c1719a03Sbsh 
222ebfb0c93Shkenken static void
imxehci_select_interface(struct imxehci_softc * sc,enum imx_usb_if interface)223c1719a03Sbsh imxehci_select_interface(struct imxehci_softc *sc, enum imx_usb_if interface)
224c1719a03Sbsh {
225c1719a03Sbsh 	uint32_t reg;
226c1719a03Sbsh 	struct ehci_softc *hsc = &sc->sc_hsc;
227c1719a03Sbsh 
228c1719a03Sbsh 	reg = EOREAD4(hsc, EHCI_PORTSC(1));
229ec482321Sryo 	reg &= ~(PORTSC_PTS | PORTSC_PTW | PORTSC_PTS2);
2302868f5bcShkenken 	switch (interface) {
2312868f5bcShkenken 	case IMXUSBC_IF_UTMI_WIDE:
2322868f5bcShkenken 		reg |= PORTSC_PTW_16;
2332868f5bcShkenken 	case IMXUSBC_IF_UTMI:
2342868f5bcShkenken 		reg |= PORTSC_PTS_UTMI;
2352868f5bcShkenken 		break;
2362868f5bcShkenken 	case IMXUSBC_IF_PHILIPS:
2372868f5bcShkenken 		reg |= PORTSC_PTS_PHILIPS;
2382868f5bcShkenken 		break;
2392868f5bcShkenken 	case IMXUSBC_IF_ULPI:
2402868f5bcShkenken 		reg |= PORTSC_PTS_ULPI;
2412868f5bcShkenken 		break;
2422868f5bcShkenken 	case IMXUSBC_IF_SERIAL:
2432868f5bcShkenken 		reg |= PORTSC_PTS_SERIAL;
2442868f5bcShkenken 		break;
245ec482321Sryo 	case IMXUSBC_IF_HSIC:
246ec482321Sryo 		reg |= PORTSC_PTS2;
247ec482321Sryo 		break;
2482868f5bcShkenken 	}
249c1719a03Sbsh 	EOWRITE4(hsc, EHCI_PORTSC(1), reg);
250c1719a03Sbsh }
251c1719a03Sbsh 
252c1719a03Sbsh static uint32_t
ulpi_wakeup(struct imxehci_softc * sc,int tout)253c1719a03Sbsh ulpi_wakeup(struct imxehci_softc *sc, int tout)
254c1719a03Sbsh {
25505ac7a10Shkenken 	struct ehci_softc *hsc = &sc->sc_hsc;
256c1719a03Sbsh 	uint32_t ulpi_view;
25705ac7a10Shkenken 
258c1719a03Sbsh 	ulpi_view = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IMXUSB_ULPIVIEW);
259c1719a03Sbsh 
260c1719a03Sbsh 	if (!(ulpi_view & ULPI_SS)) {
261c1719a03Sbsh 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
262c1719a03Sbsh 		    IMXUSB_ULPIVIEW, ULPI_WU);
26305ac7a10Shkenken 		while (tout-- > 0) {
264c1719a03Sbsh 			ulpi_view = bus_space_read_4(sc->sc_iot,
265c1719a03Sbsh 			    sc->sc_ioh, IMXUSB_ULPIVIEW);
266c1719a03Sbsh 			if (!(ulpi_view & ULPI_WU))
267c1719a03Sbsh 				break;
268c1719a03Sbsh 			delay(1);
269c1719a03Sbsh 		};
270c1719a03Sbsh 	}
271c1719a03Sbsh 
27205ac7a10Shkenken 	if (tout == 0)
27305ac7a10Shkenken 		aprint_error_dev(hsc->sc_dev, "%s: timeout\n", __func__);
274c1719a03Sbsh 
275c1719a03Sbsh 	return ulpi_view;
276c1719a03Sbsh }
277c1719a03Sbsh 
278c1719a03Sbsh static uint32_t
ulpi_wait(struct imxehci_softc * sc,int tout)279c1719a03Sbsh ulpi_wait(struct imxehci_softc *sc, int tout)
280c1719a03Sbsh {
28105ac7a10Shkenken 	struct ehci_softc *hsc = &sc->sc_hsc;
282c1719a03Sbsh 	uint32_t ulpi_view;
28305ac7a10Shkenken 
284c1719a03Sbsh 	ulpi_view = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IMXUSB_ULPIVIEW);
285c1719a03Sbsh 
28605ac7a10Shkenken 	while (tout-- > 0) {
287c1719a03Sbsh 		ulpi_view = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
288c1719a03Sbsh 		    IMXUSB_ULPIVIEW);
289c1719a03Sbsh 		if (!(ulpi_view & ULPI_RUN))
290c1719a03Sbsh 			break;
291c1719a03Sbsh 		delay(1);
292c1719a03Sbsh 	}
293c1719a03Sbsh 
29405ac7a10Shkenken 	if (tout == 0)
29505ac7a10Shkenken 		aprint_error_dev(hsc->sc_dev, "%s: timeout\n", __func__);
296c1719a03Sbsh 
297c1719a03Sbsh 	return ulpi_view;
298c1719a03Sbsh }
299c1719a03Sbsh 
300c1719a03Sbsh #define	TIMEOUT	100000
301c1719a03Sbsh 
302c1719a03Sbsh uint8_t
imxusb_ulpi_read(struct imxehci_softc * sc,int addr)303c1719a03Sbsh imxusb_ulpi_read(struct imxehci_softc *sc, int addr)
304c1719a03Sbsh {
30505ac7a10Shkenken 	uint32_t reg;
306c1719a03Sbsh 
307c1719a03Sbsh 	ulpi_wakeup(sc, TIMEOUT);
308c1719a03Sbsh 
30905ac7a10Shkenken 	reg = ULPI_RUN | __SHIFTIN(addr, ULPI_ADDR);
31005ac7a10Shkenken 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUSB_ULPIVIEW, reg);
311c1719a03Sbsh 
31205ac7a10Shkenken 	reg = ulpi_wait(sc, TIMEOUT);
313c1719a03Sbsh 
31405ac7a10Shkenken 	return __SHIFTOUT(reg, ULPI_DATRD);
315c1719a03Sbsh }
316c1719a03Sbsh 
317c1719a03Sbsh void
imxusb_ulpi_write(struct imxehci_softc * sc,int addr,uint8_t data)318c1719a03Sbsh imxusb_ulpi_write(struct imxehci_softc *sc, int addr, uint8_t data)
319c1719a03Sbsh {
320c1719a03Sbsh 	uint32_t reg;
321c1719a03Sbsh 
322c1719a03Sbsh 	ulpi_wakeup(sc, TIMEOUT);
323c1719a03Sbsh 
3242868f5bcShkenken 	reg = ULPI_RUN | ULPI_RW | __SHIFTIN(addr, ULPI_ADDR) | __SHIFTIN(data, ULPI_DATWR);
325c1719a03Sbsh 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUSB_ULPIVIEW, reg);
326c1719a03Sbsh 
327c1719a03Sbsh 	ulpi_wait(sc, TIMEOUT);
328c1719a03Sbsh 
329c1719a03Sbsh 	return;
330c1719a03Sbsh }
331c1719a03Sbsh 
332c1719a03Sbsh static void
ulpi_reset(struct imxehci_softc * sc)333c1719a03Sbsh ulpi_reset(struct imxehci_softc *sc)
334c1719a03Sbsh {
33505ac7a10Shkenken 	struct ehci_softc *hsc = &sc->sc_hsc;
336c1719a03Sbsh 	uint8_t data;
337c1719a03Sbsh 	int timo = 1000 * 1000;	/* XXXX: 1sec */
338c1719a03Sbsh 
339c1719a03Sbsh 	imxusb_ulpi_write(sc, ULPI_FUNCTION_CONTROL + ULPI_REG_SET,
340c1719a03Sbsh 	    FUNCTION_CONTROL_RESET /*0x20*/);
341c1719a03Sbsh 	do {
342c1719a03Sbsh 		data = imxusb_ulpi_read(sc, ULPI_FUNCTION_CONTROL);
343c1719a03Sbsh 		if (!(data & FUNCTION_CONTROL_RESET))
344c1719a03Sbsh 			break;
345c1719a03Sbsh 		delay(100);
346c1719a03Sbsh 		timo -= 100;
347c1719a03Sbsh 	} while (timo > 0);
34805ac7a10Shkenken 
349c1719a03Sbsh 	if (timo <= 0) {
35005ac7a10Shkenken 		aprint_error_dev(hsc->sc_dev, "%s: reset failed!!\n",
351c1719a03Sbsh 		    __func__);
352c1719a03Sbsh 		return;
353c1719a03Sbsh 	}
354c1719a03Sbsh 
355c1719a03Sbsh 	return;
356c1719a03Sbsh }
357c1719a03Sbsh 
358c1719a03Sbsh void
imxehci_reset(struct imxehci_softc * sc)359c1719a03Sbsh imxehci_reset(struct imxehci_softc *sc)
360c1719a03Sbsh {
36108a4aba7Sskrll 	uint32_t reg;
362c1719a03Sbsh 	struct ehci_softc *hsc = &sc->sc_hsc;
36305ac7a10Shkenken 	int tout;
364c1719a03Sbsh #define	RESET_TIMEOUT 100
365c1719a03Sbsh 
366c1719a03Sbsh 	reg = EOREAD4(hsc, EHCI_USBCMD);
367c1719a03Sbsh 	reg &= ~EHCI_CMD_RS;
368c1719a03Sbsh 	EOWRITE4(hsc, EHCI_USBCMD, reg);
369c1719a03Sbsh 
37005ac7a10Shkenken 	for (tout = RESET_TIMEOUT; tout > 0; tout--) {
371c1719a03Sbsh 		reg = EOREAD4(hsc, EHCI_USBCMD);
372c1719a03Sbsh 		if ((reg & EHCI_CMD_RS) == 0)
373c1719a03Sbsh 			break;
374c1719a03Sbsh 		usb_delay_ms(&hsc->sc_bus, 1);
375c1719a03Sbsh 	}
376c1719a03Sbsh 
377c1719a03Sbsh 	EOWRITE4(hsc, EHCI_USBCMD, reg | EHCI_CMD_HCRESET);
37805ac7a10Shkenken 
37905ac7a10Shkenken 	for (tout = RESET_TIMEOUT; tout > 0; tout--) {
380c1719a03Sbsh 		reg = EOREAD4(hsc, EHCI_USBCMD);
381c1719a03Sbsh 		if ((reg &  EHCI_CMD_HCRESET) == 0)
382c1719a03Sbsh 			break;
383c1719a03Sbsh 		usb_delay_ms(&hsc->sc_bus, 1);
384c1719a03Sbsh 	}
38505ac7a10Shkenken 
38605ac7a10Shkenken 	if (tout == 0)
387c1719a03Sbsh 		aprint_error_dev(hsc->sc_dev, "reset timeout (%x)\n", reg);
388c1719a03Sbsh 
389c1719a03Sbsh 	usb_delay_ms(&hsc->sc_bus, 100);
390c1719a03Sbsh }
391c1719a03Sbsh 
392ebfb0c93Shkenken static void
imxehci_init(struct ehci_softc * hsc)393ebfb0c93Shkenken imxehci_init(struct ehci_softc *hsc)
394c1719a03Sbsh {
395ebfb0c93Shkenken 	struct imxehci_softc *sc = device_private(hsc->sc_dev);
396c1719a03Sbsh 	uint32_t reg;
397c1719a03Sbsh 
398c1719a03Sbsh 	reg = EOREAD4(hsc, EHCI_PORTSC(1));
399c1719a03Sbsh 	reg &= ~(EHCI_PS_CSC | EHCI_PS_PEC | EHCI_PS_OCC);
400c1719a03Sbsh 	reg |= EHCI_PS_PP | EHCI_PS_PE;
401c1719a03Sbsh 	EOWRITE4(hsc, EHCI_PORTSC(1), reg);
402c1719a03Sbsh 
403c1719a03Sbsh 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IMXUSB_OTGSC);
404c1719a03Sbsh 	reg |= OTGSC_IDPU;
40594de0730Smatt 	/* disable IDIE not to conflict with SSP1_DETECT. */
40694de0730Smatt 	//reg |= OTGSC_DPIE | OTGSC_IDIE;
40794de0730Smatt 	reg |= OTGSC_DPIE;
408c1719a03Sbsh 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUSB_OTGSC, reg);
409c1719a03Sbsh 
41050aa6e87Sskrll 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IMXUSB_USBMODE);
411ebfb0c93Shkenken 	reg &= ~USBMODE_CM;
4122868f5bcShkenken 	reg |= USBMODE_CM_HOST;
41350aa6e87Sskrll 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUSB_USBMODE, reg);
414c1719a03Sbsh }
415