xref: /openbsd-src/sys/arch/armv7/omap/omehci.c (revision ea05d060d200e3b3c0cc54eab5d48fb53a7250b8)
1*ea05d060Sderaadt /*	$OpenBSD: omehci.c,v 1.11 2024/08/20 16:24:50 deraadt Exp $ */
28eda2d14Spatrick 
38eda2d14Spatrick /*
48eda2d14Spatrick  * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
58eda2d14Spatrick  *
68eda2d14Spatrick  * Permission to use, copy, modify, and distribute this software for any
78eda2d14Spatrick  * purpose with or without fee is hereby granted, provided that the above
88eda2d14Spatrick  * copyright notice and this permission notice appear in all copies.
98eda2d14Spatrick  *
108eda2d14Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
118eda2d14Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
128eda2d14Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
138eda2d14Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
148eda2d14Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
158eda2d14Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
168eda2d14Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
178eda2d14Spatrick  */
188eda2d14Spatrick 
198eda2d14Spatrick /*-
208eda2d14Spatrick  * Copyright (c) 2011
218eda2d14Spatrick  *	Ben Gray <ben.r.gray@gmail.com>.
228eda2d14Spatrick  * All rights reserved.
238eda2d14Spatrick  *
248eda2d14Spatrick  * Redistribution and use in source and binary forms, with or without
258eda2d14Spatrick  * modification, are permitted provided that the following conditions
268eda2d14Spatrick  * are met:
278eda2d14Spatrick  * 1. Redistributions of source code must retain the above copyright
288eda2d14Spatrick  *    notice, this list of conditions and the following disclaimer.
298eda2d14Spatrick  * 2. Redistributions in binary form must reproduce the above copyright
308eda2d14Spatrick  *    notice, this list of conditions and the following disclaimer in the
318eda2d14Spatrick  *    documentation and/or other materials provided with the distribution.
328eda2d14Spatrick  *
338eda2d14Spatrick  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
348eda2d14Spatrick  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
358eda2d14Spatrick  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
368eda2d14Spatrick  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
378eda2d14Spatrick  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
388eda2d14Spatrick  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
398eda2d14Spatrick  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
408eda2d14Spatrick  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
418eda2d14Spatrick  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
428eda2d14Spatrick  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
438eda2d14Spatrick  * SUCH DAMAGE.
448eda2d14Spatrick  */
458eda2d14Spatrick 
468eda2d14Spatrick #include <sys/param.h>
478eda2d14Spatrick #include <sys/systm.h>
488eda2d14Spatrick #include <sys/device.h>
498eda2d14Spatrick #include <sys/kernel.h>
508eda2d14Spatrick 
518eda2d14Spatrick #include <machine/intr.h>
528eda2d14Spatrick #include <machine/bus.h>
537894c39eSjsg #include <machine/fdt.h>
548eda2d14Spatrick 
558eda2d14Spatrick #include <dev/usb/usb.h>
568eda2d14Spatrick #include <dev/usb/usbdi.h>
578eda2d14Spatrick #include <dev/usb/usbdivar.h>
588eda2d14Spatrick 
598eda2d14Spatrick #include <armv7/omap/prcmvar.h>
608eda2d14Spatrick #include <armv7/omap/omehcivar.h>
618eda2d14Spatrick 
627894c39eSjsg #include <dev/ofw/openfirm.h>
6368795409Skettenis #include <dev/ofw/ofw_misc.h>
647894c39eSjsg #include <dev/ofw/fdt.h>
657894c39eSjsg 
668eda2d14Spatrick #include <dev/usb/ehcireg.h>
678eda2d14Spatrick #include <dev/usb/ehcivar.h>
688eda2d14Spatrick 
697894c39eSjsg int	omehci_match(struct device *, void *, void *);
708eda2d14Spatrick void	omehci_attach(struct device *, struct device *, void *);
718eda2d14Spatrick int	omehci_detach(struct device *, int);
728eda2d14Spatrick int	omehci_activate(struct device *, int);
738eda2d14Spatrick 
748eda2d14Spatrick struct omehci_softc {
758eda2d14Spatrick 	struct ehci_softc	 sc;
768eda2d14Spatrick 	void			*sc_ih;
778eda2d14Spatrick 	bus_space_handle_t	 uhh_ioh;
788eda2d14Spatrick 	bus_space_handle_t	 tll_ioh;
798eda2d14Spatrick 
808eda2d14Spatrick 	uint32_t		 ehci_rev;
818eda2d14Spatrick 	uint32_t		 tll_avail;
828eda2d14Spatrick 
838eda2d14Spatrick 	uint32_t		 port_mode[OMAP_HS_USB_PORTS];
848eda2d14Spatrick };
858eda2d14Spatrick 
868eda2d14Spatrick int omehci_init(struct omehci_softc *);
878eda2d14Spatrick void omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port);
888eda2d14Spatrick 
899fdf0c62Smpi const struct cfattach omehci_ca = {
907894c39eSjsg 	sizeof (struct omehci_softc), omehci_match, omehci_attach,
918eda2d14Spatrick 	omehci_detach, omehci_activate
928eda2d14Spatrick };
938eda2d14Spatrick 
947894c39eSjsg struct cfdriver omehci_cd = {
957894c39eSjsg 	NULL, "omehci", DV_DULL
967894c39eSjsg };
977894c39eSjsg 
987894c39eSjsg int
997894c39eSjsg omehci_match(struct device *parent, void *match, void *aux)
1007894c39eSjsg {
1017894c39eSjsg 	struct fdt_attach_args *faa = aux;
1027894c39eSjsg 
1037894c39eSjsg 	return OF_is_compatible(faa->fa_node, "ti,usbhs-host");
1047894c39eSjsg }
1057894c39eSjsg 
1068eda2d14Spatrick void
1078eda2d14Spatrick omehci_attach(struct device *parent, struct device *self, void *aux)
1088eda2d14Spatrick {
1098eda2d14Spatrick 	struct omehci_softc	*sc = (struct omehci_softc *)self;
1107894c39eSjsg 	struct fdt_attach_args *faa = aux;
1118eda2d14Spatrick 	usbd_status		 r;
1128eda2d14Spatrick 	char			*devname = sc->sc.sc_bus.bdev.dv_xname;
1138eda2d14Spatrick 	uint32_t		 i;
1147894c39eSjsg 	char			 port_mode[16];
1157894c39eSjsg 	char			 name[32];
1167894c39eSjsg 	int			 node;
1177894c39eSjsg 	uint32_t		 reg[2];
1188eda2d14Spatrick 
1197894c39eSjsg 	if (faa->fa_nreg < 1)
1207894c39eSjsg 		return;
1217894c39eSjsg 
1227894c39eSjsg 	sc->sc.iot = faa->fa_iot;
1237894c39eSjsg 	sc->sc.sc_bus.dmatag = faa->fa_dmat;
1248eda2d14Spatrick 
1258eda2d14Spatrick 	/* set defaults */
12668795409Skettenis 	for (i = 0; i < OMAP_HS_USB_PORTS; i++)
1278eda2d14Spatrick 		sc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN;
1288eda2d14Spatrick 
1297894c39eSjsg 	strlcpy(name, "portX-mode", sizeof(name));
1307894c39eSjsg 
1317894c39eSjsg 	for (i = 0; i < OMAP_HS_USB_PORTS; i++) {
1327894c39eSjsg 		name[4] = '1' + i;
1337894c39eSjsg 		memset(port_mode, 0, sizeof(port_mode));
1347894c39eSjsg 
1357894c39eSjsg 		if (OF_getprop(faa->fa_node, name, port_mode,
1367894c39eSjsg 		    sizeof(port_mode)) == -1)
1377894c39eSjsg 			continue;
1387894c39eSjsg 
1397894c39eSjsg 		if (strcmp(port_mode, "ehci-phy") == 0)
1407894c39eSjsg 			sc->port_mode[i] = EHCI_HCD_OMAP_MODE_PHY;
1417894c39eSjsg 		if (strcmp(port_mode, "ehci-hsic") == 0)
1427894c39eSjsg 			sc->port_mode[i] = EHCI_HCD_OMAP_MODE_HSIC;
1437894c39eSjsg 		if (strcmp(port_mode, "ehci-tll") == 0)
1447894c39eSjsg 			sc->port_mode[i] = EHCI_HCD_OMAP_MODE_TLL ;
1457894c39eSjsg 	}
1467894c39eSjsg 
1477894c39eSjsg 	for (node = OF_child(faa->fa_node); node; node = OF_peer(node)) {
1487894c39eSjsg 		if (OF_is_compatible(node, "ti,ehci-omap"))
1497894c39eSjsg 			break;
1507894c39eSjsg 	}
1517894c39eSjsg 
1527894c39eSjsg 	if (node == 0)
1537894c39eSjsg 		panic("could not find ehci child node");
1547894c39eSjsg 
1557894c39eSjsg 	if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) != sizeof(reg))
1567894c39eSjsg 		return;
1577894c39eSjsg 
1588eda2d14Spatrick 	/* Map I/O space */
1597894c39eSjsg 	if (bus_space_map(sc->sc.iot, reg[0], reg[1], 0, &sc->sc.ioh)) {
1608eda2d14Spatrick 		printf(": cannot map mem space\n");
1618eda2d14Spatrick 		goto out;
1628eda2d14Spatrick 	}
1637894c39eSjsg 	sc->sc.sc_size = reg[1];
1648eda2d14Spatrick 
1657894c39eSjsg 	if (bus_space_map(sc->sc.iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
1667894c39eSjsg 	    0, &sc->uhh_ioh)) {
1678eda2d14Spatrick 		printf(": cannot map mem space\n");
1688eda2d14Spatrick 		goto mem0;
1698eda2d14Spatrick 	}
1708eda2d14Spatrick 
1717894c39eSjsg #if 0
1728eda2d14Spatrick 	if (sc->tll_avail &&
1738d957e1aSsyl 	    bus_space_map(sc->sc.iot, aa->aa_dev->mem[2].addr,
1748d957e1aSsyl 	    aa->aa_dev->mem[2].size, 0, &sc->tll_ioh)) {
1758eda2d14Spatrick 		printf(": cannot map mem space\n");
1768eda2d14Spatrick 		goto mem1;
1778eda2d14Spatrick 	}
1787894c39eSjsg #endif
1798eda2d14Spatrick 
1808eda2d14Spatrick 	printf("\n");
1818eda2d14Spatrick 
1826f07450fSjsg 	phy_enable_idx(node, 0);
1838eda2d14Spatrick 
1848eda2d14Spatrick 	if (omehci_init(sc))
1858eda2d14Spatrick 		return;
1868eda2d14Spatrick 
1878eda2d14Spatrick 	/* Disable interrupts, so we don't get any spurious ones. */
1888eda2d14Spatrick 	sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH);
1898eda2d14Spatrick 	EOWRITE2(&sc->sc, EHCI_USBINTR, 0);
1908eda2d14Spatrick 
1917894c39eSjsg 	sc->sc_ih = arm_intr_establish_fdt(node, IPL_USB,
1928eda2d14Spatrick 	    ehci_intr, &sc->sc, devname);
1938eda2d14Spatrick 	if (sc->sc_ih == NULL) {
1948eda2d14Spatrick 		printf(": unable to establish interrupt\n");
1958eda2d14Spatrick 		printf("XXX - disable ehci and prcm");
1968eda2d14Spatrick 		goto mem2;
1978eda2d14Spatrick 	}
1988eda2d14Spatrick 
1998eda2d14Spatrick 	strlcpy(sc->sc.sc_vendor, "TI OMAP", sizeof(sc->sc.sc_vendor));
2008eda2d14Spatrick 	r = ehci_init(&sc->sc);
2018eda2d14Spatrick 	if (r != USBD_NORMAL_COMPLETION) {
2028eda2d14Spatrick 		printf("%s: init failed, error=%d\n", devname, r);
2038eda2d14Spatrick 		printf("XXX - disable ehci and prcm");
2048eda2d14Spatrick 		goto intr;
2058eda2d14Spatrick 	}
2068eda2d14Spatrick 
207ad21ef77Smpi 	config_found(self, &sc->sc.sc_bus, usbctlprint);
2088eda2d14Spatrick 
2098eda2d14Spatrick 	goto out;
2108eda2d14Spatrick 
2118eda2d14Spatrick intr:
2128eda2d14Spatrick 	arm_intr_disestablish(sc->sc_ih);
2138eda2d14Spatrick 	sc->sc_ih = NULL;
2148eda2d14Spatrick mem2:
2157894c39eSjsg #if 0
2168d957e1aSsyl 	bus_space_unmap(sc->sc.iot, sc->tll_ioh, aa->aa_dev->mem[2].size);
2178eda2d14Spatrick mem1:
2187894c39eSjsg #endif
2197894c39eSjsg 	bus_space_unmap(sc->sc.iot, sc->uhh_ioh, faa->fa_reg[0].size);
2208eda2d14Spatrick mem0:
2218eda2d14Spatrick 	bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
2228eda2d14Spatrick 	sc->sc.sc_size = 0;
2238eda2d14Spatrick out:
2248eda2d14Spatrick 	return;
2258eda2d14Spatrick }
2268eda2d14Spatrick 
2278eda2d14Spatrick int
2288eda2d14Spatrick omehci_init(struct omehci_softc *sc)
2298eda2d14Spatrick {
2308eda2d14Spatrick 	uint32_t i = 0, reg;
2318eda2d14Spatrick 	uint32_t reset_performed = 0;
2328eda2d14Spatrick 	uint32_t timeout = 0;
2338eda2d14Spatrick 	uint32_t tll_ch_mask = 0;
2348eda2d14Spatrick 
2358eda2d14Spatrick 	/* enable high speed usb host clock */
2368eda2d14Spatrick 	prcm_enablemodule(PRCM_USB);
2378eda2d14Spatrick 
2388eda2d14Spatrick 	/* Hold the PHY in RESET for enough time till DIR is high */
2398eda2d14Spatrick 	if (reset_performed)
2408eda2d14Spatrick 		delay(10);
2418eda2d14Spatrick 
2428eda2d14Spatrick 	/* Read the UHH revision */
2438eda2d14Spatrick 	sc->ehci_rev = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
2448eda2d14Spatrick 	    OMAP_USBHOST_UHH_REVISION);
2458eda2d14Spatrick 
24636fd90dcSjsg 	/* Initialise the low level interface module(s) */
2478eda2d14Spatrick 	if (sc->ehci_rev == OMAP_EHCI_REV1) {
2488eda2d14Spatrick 		/* Enable the USB TLL */
2498eda2d14Spatrick 		prcm_enablemodule(PRCM_USBTLL);
2508eda2d14Spatrick 
2518eda2d14Spatrick 		/* Perform TLL soft reset, and wait until reset is complete */
2528eda2d14Spatrick 		bus_space_write_4(sc->sc.iot, sc->tll_ioh,
2538eda2d14Spatrick 		    OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET);
2548eda2d14Spatrick 
2558eda2d14Spatrick 		/* Set the timeout to 100ms*/
2568eda2d14Spatrick 		timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
2578eda2d14Spatrick 
2588eda2d14Spatrick 		/* Wait for TLL reset to complete */
2598eda2d14Spatrick 		while ((bus_space_read_4(sc->sc.iot, sc->tll_ioh,
2608eda2d14Spatrick 		    OMAP_USBTLL_SYSSTATUS) & TLL_SYSSTATUS_RESETDONE)
2618eda2d14Spatrick 		    == 0x00) {
2628eda2d14Spatrick 
2638eda2d14Spatrick 			/* Sleep for a tick */
2648eda2d14Spatrick 			delay(10);
2658eda2d14Spatrick 
2668eda2d14Spatrick 			if (timeout-- == 0) {
2678eda2d14Spatrick 				return 1;
2688eda2d14Spatrick 			}
2698eda2d14Spatrick 		}
2708eda2d14Spatrick 
2718eda2d14Spatrick 		bus_space_write_4(sc->sc.iot, sc->tll_ioh,
2728eda2d14Spatrick 		    OMAP_USBTLL_SYSCONFIG,
2738eda2d14Spatrick 		    TLL_SYSCONFIG_ENAWAKEUP | TLL_SYSCONFIG_AUTOIDLE |
2748eda2d14Spatrick 		    TLL_SYSCONFIG_SIDLE_SMART_IDLE | TLL_SYSCONFIG_CACTIVITY);
2758eda2d14Spatrick 	} else if (sc->ehci_rev == OMAP_EHCI_REV2) {
2768eda2d14Spatrick 		/* For OMAP44xx devices you have to enable the per-port clocks:
2778eda2d14Spatrick 		 *  PHY_MODE  - External ULPI clock
2788eda2d14Spatrick 		 *  TTL_MODE  - Internal UTMI clock
2798eda2d14Spatrick 		 *  HSIC_MODE - Internal 480Mhz and 60Mhz clocks
2808eda2d14Spatrick 		 */
2818eda2d14Spatrick 		if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) {
2828eda2d14Spatrick 			//ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK);
2838eda2d14Spatrick 			prcm_enablemodule(PRCM_USBP1_PHY);
2848eda2d14Spatrick 		} else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
2858eda2d14Spatrick 			prcm_enablemodule(PRCM_USBP1_UTMI);
2868eda2d14Spatrick 		else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
2878eda2d14Spatrick 			prcm_enablemodule(PRCM_USBP1_HSIC);
2888eda2d14Spatrick 
2898eda2d14Spatrick 		if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) {
2908eda2d14Spatrick 			//ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK);
2918eda2d14Spatrick 			prcm_enablemodule(PRCM_USBP2_PHY);
2928eda2d14Spatrick 		} else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
2938eda2d14Spatrick 			prcm_enablemodule(PRCM_USBP2_UTMI);
2948eda2d14Spatrick 		else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
2958eda2d14Spatrick 			prcm_enablemodule(PRCM_USBP2_HSIC);
2968eda2d14Spatrick 	}
2978eda2d14Spatrick 
2988eda2d14Spatrick 	/* Put UHH in SmartIdle/SmartStandby mode */
2998eda2d14Spatrick 	reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
3008eda2d14Spatrick 	    OMAP_USBHOST_UHH_SYSCONFIG);
3018eda2d14Spatrick 	if (sc->ehci_rev == OMAP_EHCI_REV1) {
3028eda2d14Spatrick 		reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK |
3038eda2d14Spatrick 		         UHH_SYSCONFIG_MIDLEMODE_MASK);
3048eda2d14Spatrick 		reg |= (UHH_SYSCONFIG_ENAWAKEUP |
3058eda2d14Spatrick 		        UHH_SYSCONFIG_AUTOIDLE |
3068eda2d14Spatrick 		        UHH_SYSCONFIG_CLOCKACTIVITY |
3078eda2d14Spatrick 		        UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE |
3088eda2d14Spatrick 		        UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY);
3098eda2d14Spatrick 	} else if (sc->ehci_rev == OMAP_EHCI_REV2) {
3108eda2d14Spatrick 		reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK;
3118eda2d14Spatrick 		reg |=  UHH_SYSCONFIG_IDLEMODE_NOIDLE;
3128eda2d14Spatrick 		reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK;
3138eda2d14Spatrick 		reg |=  UHH_SYSCONFIG_STANDBYMODE_NOSTDBY;
3148eda2d14Spatrick 	}
3158eda2d14Spatrick 	bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_SYSCONFIG,
3168eda2d14Spatrick 	    reg);
3178eda2d14Spatrick 
3188eda2d14Spatrick 	reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
3198eda2d14Spatrick 	    OMAP_USBHOST_UHH_HOSTCONFIG);
3208eda2d14Spatrick 
3218eda2d14Spatrick 	/* Setup ULPI bypass and burst configurations */
3228eda2d14Spatrick 	reg |= (UHH_HOSTCONFIG_ENA_INCR4 |
3238eda2d14Spatrick 		UHH_HOSTCONFIG_ENA_INCR8 |
3248eda2d14Spatrick 		UHH_HOSTCONFIG_ENA_INCR16);
3258eda2d14Spatrick 	reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN;
3268eda2d14Spatrick 
3278eda2d14Spatrick 	if (sc->ehci_rev == OMAP_EHCI_REV1) {
3288eda2d14Spatrick 		if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
3298eda2d14Spatrick 			reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS;
3308eda2d14Spatrick 		if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
3318eda2d14Spatrick 			reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS;
3328eda2d14Spatrick 		if (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
3338eda2d14Spatrick 			reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS;
3348eda2d14Spatrick 
3358eda2d14Spatrick 		/* Bypass the TLL module for PHY mode operation */
3368eda2d14Spatrick 		if ((sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
3378eda2d14Spatrick 		    (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
3388eda2d14Spatrick 		    (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
3398eda2d14Spatrick 			reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS;
3408eda2d14Spatrick 		else
3418eda2d14Spatrick 			reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS;
3428eda2d14Spatrick 	} else if (sc->ehci_rev == OMAP_EHCI_REV2) {
3438eda2d14Spatrick 		reg |=  UHH_HOSTCONFIG_APP_START_CLK;
3448eda2d14Spatrick 
3458eda2d14Spatrick 		/* Clear port mode fields for PHY mode*/
3468eda2d14Spatrick 		reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK;
3478eda2d14Spatrick 		reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK;
3488eda2d14Spatrick 
3498eda2d14Spatrick 		if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
3508eda2d14Spatrick 			reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY;
3518eda2d14Spatrick 		else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
3528eda2d14Spatrick 			reg |= UHH_HOSTCONFIG_P1_MODE_HSIC;
3538eda2d14Spatrick 
3548eda2d14Spatrick 		if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
3558eda2d14Spatrick 			reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY;
3568eda2d14Spatrick 		else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
3578eda2d14Spatrick 			reg |= UHH_HOSTCONFIG_P2_MODE_HSIC;
3588eda2d14Spatrick 	}
3598eda2d14Spatrick 
3608eda2d14Spatrick 	bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_HOSTCONFIG, reg);
3618eda2d14Spatrick 
3628eda2d14Spatrick 	/* If any of the ports are configured in TLL mode, enable them */
3638eda2d14Spatrick 	for (i = 0; i < OMAP_HS_USB_PORTS; i++)
3648eda2d14Spatrick 		if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY)
3658eda2d14Spatrick 			tll_ch_mask |= 1 << i;
3668eda2d14Spatrick 
3678eda2d14Spatrick 	/* Enable UTMI mode for required TLL channels */
3688eda2d14Spatrick #ifdef notyet
3698eda2d14Spatrick 	if (tll_ch_mask)
3708eda2d14Spatrick 		omap_ehci_utmi_init(sc, tll_ch_mask);
3718eda2d14Spatrick #endif
3728eda2d14Spatrick 
3738eda2d14Spatrick 	/* Set the interrupt threshold control, it controls the maximum rate at
3748eda2d14Spatrick 	 * which the host controller issues interrupts.  We set it to 1 microframe
3758eda2d14Spatrick 	 * at startup - the default is 8 mircoframes (equates to 1ms).
3768eda2d14Spatrick 	 */
3778eda2d14Spatrick 	reg = bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD);
3788eda2d14Spatrick 	reg &= 0xff00ffff;
3798eda2d14Spatrick 	reg |= (1 << 16);
3808eda2d14Spatrick 	bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD, reg);
3818eda2d14Spatrick 
3828eda2d14Spatrick 	/* Soft reset the PHY using PHY reset command over ULPI */
3838eda2d14Spatrick 	for (i = 0; i < OMAP_HS_USB_PORTS; i++)
3848eda2d14Spatrick 		if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY)
3858eda2d14Spatrick 			omehci_soft_phy_reset(sc, i);
3868eda2d14Spatrick 
3878eda2d14Spatrick 	return(0);
3888eda2d14Spatrick }
3898eda2d14Spatrick 
3908eda2d14Spatrick void
3918eda2d14Spatrick omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port)
3928eda2d14Spatrick {
3938eda2d14Spatrick 	unsigned long timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
3948eda2d14Spatrick 	uint32_t reg;
3958eda2d14Spatrick 
3968eda2d14Spatrick 	reg = ULPI_FUNC_CTRL_RESET
3978eda2d14Spatrick 		/* FUNCTION_CTRL_SET register */
3988eda2d14Spatrick 		| (ULPI_SET(ULPI_FUNC_CTRL) << OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT)
3998eda2d14Spatrick 		/* Write */
4008eda2d14Spatrick 		| (2 << OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT)
4018eda2d14Spatrick 		/* PORTn */
4028eda2d14Spatrick 		| ((port + 1) << OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT)
4038eda2d14Spatrick 		/* start ULPI access*/
4048eda2d14Spatrick 		| (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT);
4058eda2d14Spatrick 
4068eda2d14Spatrick 	bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI, reg);
4078eda2d14Spatrick 
4088eda2d14Spatrick 	timeout += 1000000;
4098eda2d14Spatrick 	/* Wait for ULPI access completion */
4108eda2d14Spatrick 	while ((bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI)
4118eda2d14Spatrick 			& (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT))) {
4128eda2d14Spatrick 
4138eda2d14Spatrick 		/* Sleep for a tick */
4148eda2d14Spatrick 		delay(10);
4158eda2d14Spatrick 
4168eda2d14Spatrick 		if (timeout-- == 0) {
4178eda2d14Spatrick 			printf("PHY reset operation timed out\n");
4188eda2d14Spatrick 			break;
4198eda2d14Spatrick 		}
4208eda2d14Spatrick 	}
4218eda2d14Spatrick }
4228eda2d14Spatrick 
4238eda2d14Spatrick int
4248eda2d14Spatrick omehci_detach(struct device *self, int flags)
4258eda2d14Spatrick {
4268eda2d14Spatrick 	struct omehci_softc		*sc = (struct omehci_softc *)self;
4278eda2d14Spatrick 	int				rv;
4288eda2d14Spatrick 
429ad21ef77Smpi 	rv = ehci_detach(self, flags);
4308eda2d14Spatrick 	if (rv)
4318eda2d14Spatrick 		return (rv);
4328eda2d14Spatrick 
4338eda2d14Spatrick 	if (sc->sc_ih != NULL) {
4348eda2d14Spatrick 		arm_intr_disestablish(sc->sc_ih);
4358eda2d14Spatrick 		sc->sc_ih = NULL;
4368eda2d14Spatrick 	}
4378eda2d14Spatrick 
4388eda2d14Spatrick 	if (sc->sc.sc_size) {
4398eda2d14Spatrick 		bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
4408eda2d14Spatrick 		sc->sc.sc_size = 0;
4418eda2d14Spatrick 	}
4428eda2d14Spatrick 
4438eda2d14Spatrick 	/* XXX: stop clock */
4448eda2d14Spatrick 
4458eda2d14Spatrick 	return (0);
4468eda2d14Spatrick }
4478eda2d14Spatrick 
4488eda2d14Spatrick int
4498eda2d14Spatrick omehci_activate(struct device *self, int act)
4508eda2d14Spatrick {
4518eda2d14Spatrick 	struct omehci_softc *sc = (struct omehci_softc *)self;
452*ea05d060Sderaadt 	int rv;
4538eda2d14Spatrick 
4548eda2d14Spatrick 	switch (act) {
4558eda2d14Spatrick 	case DVACT_SUSPEND:
456*ea05d060Sderaadt 		rv = config_activate_children(self, act);
4578eda2d14Spatrick 		sc->sc.sc_bus.use_polling++;
4588eda2d14Spatrick 		/* FIXME */
4598eda2d14Spatrick 		sc->sc.sc_bus.use_polling--;
4608eda2d14Spatrick 		break;
4618eda2d14Spatrick 	case DVACT_RESUME:
4628eda2d14Spatrick 		sc->sc.sc_bus.use_polling++;
4638eda2d14Spatrick 		/* FIXME */
4648eda2d14Spatrick 		sc->sc.sc_bus.use_polling--;
465*ea05d060Sderaadt 		rv = config_activate_children(self, act);
4668eda2d14Spatrick 		break;
4678eda2d14Spatrick 	case DVACT_POWERDOWN:
468*ea05d060Sderaadt 		rv = config_activate_children(self, act);
4698eda2d14Spatrick 		ehci_reset(&sc->sc);
4708eda2d14Spatrick 		break;
4718eda2d14Spatrick 	}
472*ea05d060Sderaadt 	return rv;
4738eda2d14Spatrick }
474