xref: /openbsd-src/sys/arch/armv7/omap/omehci.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: omehci.c,v 1.4 2016/08/11 01:53:18 jsg Exp $ */
2 
3 /*
4  * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*-
20  * Copyright (c) 2011
21  *	Ben Gray <ben.r.gray@gmail.com>.
22  * All rights reserved.
23  *
24  * Redistribution and use in source and binary forms, with or without
25  * modification, are permitted provided that the following conditions
26  * are met:
27  * 1. Redistributions of source code must retain the above copyright
28  *    notice, this list of conditions and the following disclaimer.
29  * 2. Redistributions in binary form must reproduce the above copyright
30  *    notice, this list of conditions and the following disclaimer in the
31  *    documentation and/or other materials provided with the distribution.
32  *
33  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
34  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
37  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43  * SUCH DAMAGE.
44  */
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/device.h>
49 #include <sys/kernel.h>
50 #include <sys/rwlock.h>
51 #include <sys/timeout.h>
52 
53 #include <machine/intr.h>
54 #include <machine/bus.h>
55 #include <machine/fdt.h>
56 
57 #include <dev/usb/usb.h>
58 #include <dev/usb/usbdi.h>
59 #include <dev/usb/usbdivar.h>
60 #include <dev/usb/usb_mem.h>
61 
62 #include <armv7/armv7/armv7var.h>
63 #include <armv7/omap/prcmvar.h>
64 #include <armv7/omap/omgpiovar.h>
65 #include <armv7/omap/omehcivar.h>
66 
67 #include <dev/ofw/openfirm.h>
68 #include <dev/ofw/fdt.h>
69 
70 #include <dev/usb/ehcireg.h>
71 #include <dev/usb/ehcivar.h>
72 
73 int	omehci_match(struct device *, void *, void *);
74 void	omehci_attach(struct device *, struct device *, void *);
75 int	omehci_detach(struct device *, int);
76 int	omehci_activate(struct device *, int);
77 
78 struct omehci_softc {
79 	struct ehci_softc	 sc;
80 	void			*sc_ih;
81 	bus_space_handle_t	 uhh_ioh;
82 	bus_space_handle_t	 tll_ioh;
83 
84 	uint32_t		 ehci_rev;
85 	uint32_t		 tll_avail;
86 
87 	uint32_t		 port_mode[OMAP_HS_USB_PORTS];
88 	uint32_t		 phy_reset[OMAP_HS_USB_PORTS];
89 	uint32_t		 reset_gpio_pin[OMAP_HS_USB_PORTS];
90 
91 	void			 (*early_init)(void);
92 };
93 
94 int omehci_init(struct omehci_softc *);
95 void omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port);
96 void omehci_enable(struct omehci_softc *);
97 void omehci_disable(struct omehci_softc *);
98 void omehci_utmi_init(struct omehci_softc *sc, unsigned int en_mask);
99 void misc_setup(struct omehci_softc *sc);
100 void omehci_phy_reset(uint32_t on, uint32_t _delay);
101 void omehci_uhh_init(struct omehci_softc *sc);
102 void omehci_v4_early_init(void);
103 
104 struct cfattach omehci_ca = {
105 	sizeof (struct omehci_softc), omehci_match, omehci_attach,
106 	omehci_detach, omehci_activate
107 };
108 
109 struct cfdriver omehci_cd = {
110 	NULL, "omehci", DV_DULL
111 };
112 
113 int
114 omehci_match(struct device *parent, void *match, void *aux)
115 {
116 	struct fdt_attach_args *faa = aux;
117 
118 	return OF_is_compatible(faa->fa_node, "ti,usbhs-host");
119 }
120 
121 void
122 omehci_attach(struct device *parent, struct device *self, void *aux)
123 {
124 	struct omehci_softc	*sc = (struct omehci_softc *)self;
125 	struct fdt_attach_args *faa = aux;
126 	usbd_status		 r;
127 	char			*devname = sc->sc.sc_bus.bdev.dv_xname;
128 	uint32_t		 i;
129 	char			 port_mode[16];
130 	char			 name[32];
131 	int			 node;
132 	uint32_t		 reg[2];
133 
134 	if (faa->fa_nreg < 1)
135 		return;
136 
137 	sc->sc.iot = faa->fa_iot;
138 	sc->sc.sc_bus.dmatag = faa->fa_dmat;
139 
140 	/* set defaults */
141 	for (i = 0; i < OMAP_HS_USB_PORTS; i++) {
142 		sc->phy_reset[i] = 0;
143 		sc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN;
144 		sc->reset_gpio_pin[i] = -1;
145 	}
146 
147 	switch (board_id)
148 	{
149 	case BOARD_ID_OMAP4_PANDA:
150 		sc->tll_avail = 0;
151 		sc->early_init = omehci_v4_early_init;
152 		break;
153 	default:
154 		break;
155 	}
156 
157 	strlcpy(name, "portX-mode", sizeof(name));
158 
159 	for (i = 0; i < OMAP_HS_USB_PORTS; i++) {
160 		name[4] = '1' + i;
161 		memset(port_mode, 0, sizeof(port_mode));
162 
163 		if (OF_getprop(faa->fa_node, name, port_mode,
164 		    sizeof(port_mode)) == -1)
165 			continue;
166 
167 		if (strcmp(port_mode, "ehci-phy") == 0)
168 			sc->port_mode[i] = EHCI_HCD_OMAP_MODE_PHY;
169 		if (strcmp(port_mode, "ehci-hsic") == 0)
170 			sc->port_mode[i] = EHCI_HCD_OMAP_MODE_HSIC;
171 		if (strcmp(port_mode, "ehci-tll") == 0)
172 			sc->port_mode[i] = EHCI_HCD_OMAP_MODE_TLL ;
173 	}
174 
175 	for (node = OF_child(faa->fa_node); node; node = OF_peer(node)) {
176 		if (OF_is_compatible(node, "ti,ehci-omap"))
177 			break;
178 	}
179 
180 	if (node == 0)
181 		panic("could not find ehci child node");
182 
183 	if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) != sizeof(reg))
184 		return;
185 
186 	/* Map I/O space */
187 	if (bus_space_map(sc->sc.iot, reg[0], reg[1], 0, &sc->sc.ioh)) {
188 		printf(": cannot map mem space\n");
189 		goto out;
190 	}
191 	sc->sc.sc_size = reg[1];
192 
193 	if (bus_space_map(sc->sc.iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
194 	    0, &sc->uhh_ioh)) {
195 		printf(": cannot map mem space\n");
196 		goto mem0;
197 	}
198 
199 #if 0
200 	if (sc->tll_avail &&
201 	    bus_space_map(sc->sc.iot, aa->aa_dev->mem[2].addr,
202 	    aa->aa_dev->mem[2].size, 0, &sc->tll_ioh)) {
203 		printf(": cannot map mem space\n");
204 		goto mem1;
205 	}
206 #endif
207 
208 	printf("\n");
209 
210 	if (sc->early_init)
211 		sc->early_init();
212 
213 	if (omehci_init(sc))
214 		return;
215 
216 	/* Disable interrupts, so we don't get any spurious ones. */
217 	sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH);
218 	EOWRITE2(&sc->sc, EHCI_USBINTR, 0);
219 
220 	sc->sc_ih = arm_intr_establish_fdt(node, IPL_USB,
221 	    ehci_intr, &sc->sc, devname);
222 	if (sc->sc_ih == NULL) {
223 		printf(": unable to establish interrupt\n");
224 		printf("XXX - disable ehci and prcm");
225 		goto mem2;
226 	}
227 
228 	strlcpy(sc->sc.sc_vendor, "TI OMAP", sizeof(sc->sc.sc_vendor));
229 	r = ehci_init(&sc->sc);
230 	if (r != USBD_NORMAL_COMPLETION) {
231 		printf("%s: init failed, error=%d\n", devname, r);
232 		printf("XXX - disable ehci and prcm");
233 		goto intr;
234 	}
235 
236 	config_found(self, &sc->sc.sc_bus, usbctlprint);
237 
238 	goto out;
239 
240 intr:
241 	arm_intr_disestablish(sc->sc_ih);
242 	sc->sc_ih = NULL;
243 mem2:
244 #if 0
245 	bus_space_unmap(sc->sc.iot, sc->tll_ioh, aa->aa_dev->mem[2].size);
246 mem1:
247 #endif
248 	bus_space_unmap(sc->sc.iot, sc->uhh_ioh, faa->fa_reg[0].size);
249 mem0:
250 	bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
251 	sc->sc.sc_size = 0;
252 out:
253 	return;
254 }
255 
256 int
257 omehci_init(struct omehci_softc *sc)
258 {
259 	uint32_t i = 0, reg;
260 	uint32_t reset_performed = 0;
261 	uint32_t timeout = 0;
262 	uint32_t tll_ch_mask = 0;
263 
264 	/* enable high speed usb host clock */
265 	prcm_enablemodule(PRCM_USB);
266 
267 	/* Hold the PHY in reset while configuring */
268 	for (i = 0; i < OMAP_HS_USB_PORTS; i++) {
269 		if (sc->phy_reset[i]) {
270 			/* Configure the GPIO to drive low (hold in reset) */
271 			if (sc->reset_gpio_pin[i] != -1) {
272 				omgpio_set_dir(sc->reset_gpio_pin[i],
273 				    OMGPIO_DIR_OUT);
274 				omgpio_clear_bit(sc->reset_gpio_pin[i]);
275 				reset_performed = 1;
276 			}
277 		}
278 	}
279 
280 	/* Hold the PHY in RESET for enough time till DIR is high */
281 	if (reset_performed)
282 		delay(10);
283 
284 	/* Read the UHH revision */
285 	sc->ehci_rev = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
286 	    OMAP_USBHOST_UHH_REVISION);
287 
288 	/* Initilise the low level interface module(s) */
289 	if (sc->ehci_rev == OMAP_EHCI_REV1) {
290 		/* Enable the USB TLL */
291 		prcm_enablemodule(PRCM_USBTLL);
292 
293 		/* Perform TLL soft reset, and wait until reset is complete */
294 		bus_space_write_4(sc->sc.iot, sc->tll_ioh,
295 		    OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET);
296 
297 		/* Set the timeout to 100ms*/
298 		timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
299 
300 		/* Wait for TLL reset to complete */
301 		while ((bus_space_read_4(sc->sc.iot, sc->tll_ioh,
302 		    OMAP_USBTLL_SYSSTATUS) & TLL_SYSSTATUS_RESETDONE)
303 		    == 0x00) {
304 
305 			/* Sleep for a tick */
306 			delay(10);
307 
308 			if (timeout-- == 0) {
309 				return 1;
310 			}
311 		}
312 
313 		bus_space_write_4(sc->sc.iot, sc->tll_ioh,
314 		    OMAP_USBTLL_SYSCONFIG,
315 		    TLL_SYSCONFIG_ENAWAKEUP | TLL_SYSCONFIG_AUTOIDLE |
316 		    TLL_SYSCONFIG_SIDLE_SMART_IDLE | TLL_SYSCONFIG_CACTIVITY);
317 	} else if (sc->ehci_rev == OMAP_EHCI_REV2) {
318 		/* For OMAP44xx devices you have to enable the per-port clocks:
319 		 *  PHY_MODE  - External ULPI clock
320 		 *  TTL_MODE  - Internal UTMI clock
321 		 *  HSIC_MODE - Internal 480Mhz and 60Mhz clocks
322 		 */
323 		if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) {
324 			//ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK);
325 			prcm_enablemodule(PRCM_USBP1_PHY);
326 		} else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
327 			prcm_enablemodule(PRCM_USBP1_UTMI);
328 		else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
329 			prcm_enablemodule(PRCM_USBP1_HSIC);
330 
331 		if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) {
332 			//ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK);
333 			prcm_enablemodule(PRCM_USBP2_PHY);
334 		} else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
335 			prcm_enablemodule(PRCM_USBP2_UTMI);
336 		else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
337 			prcm_enablemodule(PRCM_USBP2_HSIC);
338 	}
339 
340 	/* Put UHH in SmartIdle/SmartStandby mode */
341 	reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
342 	    OMAP_USBHOST_UHH_SYSCONFIG);
343 	if (sc->ehci_rev == OMAP_EHCI_REV1) {
344 		reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK |
345 		         UHH_SYSCONFIG_MIDLEMODE_MASK);
346 		reg |= (UHH_SYSCONFIG_ENAWAKEUP |
347 		        UHH_SYSCONFIG_AUTOIDLE |
348 		        UHH_SYSCONFIG_CLOCKACTIVITY |
349 		        UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE |
350 		        UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY);
351 	} else if (sc->ehci_rev == OMAP_EHCI_REV2) {
352 		reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK;
353 		reg |=  UHH_SYSCONFIG_IDLEMODE_NOIDLE;
354 		reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK;
355 		reg |=  UHH_SYSCONFIG_STANDBYMODE_NOSTDBY;
356 	}
357 	bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_SYSCONFIG,
358 	    reg);
359 
360 	reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
361 	    OMAP_USBHOST_UHH_HOSTCONFIG);
362 
363 	/* Setup ULPI bypass and burst configurations */
364 	reg |= (UHH_HOSTCONFIG_ENA_INCR4 |
365 		UHH_HOSTCONFIG_ENA_INCR8 |
366 		UHH_HOSTCONFIG_ENA_INCR16);
367 	reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN;
368 
369 	if (sc->ehci_rev == OMAP_EHCI_REV1) {
370 		if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
371 			reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS;
372 		if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
373 			reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS;
374 		if (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
375 			reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS;
376 
377 		/* Bypass the TLL module for PHY mode operation */
378 		if ((sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
379 		    (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
380 		    (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
381 			reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS;
382 		else
383 			reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS;
384 	} else if (sc->ehci_rev == OMAP_EHCI_REV2) {
385 		reg |=  UHH_HOSTCONFIG_APP_START_CLK;
386 
387 		/* Clear port mode fields for PHY mode*/
388 		reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK;
389 		reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK;
390 
391 		if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
392 			reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY;
393 		else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
394 			reg |= UHH_HOSTCONFIG_P1_MODE_HSIC;
395 
396 		if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
397 			reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY;
398 		else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
399 			reg |= UHH_HOSTCONFIG_P2_MODE_HSIC;
400 	}
401 
402 	bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_HOSTCONFIG, reg);
403 
404 	/* If any of the ports are configured in TLL mode, enable them */
405 	for (i = 0; i < OMAP_HS_USB_PORTS; i++)
406 		if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY)
407 			tll_ch_mask |= 1 << i;
408 
409 	/* Enable UTMI mode for required TLL channels */
410 #ifdef notyet
411 	if (tll_ch_mask)
412 		omap_ehci_utmi_init(sc, tll_ch_mask);
413 #endif
414 
415 	/* Release the PHY reset signal now we have configured everything */
416 	if (reset_performed) {
417 		/* Delay for 10ms */
418 		delay(10000);
419 
420 		/* Release reset */
421 		for (i = 0; i < 3; i++) {
422 			if (sc->phy_reset[i] && (sc->reset_gpio_pin[i] != -1))
423 				omgpio_set_bit(sc->reset_gpio_pin[i]);
424 		}
425 	}
426 
427 	/* Set the interrupt threshold control, it controls the maximum rate at
428 	 * which the host controller issues interrupts.  We set it to 1 microframe
429 	 * at startup - the default is 8 mircoframes (equates to 1ms).
430 	 */
431 	reg = bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD);
432 	reg &= 0xff00ffff;
433 	reg |= (1 << 16);
434 	bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD, reg);
435 
436 	/* Soft reset the PHY using PHY reset command over ULPI */
437 	for (i = 0; i < OMAP_HS_USB_PORTS; i++)
438 		if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY)
439 			omehci_soft_phy_reset(sc, i);
440 
441 	return(0);
442 }
443 
444 void
445 omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port)
446 {
447 	unsigned long timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
448 	uint32_t reg;
449 
450 	reg = ULPI_FUNC_CTRL_RESET
451 		/* FUNCTION_CTRL_SET register */
452 		| (ULPI_SET(ULPI_FUNC_CTRL) << OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT)
453 		/* Write */
454 		| (2 << OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT)
455 		/* PORTn */
456 		| ((port + 1) << OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT)
457 		/* start ULPI access*/
458 		| (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT);
459 
460 	bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI, reg);
461 
462 	timeout += 1000000;
463 	/* Wait for ULPI access completion */
464 	while ((bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI)
465 			& (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT))) {
466 
467 		/* Sleep for a tick */
468 		delay(10);
469 
470 		if (timeout-- == 0) {
471 			printf("PHY reset operation timed out\n");
472 			break;
473 		}
474 	}
475 }
476 
477 int
478 omehci_detach(struct device *self, int flags)
479 {
480 	struct omehci_softc		*sc = (struct omehci_softc *)self;
481 	int				rv;
482 
483 	rv = ehci_detach(self, flags);
484 	if (rv)
485 		return (rv);
486 
487 	if (sc->sc_ih != NULL) {
488 		arm_intr_disestablish(sc->sc_ih);
489 		sc->sc_ih = NULL;
490 	}
491 
492 	if (sc->sc.sc_size) {
493 		bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
494 		sc->sc.sc_size = 0;
495 	}
496 
497 	/* XXX: stop clock */
498 
499 	return (0);
500 }
501 
502 int
503 omehci_activate(struct device *self, int act)
504 {
505 	struct omehci_softc *sc = (struct omehci_softc *)self;
506 
507 	switch (act) {
508 	case DVACT_SUSPEND:
509 		sc->sc.sc_bus.use_polling++;
510 		/* FIXME */
511 		sc->sc.sc_bus.use_polling--;
512 		break;
513 	case DVACT_RESUME:
514 		sc->sc.sc_bus.use_polling++;
515 		/* FIXME */
516 		sc->sc.sc_bus.use_polling--;
517 		break;
518 	case DVACT_POWERDOWN:
519 		ehci_reset(&sc->sc);
520 		break;
521 	}
522 	return 0;
523 }
524 
525 void
526 omehci_v4_early_init()
527 {
528 	omgpio_set_dir(1, OMGPIO_DIR_OUT);
529 	omgpio_clear_bit(1);
530 	omgpio_set_dir(62, OMGPIO_DIR_OUT);
531 	omgpio_clear_bit(62);
532 
533 	/* wait for power down */
534 	delay(1000);
535 
536 	omgpio_set_bit(1);
537 	omgpio_set_bit(62);
538 
539 	/* wait until powered up */
540 	delay(1000);
541 }
542