1 /* $NetBSD: tegra_usbphy.c,v 1.10 2019/10/13 06:11:31 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: tegra_usbphy.c,v 1.10 2019/10/13 06:11:31 skrll Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/device.h> 35 #include <sys/intr.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/atomic.h> 39 40 #include <arm/nvidia/tegra_reg.h> 41 #include <arm/nvidia/tegra_var.h> 42 #include <arm/nvidia/tegra_usbreg.h> 43 44 #include <dev/fdt/fdtvar.h> 45 46 static int tegra_usbphy_match(device_t, cfdata_t, void *); 47 static void tegra_usbphy_attach(device_t, device_t, void *); 48 49 struct tegra_usbphy_softc { 50 device_t sc_dev; 51 bus_space_tag_t sc_bst; 52 bus_space_handle_t sc_bsh; 53 int sc_phandle; 54 struct clk *sc_clk_reg; 55 struct clk *sc_clk_pll; 56 struct clk *sc_clk_utmip; 57 struct fdtbus_reset *sc_rst_usb; 58 struct fdtbus_reset *sc_rst_utmip; 59 60 struct tegra_gpio_pin *sc_pin_vbus; 61 uint32_t sc_hssync_start_delay; 62 uint32_t sc_idle_wait_delay; 63 uint32_t sc_elastic_limit; 64 uint32_t sc_term_range_adj; 65 uint32_t sc_xcvr_setup; 66 uint32_t sc_xcvr_lsfslew; 67 uint32_t sc_xcvr_lsrslew; 68 uint32_t sc_hssquelch_level; 69 uint32_t sc_hsdiscon_level; 70 uint32_t sc_xcvr_hsslew; 71 }; 72 73 static int tegra_usbphy_parse_properties(struct tegra_usbphy_softc *); 74 static void tegra_usbphy_utmip_init(struct tegra_usbphy_softc *); 75 76 CFATTACH_DECL_NEW(tegra_usbphy, sizeof(struct tegra_usbphy_softc), 77 tegra_usbphy_match, tegra_usbphy_attach, NULL, NULL); 78 79 static int 80 tegra_usbphy_match(device_t parent, cfdata_t cf, void *aux) 81 { 82 const char * const compatible[] = { 83 "nvidia,tegra210-usb-phy", 84 "nvidia,tegra124-usb-phy", 85 "nvidia,tegra30-usb-phy", 86 NULL 87 }; 88 struct fdt_attach_args * const faa = aux; 89 90 return of_match_compatible(faa->faa_phandle, compatible); 91 } 92 93 static void 94 tegra_usbphy_attach(device_t parent, device_t self, void *aux) 95 { 96 struct tegra_usbphy_softc * const sc = device_private(self); 97 struct fdt_attach_args * const faa = aux; 98 struct fdtbus_regulator *reg; 99 const int phandle = faa->faa_phandle; 100 bus_addr_t addr; 101 bus_size_t size; 102 int error; 103 104 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 105 aprint_error(": couldn't get registers\n"); 106 return; 107 } 108 sc->sc_clk_reg = fdtbus_clock_get(phandle, "reg"); 109 if (sc->sc_clk_reg == NULL) { 110 aprint_error(": couldn't get clock reg\n"); 111 return; 112 } 113 sc->sc_clk_pll = fdtbus_clock_get(phandle, "pll_u"); 114 if (sc->sc_clk_pll == NULL) { 115 aprint_error(": couldn't get clock pll_u\n"); 116 return; 117 } 118 sc->sc_clk_utmip = fdtbus_clock_get(phandle, "utmi-pads"); 119 if (sc->sc_clk_utmip == NULL) { 120 aprint_error(": couldn't get clock utmi-pads\n"); 121 return; 122 } 123 sc->sc_rst_usb = fdtbus_reset_get(phandle, "usb"); 124 if (sc->sc_rst_usb == NULL) { 125 aprint_error(": couldn't get reset usb\n"); 126 return; 127 } 128 sc->sc_rst_utmip = fdtbus_reset_get(phandle, "utmi-pads"); 129 if (sc->sc_rst_utmip == NULL) { 130 aprint_error(": couldn't get reset utmi-pads\n"); 131 return; 132 } 133 134 sc->sc_dev = self; 135 sc->sc_phandle = phandle; 136 sc->sc_bst = faa->faa_bst; 137 error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh); 138 if (error) { 139 aprint_error(": couldn't map %#" PRIxBUSADDR ": %d", addr, error); 140 return; 141 } 142 143 aprint_naive("\n"); 144 aprint_normal(": USB PHY\n"); 145 146 if (tegra_usbphy_parse_properties(sc) != 0) 147 return; 148 149 fdtbus_reset_assert(sc->sc_rst_usb); 150 error = clk_enable(sc->sc_clk_reg); 151 if (error) { 152 aprint_error_dev(self, "couldn't enable clock reg: %d\n", 153 error); 154 return; 155 } 156 fdtbus_reset_deassert(sc->sc_rst_usb); 157 158 tegra_usbphy_utmip_init(sc); 159 160 reg = fdtbus_regulator_acquire(phandle, "vbus-supply"); 161 if (reg) { 162 const uint32_t v = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 163 TEGRA_EHCI_PHY_VBUS_SENSORS_REG); 164 if ((v & TEGRA_EHCI_PHY_VBUS_SENSORS_A_VBUS_VLD_STS) == 0) { 165 fdtbus_regulator_enable(reg); 166 } else { 167 aprint_normal_dev(self, "VBUS input active\n"); 168 } 169 } 170 } 171 172 static int 173 tegra_usbphy_parse_properties(struct tegra_usbphy_softc *sc) 174 { 175 #define PROPGET(k, v) \ 176 if (of_getprop_uint32(sc->sc_phandle, (k), (v))) { \ 177 aprint_error_dev(sc->sc_dev, \ 178 "missing property '%s'\n", (k)); \ 179 return EIO; \ 180 } 181 182 PROPGET("nvidia,hssync-start-delay", &sc->sc_hssync_start_delay); 183 PROPGET("nvidia,idle-wait-delay", &sc->sc_idle_wait_delay); 184 PROPGET("nvidia,elastic-limit", &sc->sc_elastic_limit); 185 PROPGET("nvidia,term-range-adj", &sc->sc_term_range_adj); 186 PROPGET("nvidia,xcvr-setup", &sc->sc_xcvr_setup); 187 PROPGET("nvidia,xcvr-lsfslew", &sc->sc_xcvr_lsfslew); 188 PROPGET("nvidia,xcvr-lsrslew", &sc->sc_xcvr_lsrslew); 189 PROPGET("nvidia,hssquelch-level", &sc->sc_hssquelch_level); 190 PROPGET("nvidia,hsdiscon-level", &sc->sc_hsdiscon_level); 191 PROPGET("nvidia,xcvr-hsslew", &sc->sc_xcvr_hsslew); 192 193 return 0; 194 #undef PROPGET 195 } 196 197 static void 198 tegra_usbphy_utmip_init(struct tegra_usbphy_softc *sc) 199 { 200 bus_space_tag_t bst = sc->sc_bst; 201 bus_space_handle_t bsh = sc->sc_bsh; 202 int retry; 203 204 /* Put UTMIP PHY into reset before programming UTMIP config registers */ 205 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG, 206 TEGRA_EHCI_SUSP_CTRL_UTMIP_RESET, 0); 207 208 /* Enable UTMIP PHY mode */ 209 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG, 210 TEGRA_EHCI_SUSP_CTRL_UTMIP_PHY_ENB, 0); 211 212 /* Stop crystal clock */ 213 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_MISC_CFG1_REG, 214 0, TEGRA_EHCI_UTMIP_MISC_CFG1_PHY_XTAL_CLOCKEN); 215 delay(1); 216 217 /* Clear session status */ 218 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_PHY_VBUS_SENSORS_REG, 219 0, 220 TEGRA_EHCI_PHY_VBUS_SENSORS_B_VLD_SW_VALUE | 221 TEGRA_EHCI_PHY_VBUS_SENSORS_B_VLD_SW_EN); 222 223 /* Transceiver configuration */ 224 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG0_REG, 225 __SHIFTIN(4, TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP) | 226 __SHIFTIN(3, TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP_MSB) | 227 __SHIFTIN(sc->sc_xcvr_hsslew, 228 TEGRA_EHCI_UTMIP_XCVR_CFG0_HSSLEW_MSB), 229 TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP | 230 TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP_MSB | 231 TEGRA_EHCI_UTMIP_XCVR_CFG0_HSSLEW_MSB); 232 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG1_REG, 233 __SHIFTIN(sc->sc_term_range_adj, 234 TEGRA_EHCI_UTMIP_XCVR_CFG1_TERM_RANGE_ADJ), 235 TEGRA_EHCI_UTMIP_XCVR_CFG1_TERM_RANGE_ADJ); 236 237 if (of_getprop_bool(sc->sc_phandle, "nvidia,has-utmi-pad-registers")) { 238 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG0_REG, 239 TEGRA_EHCI_UTMIP_BIAS_CFG0_HSDISCON_LEVEL_MSB | 240 __SHIFTIN(sc->sc_hsdiscon_level, 241 TEGRA_EHCI_UTMIP_BIAS_CFG0_HSDISCON_LEVEL), 242 TEGRA_EHCI_UTMIP_BIAS_CFG0_BIASPD | 243 TEGRA_EHCI_UTMIP_BIAS_CFG0_HSDISCON_LEVEL); 244 delay(25); 245 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG1_REG, 246 0, TEGRA_EHCI_UTMIP_BIAS_CFG1_PDTRK_POWERDOWN); 247 } 248 249 /* Misc config */ 250 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_MISC_CFG0_REG, 251 0, 252 TEGRA_EHCI_UTMIP_MISC_CFG0_SUSPEND_EXIT_ON_EDGE); 253 254 /* BIAS cell power down lag */ 255 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG1_REG, 256 __SHIFTIN(5, TEGRA_EHCI_UTMIP_BIAS_CFG1_PDTRK_COUNT), 257 TEGRA_EHCI_UTMIP_BIAS_CFG1_PDTRK_COUNT); 258 259 /* Debounce config */ 260 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_DEBOUNCE_CFG0_REG, 261 __SHIFTIN(0x7530, TEGRA_EHCI_UTMIP_DEBOUNCE_CFG0_A), 262 TEGRA_EHCI_UTMIP_DEBOUNCE_CFG0_A); 263 264 /* Transmit signal preamble config */ 265 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_TX_CFG0_REG, 266 TEGRA_EHCI_UTMIP_TX_CFG0_FS_PREAMBLE_J, 0); 267 268 /* Power-down battery charger circuit */ 269 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BAT_CHRG_CFG0_REG, 270 TEGRA_EHCI_UTMIP_BAT_CHRG_CFG0_PD_CHRG, 0); 271 272 /* Select low speed bias method */ 273 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG0_REG, 274 0, TEGRA_EHCI_UTMIP_XCVR_CFG0_LSBIAS_SEL); 275 276 /* High speed receive config */ 277 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_HSRX_CFG0_REG, 278 __SHIFTIN(sc->sc_idle_wait_delay, 279 TEGRA_EHCI_UTMIP_HSRX_CFG0_IDLE_WAIT) | 280 __SHIFTIN(sc->sc_elastic_limit, 281 TEGRA_EHCI_UTMIP_HSRX_CFG0_ELASTIC_LIMIT), 282 TEGRA_EHCI_UTMIP_HSRX_CFG0_IDLE_WAIT | 283 TEGRA_EHCI_UTMIP_HSRX_CFG0_ELASTIC_LIMIT); 284 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_HSRX_CFG1_REG, 285 __SHIFTIN(sc->sc_hssync_start_delay, 286 TEGRA_EHCI_UTMIP_HSRX_CFG1_SYNC_START_DLY), 287 TEGRA_EHCI_UTMIP_HSRX_CFG1_SYNC_START_DLY); 288 289 /* Start crystal clock */ 290 delay(1); 291 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_MISC_CFG1_REG, 292 TEGRA_EHCI_UTMIP_MISC_CFG1_PHY_XTAL_CLOCKEN, 0); 293 294 /* Bring UTMIP PHY out of reset */ 295 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG, 296 0, TEGRA_EHCI_SUSP_CTRL_UTMIP_RESET); 297 for (retry = 100000; retry > 0; retry--) { 298 const uint32_t susp = bus_space_read_4(bst, bsh, 299 TEGRA_EHCI_SUSP_CTRL_REG); 300 if (susp & TEGRA_EHCI_SUSP_CTRL_PHY_CLK_VALID) 301 break; 302 delay(1); 303 } 304 if (retry == 0) { 305 aprint_error_dev(sc->sc_dev, "PHY clock is not valid\n"); 306 return; 307 } 308 309 /* Disable ICUSB transceiver */ 310 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_ICUSB_CTRL_REG, 311 0, 312 TEGRA_EHCI_ICUSB_CTRL_ENB1); 313 314 /* Power up UTMPI transceiver */ 315 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG0_REG, 316 0, 317 TEGRA_EHCI_UTMIP_XCVR_CFG0_PD_POWERDOWN | 318 TEGRA_EHCI_UTMIP_XCVR_CFG0_PD2_POWERDOWN | 319 TEGRA_EHCI_UTMIP_XCVR_CFG0_PDZI_POWERDOWN); 320 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG1_REG, 321 0, 322 TEGRA_EHCI_UTMIP_XCVR_CFG1_PDDISC_POWERDOWN | 323 TEGRA_EHCI_UTMIP_XCVR_CFG1_PDCHRP_POWERDOWN | 324 TEGRA_EHCI_UTMIP_XCVR_CFG1_PDDR_POWERDOWN); 325 } 326