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