tegra_usbphy.c revision 1.7.8.2
11.7.8.2Sjdolecek/* $NetBSD: tegra_usbphy.c,v 1.7.8.2 2017/12/03 11:35:54 jdolecek Exp $ */ 21.7.8.2Sjdolecek 31.7.8.2Sjdolecek/*- 41.7.8.2Sjdolecek * Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca> 51.7.8.2Sjdolecek * All rights reserved. 61.7.8.2Sjdolecek * 71.7.8.2Sjdolecek * Redistribution and use in source and binary forms, with or without 81.7.8.2Sjdolecek * modification, are permitted provided that the following conditions 91.7.8.2Sjdolecek * are met: 101.7.8.2Sjdolecek * 1. Redistributions of source code must retain the above copyright 111.7.8.2Sjdolecek * notice, this list of conditions and the following disclaimer. 121.7.8.2Sjdolecek * 2. Redistributions in binary form must reproduce the above copyright 131.7.8.2Sjdolecek * notice, this list of conditions and the following disclaimer in the 141.7.8.2Sjdolecek * documentation and/or other materials provided with the distribution. 151.7.8.2Sjdolecek * 161.7.8.2Sjdolecek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 171.7.8.2Sjdolecek * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 181.7.8.2Sjdolecek * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 191.7.8.2Sjdolecek * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 201.7.8.2Sjdolecek * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211.7.8.2Sjdolecek * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 221.7.8.2Sjdolecek * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231.7.8.2Sjdolecek * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241.7.8.2Sjdolecek * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251.7.8.2Sjdolecek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261.7.8.2Sjdolecek * SUCH DAMAGE. 271.7.8.2Sjdolecek */ 281.7.8.2Sjdolecek 291.7.8.2Sjdolecek#include <sys/cdefs.h> 301.7.8.2Sjdolecek__KERNEL_RCSID(0, "$NetBSD: tegra_usbphy.c,v 1.7.8.2 2017/12/03 11:35:54 jdolecek Exp $"); 311.7.8.2Sjdolecek 321.7.8.2Sjdolecek#include <sys/param.h> 331.7.8.2Sjdolecek#include <sys/bus.h> 341.7.8.2Sjdolecek#include <sys/device.h> 351.7.8.2Sjdolecek#include <sys/intr.h> 361.7.8.2Sjdolecek#include <sys/systm.h> 371.7.8.2Sjdolecek#include <sys/kernel.h> 381.7.8.2Sjdolecek#include <sys/atomic.h> 391.7.8.2Sjdolecek 401.7.8.2Sjdolecek#include <arm/nvidia/tegra_reg.h> 411.7.8.2Sjdolecek#include <arm/nvidia/tegra_var.h> 421.7.8.2Sjdolecek#include <arm/nvidia/tegra_usbreg.h> 431.7.8.2Sjdolecek 441.7.8.2Sjdolecek#include <dev/fdt/fdtvar.h> 451.7.8.2Sjdolecek 461.7.8.2Sjdolecekstatic int tegra_usbphy_match(device_t, cfdata_t, void *); 471.7.8.2Sjdolecekstatic void tegra_usbphy_attach(device_t, device_t, void *); 481.7.8.2Sjdolecek 491.7.8.2Sjdolecekstruct tegra_usbphy_softc { 501.7.8.2Sjdolecek device_t sc_dev; 511.7.8.2Sjdolecek bus_space_tag_t sc_bst; 521.7.8.2Sjdolecek bus_space_handle_t sc_bsh; 531.7.8.2Sjdolecek int sc_phandle; 541.7.8.2Sjdolecek struct clk *sc_clk_reg; 551.7.8.2Sjdolecek struct clk *sc_clk_pll; 561.7.8.2Sjdolecek struct clk *sc_clk_utmip; 571.7.8.2Sjdolecek struct fdtbus_reset *sc_rst_usb; 581.7.8.2Sjdolecek struct fdtbus_reset *sc_rst_utmip; 591.7.8.2Sjdolecek 601.7.8.2Sjdolecek struct tegra_gpio_pin *sc_pin_vbus; 611.7.8.2Sjdolecek uint32_t sc_hssync_start_delay; 621.7.8.2Sjdolecek uint32_t sc_idle_wait_delay; 631.7.8.2Sjdolecek uint32_t sc_elastic_limit; 641.7.8.2Sjdolecek uint32_t sc_term_range_adj; 651.7.8.2Sjdolecek uint32_t sc_xcvr_setup; 661.7.8.2Sjdolecek uint32_t sc_xcvr_lsfslew; 671.7.8.2Sjdolecek uint32_t sc_xcvr_lsrslew; 681.7.8.2Sjdolecek uint32_t sc_hssquelch_level; 691.7.8.2Sjdolecek uint32_t sc_hsdiscon_level; 701.7.8.2Sjdolecek uint32_t sc_xcvr_hsslew; 711.7.8.2Sjdolecek}; 721.7.8.2Sjdolecek 731.7.8.2Sjdolecekstatic int tegra_usbphy_parse_properties(struct tegra_usbphy_softc *); 741.7.8.2Sjdolecekstatic void tegra_usbphy_utmip_init(struct tegra_usbphy_softc *); 751.7.8.2Sjdolecek 761.7.8.2SjdolecekCFATTACH_DECL_NEW(tegra_usbphy, sizeof(struct tegra_usbphy_softc), 771.7.8.2Sjdolecek tegra_usbphy_match, tegra_usbphy_attach, NULL, NULL); 781.7.8.2Sjdolecek 791.7.8.2Sjdolecekstatic int 801.7.8.2Sjdolecektegra_usbphy_match(device_t parent, cfdata_t cf, void *aux) 811.7.8.2Sjdolecek{ 821.7.8.2Sjdolecek const char * const compatible[] = { 831.7.8.2Sjdolecek "nvidia,tegra210-usb-phy", 841.7.8.2Sjdolecek "nvidia,tegra124-usb-phy", 851.7.8.2Sjdolecek "nvidia,tegra30-usb-phy", 861.7.8.2Sjdolecek NULL 871.7.8.2Sjdolecek }; 881.7.8.2Sjdolecek struct fdt_attach_args * const faa = aux; 891.7.8.2Sjdolecek 901.7.8.2Sjdolecek return of_match_compatible(faa->faa_phandle, compatible); 911.7.8.2Sjdolecek} 921.7.8.2Sjdolecek 931.7.8.2Sjdolecekstatic void 941.7.8.2Sjdolecektegra_usbphy_attach(device_t parent, device_t self, void *aux) 951.7.8.2Sjdolecek{ 961.7.8.2Sjdolecek struct tegra_usbphy_softc * const sc = device_private(self); 971.7.8.2Sjdolecek struct fdt_attach_args * const faa = aux; 981.7.8.2Sjdolecek struct fdtbus_regulator *reg; 991.7.8.2Sjdolecek const int phandle = faa->faa_phandle; 1001.7.8.2Sjdolecek bus_addr_t addr; 1011.7.8.2Sjdolecek bus_size_t size; 1021.7.8.2Sjdolecek int error; 1031.7.8.2Sjdolecek 1041.7.8.2Sjdolecek if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 1051.7.8.2Sjdolecek aprint_error(": couldn't get registers\n"); 1061.7.8.2Sjdolecek return; 1071.7.8.2Sjdolecek } 1081.7.8.2Sjdolecek sc->sc_clk_reg = fdtbus_clock_get(phandle, "reg"); 1091.7.8.2Sjdolecek if (sc->sc_clk_reg == NULL) { 1101.7.8.2Sjdolecek aprint_error(": couldn't get clock reg\n"); 1111.7.8.2Sjdolecek return; 1121.7.8.2Sjdolecek } 1131.7.8.2Sjdolecek sc->sc_clk_pll = fdtbus_clock_get(phandle, "pll_u"); 1141.7.8.2Sjdolecek if (sc->sc_clk_pll == NULL) { 1151.7.8.2Sjdolecek aprint_error(": couldn't get clock pll_u\n"); 1161.7.8.2Sjdolecek return; 1171.7.8.2Sjdolecek } 1181.7.8.2Sjdolecek sc->sc_clk_utmip = fdtbus_clock_get(phandle, "utmi-pads"); 1191.7.8.2Sjdolecek if (sc->sc_clk_utmip == NULL) { 1201.7.8.2Sjdolecek aprint_error(": couldn't get clock utmi-pads\n"); 1211.7.8.2Sjdolecek return; 1221.7.8.2Sjdolecek } 1231.7.8.2Sjdolecek sc->sc_rst_usb = fdtbus_reset_get(phandle, "usb"); 1241.7.8.2Sjdolecek if (sc->sc_rst_usb == NULL) { 1251.7.8.2Sjdolecek aprint_error(": couldn't get reset usb\n"); 1261.7.8.2Sjdolecek return; 1271.7.8.2Sjdolecek } 1281.7.8.2Sjdolecek sc->sc_rst_utmip = fdtbus_reset_get(phandle, "utmi-pads"); 1291.7.8.2Sjdolecek if (sc->sc_rst_utmip == NULL) { 1301.7.8.2Sjdolecek aprint_error(": couldn't get reset utmi-pads\n"); 1311.7.8.2Sjdolecek return; 1321.7.8.2Sjdolecek } 1331.7.8.2Sjdolecek 1341.7.8.2Sjdolecek sc->sc_dev = self; 1351.7.8.2Sjdolecek sc->sc_phandle = phandle; 1361.7.8.2Sjdolecek sc->sc_bst = faa->faa_bst; 1371.7.8.2Sjdolecek error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh); 1381.7.8.2Sjdolecek if (error) { 1391.7.8.2Sjdolecek aprint_error(": couldn't map %#llx: %d", (uint64_t)addr, error); 1401.7.8.2Sjdolecek return; 1411.7.8.2Sjdolecek } 1421.7.8.2Sjdolecek 1431.7.8.2Sjdolecek aprint_naive("\n"); 1441.7.8.2Sjdolecek aprint_normal(": USB PHY\n"); 1451.7.8.2Sjdolecek 1461.7.8.2Sjdolecek if (tegra_usbphy_parse_properties(sc) != 0) 1471.7.8.2Sjdolecek return; 1481.7.8.2Sjdolecek 1491.7.8.2Sjdolecek fdtbus_reset_assert(sc->sc_rst_usb); 1501.7.8.2Sjdolecek error = clk_enable(sc->sc_clk_reg); 1511.7.8.2Sjdolecek if (error) { 1521.7.8.2Sjdolecek aprint_error_dev(self, "couldn't enable clock reg: %d\n", 1531.7.8.2Sjdolecek error); 1541.7.8.2Sjdolecek return; 1551.7.8.2Sjdolecek } 1561.7.8.2Sjdolecek fdtbus_reset_deassert(sc->sc_rst_usb); 1571.7.8.2Sjdolecek 1581.7.8.2Sjdolecek tegra_usbphy_utmip_init(sc); 1591.7.8.2Sjdolecek 1601.7.8.2Sjdolecek reg = fdtbus_regulator_acquire(phandle, "vbus-supply"); 1611.7.8.2Sjdolecek if (reg) { 1621.7.8.2Sjdolecek const uint32_t v = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 1631.7.8.2Sjdolecek TEGRA_EHCI_PHY_VBUS_SENSORS_REG); 1641.7.8.2Sjdolecek if ((v & TEGRA_EHCI_PHY_VBUS_SENSORS_A_VBUS_VLD_STS) == 0) { 1651.7.8.2Sjdolecek fdtbus_regulator_enable(reg); 1661.7.8.2Sjdolecek } else { 1671.7.8.2Sjdolecek aprint_normal_dev(self, "VBUS input active\n"); 1681.7.8.2Sjdolecek } 1691.7.8.2Sjdolecek } 1701.7.8.2Sjdolecek} 1711.7.8.2Sjdolecek 1721.7.8.2Sjdolecekstatic int 1731.7.8.2Sjdolecektegra_usbphy_parse_properties(struct tegra_usbphy_softc *sc) 1741.7.8.2Sjdolecek{ 1751.7.8.2Sjdolecek#define PROPGET(k, v) \ 1761.7.8.2Sjdolecek if (of_getprop_uint32(sc->sc_phandle, (k), (v))) { \ 1771.7.8.2Sjdolecek aprint_error_dev(sc->sc_dev, \ 1781.7.8.2Sjdolecek "missing property '%s'\n", (k)); \ 1791.7.8.2Sjdolecek return EIO; \ 1801.7.8.2Sjdolecek } 1811.7.8.2Sjdolecek 1821.7.8.2Sjdolecek PROPGET("nvidia,hssync-start-delay", &sc->sc_hssync_start_delay); 1831.7.8.2Sjdolecek PROPGET("nvidia,idle-wait-delay", &sc->sc_idle_wait_delay); 1841.7.8.2Sjdolecek PROPGET("nvidia,elastic-limit", &sc->sc_elastic_limit); 1851.7.8.2Sjdolecek PROPGET("nvidia,term-range-adj", &sc->sc_term_range_adj); 1861.7.8.2Sjdolecek PROPGET("nvidia,xcvr-setup", &sc->sc_xcvr_setup); 1871.7.8.2Sjdolecek PROPGET("nvidia,xcvr-lsfslew", &sc->sc_xcvr_lsfslew); 1881.7.8.2Sjdolecek PROPGET("nvidia,xcvr-lsrslew", &sc->sc_xcvr_lsrslew); 1891.7.8.2Sjdolecek PROPGET("nvidia,hssquelch-level", &sc->sc_hssquelch_level); 1901.7.8.2Sjdolecek PROPGET("nvidia,hsdiscon-level", &sc->sc_hsdiscon_level); 1911.7.8.2Sjdolecek PROPGET("nvidia,xcvr-hsslew", &sc->sc_xcvr_hsslew); 1921.7.8.2Sjdolecek 1931.7.8.2Sjdolecek return 0; 1941.7.8.2Sjdolecek#undef PROPGET 1951.7.8.2Sjdolecek} 1961.7.8.2Sjdolecek 1971.7.8.2Sjdolecekstatic void 1981.7.8.2Sjdolecektegra_usbphy_utmip_init(struct tegra_usbphy_softc *sc) 1991.7.8.2Sjdolecek{ 2001.7.8.2Sjdolecek bus_space_tag_t bst = sc->sc_bst; 2011.7.8.2Sjdolecek bus_space_handle_t bsh = sc->sc_bsh; 2021.7.8.2Sjdolecek int retry; 2031.7.8.2Sjdolecek 2041.7.8.2Sjdolecek /* Put UTMIP PHY into reset before programming UTMIP config registers */ 2051.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG, 2061.7.8.2Sjdolecek TEGRA_EHCI_SUSP_CTRL_UTMIP_RESET, 0); 2071.7.8.2Sjdolecek 2081.7.8.2Sjdolecek /* Enable UTMIP PHY mode */ 2091.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG, 2101.7.8.2Sjdolecek TEGRA_EHCI_SUSP_CTRL_UTMIP_PHY_ENB, 0); 2111.7.8.2Sjdolecek 2121.7.8.2Sjdolecek /* Stop crystal clock */ 2131.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_MISC_CFG1_REG, 2141.7.8.2Sjdolecek 0, TEGRA_EHCI_UTMIP_MISC_CFG1_PHY_XTAL_CLOCKEN); 2151.7.8.2Sjdolecek delay(1); 2161.7.8.2Sjdolecek 2171.7.8.2Sjdolecek /* Clear session status */ 2181.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_PHY_VBUS_SENSORS_REG, 2191.7.8.2Sjdolecek 0, 2201.7.8.2Sjdolecek TEGRA_EHCI_PHY_VBUS_SENSORS_B_VLD_SW_VALUE | 2211.7.8.2Sjdolecek TEGRA_EHCI_PHY_VBUS_SENSORS_B_VLD_SW_EN); 2221.7.8.2Sjdolecek 2231.7.8.2Sjdolecek /* Transceiver configuration */ 2241.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG0_REG, 2251.7.8.2Sjdolecek __SHIFTIN(4, TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP) | 2261.7.8.2Sjdolecek __SHIFTIN(3, TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP_MSB) | 2271.7.8.2Sjdolecek __SHIFTIN(sc->sc_xcvr_hsslew, 2281.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_XCVR_CFG0_HSSLEW_MSB), 2291.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP | 2301.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP_MSB | 2311.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_XCVR_CFG0_HSSLEW_MSB); 2321.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG1_REG, 2331.7.8.2Sjdolecek __SHIFTIN(sc->sc_term_range_adj, 2341.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_XCVR_CFG1_TERM_RANGE_ADJ), 2351.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_XCVR_CFG1_TERM_RANGE_ADJ); 2361.7.8.2Sjdolecek 2371.7.8.2Sjdolecek if (of_getprop_bool(sc->sc_phandle, "nvidia,has-utmi-pad-registers")) { 2381.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG0_REG, 2391.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_BIAS_CFG0_HSDISCON_LEVEL_MSB | 2401.7.8.2Sjdolecek __SHIFTIN(sc->sc_hsdiscon_level, 2411.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_BIAS_CFG0_HSDISCON_LEVEL), 2421.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_BIAS_CFG0_BIASPD | 2431.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_BIAS_CFG0_HSDISCON_LEVEL); 2441.7.8.2Sjdolecek delay(25); 2451.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG1_REG, 2461.7.8.2Sjdolecek 0, TEGRA_EHCI_UTMIP_BIAS_CFG1_PDTRK_POWERDOWN); 2471.7.8.2Sjdolecek } 2481.7.8.2Sjdolecek 2491.7.8.2Sjdolecek /* Misc config */ 2501.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_MISC_CFG0_REG, 2511.7.8.2Sjdolecek 0, 2521.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_MISC_CFG0_SUSPEND_EXIT_ON_EDGE); 2531.7.8.2Sjdolecek 2541.7.8.2Sjdolecek /* BIAS cell power down lag */ 2551.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG1_REG, 2561.7.8.2Sjdolecek __SHIFTIN(5, TEGRA_EHCI_UTMIP_BIAS_CFG1_PDTRK_COUNT), 2571.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_BIAS_CFG1_PDTRK_COUNT); 2581.7.8.2Sjdolecek 2591.7.8.2Sjdolecek /* Debounce config */ 2601.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_DEBOUNCE_CFG0_REG, 2611.7.8.2Sjdolecek __SHIFTIN(0x7530, TEGRA_EHCI_UTMIP_DEBOUNCE_CFG0_A), 2621.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_DEBOUNCE_CFG0_A); 2631.7.8.2Sjdolecek 2641.7.8.2Sjdolecek /* Transmit signal preamble config */ 2651.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_TX_CFG0_REG, 2661.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_TX_CFG0_FS_PREAMBLE_J, 0); 2671.7.8.2Sjdolecek 2681.7.8.2Sjdolecek /* Power-down battery charger circuit */ 2691.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BAT_CHRG_CFG0_REG, 2701.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_BAT_CHRG_CFG0_PD_CHRG, 0); 2711.7.8.2Sjdolecek 2721.7.8.2Sjdolecek /* Select low speed bias method */ 2731.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG0_REG, 2741.7.8.2Sjdolecek 0, TEGRA_EHCI_UTMIP_XCVR_CFG0_LSBIAS_SEL); 2751.7.8.2Sjdolecek 2761.7.8.2Sjdolecek /* High speed receive config */ 2771.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_HSRX_CFG0_REG, 2781.7.8.2Sjdolecek __SHIFTIN(sc->sc_idle_wait_delay, 2791.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_HSRX_CFG0_IDLE_WAIT) | 2801.7.8.2Sjdolecek __SHIFTIN(sc->sc_elastic_limit, 2811.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_HSRX_CFG0_ELASTIC_LIMIT), 2821.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_HSRX_CFG0_IDLE_WAIT | 2831.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_HSRX_CFG0_ELASTIC_LIMIT); 2841.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_HSRX_CFG1_REG, 2851.7.8.2Sjdolecek __SHIFTIN(sc->sc_hssync_start_delay, 2861.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_HSRX_CFG1_SYNC_START_DLY), 2871.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_HSRX_CFG1_SYNC_START_DLY); 2881.7.8.2Sjdolecek 2891.7.8.2Sjdolecek /* Start crystal clock */ 2901.7.8.2Sjdolecek delay(1); 2911.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_MISC_CFG1_REG, 2921.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_MISC_CFG1_PHY_XTAL_CLOCKEN, 0); 2931.7.8.2Sjdolecek 2941.7.8.2Sjdolecek /* Bring UTMIP PHY out of reset */ 2951.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG, 2961.7.8.2Sjdolecek 0, TEGRA_EHCI_SUSP_CTRL_UTMIP_RESET); 2971.7.8.2Sjdolecek for (retry = 100000; retry > 0; retry--) { 2981.7.8.2Sjdolecek const uint32_t susp = bus_space_read_4(bst, bsh, 2991.7.8.2Sjdolecek TEGRA_EHCI_SUSP_CTRL_REG); 3001.7.8.2Sjdolecek if (susp & TEGRA_EHCI_SUSP_CTRL_PHY_CLK_VALID) 3011.7.8.2Sjdolecek break; 3021.7.8.2Sjdolecek delay(1); 3031.7.8.2Sjdolecek } 3041.7.8.2Sjdolecek if (retry == 0) { 3051.7.8.2Sjdolecek aprint_error_dev(sc->sc_dev, "PHY clock is not valid\n"); 3061.7.8.2Sjdolecek return; 3071.7.8.2Sjdolecek } 3081.7.8.2Sjdolecek 3091.7.8.2Sjdolecek /* Disable ICUSB transceiver */ 3101.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_ICUSB_CTRL_REG, 3111.7.8.2Sjdolecek 0, 3121.7.8.2Sjdolecek TEGRA_EHCI_ICUSB_CTRL_ENB1); 3131.7.8.2Sjdolecek 3141.7.8.2Sjdolecek /* Power up UTMPI transceiver */ 3151.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG0_REG, 3161.7.8.2Sjdolecek 0, 3171.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_XCVR_CFG0_PD_POWERDOWN | 3181.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_XCVR_CFG0_PD2_POWERDOWN | 3191.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_XCVR_CFG0_PDZI_POWERDOWN); 3201.7.8.2Sjdolecek tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG1_REG, 3211.7.8.2Sjdolecek 0, 3221.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_XCVR_CFG1_PDDISC_POWERDOWN | 3231.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_XCVR_CFG1_PDCHRP_POWERDOWN | 3241.7.8.2Sjdolecek TEGRA_EHCI_UTMIP_XCVR_CFG1_PDDR_POWERDOWN); 3251.7.8.2Sjdolecek} 326