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