1 /* $NetBSD: tegra_usbphy.c,v 1.4 2015/12/16 19:46:55 jmcneill 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.4 2015/12/16 19:46:55 jmcneill 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 39 #include <arm/nvidia/tegra_reg.h> 40 #include <arm/nvidia/tegra_var.h> 41 #include <arm/nvidia/tegra_usbreg.h> 42 43 #include <dev/fdt/fdtvar.h> 44 45 /* XXX */ 46 static int 47 tegra_usbphy_addr2port(bus_addr_t addr) 48 { 49 switch (addr) { 50 case TEGRA_AHB_A2_BASE + TEGRA_USB1_OFFSET: 51 return 0; 52 case TEGRA_AHB_A2_BASE + TEGRA_USB2_OFFSET: 53 return 1; 54 case TEGRA_AHB_A2_BASE + TEGRA_USB3_OFFSET: 55 return 2; 56 default: 57 return -1; 58 } 59 } 60 61 static int tegra_usbphy_match(device_t, cfdata_t, void *); 62 static void tegra_usbphy_attach(device_t, device_t, void *); 63 64 struct tegra_usbphy_softc { 65 device_t sc_dev; 66 bus_space_tag_t sc_bst; 67 bus_space_handle_t sc_bsh; 68 int sc_phandle; 69 u_int sc_port; 70 71 struct tegra_gpio_pin *sc_pin_vbus; 72 uint32_t sc_hssync_start_delay; 73 uint32_t sc_idle_wait_delay; 74 uint32_t sc_elastic_limit; 75 uint32_t sc_term_range_adj; 76 uint32_t sc_xcvr_setup; 77 uint32_t sc_xcvr_lsfslew; 78 uint32_t sc_xcvr_lsrslew; 79 uint32_t sc_hssquelch_level; 80 uint32_t sc_hsdiscon_level; 81 uint32_t sc_xcvr_hsslew; 82 }; 83 84 static int tegra_usbphy_parse_properties(struct tegra_usbphy_softc *); 85 static void tegra_usbphy_utmip_init(struct tegra_usbphy_softc *); 86 87 CFATTACH_DECL_NEW(tegra_usbphy, sizeof(struct tegra_usbphy_softc), 88 tegra_usbphy_match, tegra_usbphy_attach, NULL, NULL); 89 90 static int 91 tegra_usbphy_match(device_t parent, cfdata_t cf, void *aux) 92 { 93 const char * const compatible[] = { "nvidia,tegra124-usb-phy", NULL }; 94 struct fdt_attach_args * const faa = aux; 95 96 return of_match_compatible(faa->faa_phandle, compatible); 97 } 98 99 static void 100 tegra_usbphy_attach(device_t parent, device_t self, void *aux) 101 { 102 struct tegra_usbphy_softc * const sc = device_private(self); 103 struct fdt_attach_args * const faa = aux; 104 struct fdtbus_regulator *reg; 105 bus_addr_t addr; 106 bus_size_t size; 107 int error; 108 109 if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) { 110 aprint_error(": couldn't get registers\n"); 111 return; 112 } 113 114 sc->sc_dev = self; 115 sc->sc_phandle = faa->faa_phandle; 116 sc->sc_bst = faa->faa_bst; 117 error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh); 118 if (error) { 119 aprint_error(": couldn't map %#llx: %d", (uint64_t)addr, error); 120 return; 121 } 122 sc->sc_port = tegra_usbphy_addr2port(addr); 123 124 aprint_naive("\n"); 125 aprint_normal(": USB PHY%d\n", sc->sc_port + 1); 126 127 if (tegra_usbphy_parse_properties(sc) != 0) 128 return; 129 130 tegra_car_periph_usb_enable(sc->sc_port); 131 delay(2); 132 133 tegra_usbphy_utmip_init(sc); 134 135 reg = fdtbus_regulator_acquire(faa->faa_phandle, "vbus-supply"); 136 if (reg) { 137 const uint32_t v = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 138 TEGRA_EHCI_PHY_VBUS_SENSORS_REG); 139 if ((v & TEGRA_EHCI_PHY_VBUS_SENSORS_A_VBUS_VLD_STS) == 0) { 140 fdtbus_regulator_enable(reg); 141 } else { 142 aprint_normal_dev(self, "VBUS input active\n"); 143 } 144 } 145 } 146 147 static int 148 tegra_usbphy_parse_properties(struct tegra_usbphy_softc *sc) 149 { 150 #define PROPGET(k, v) \ 151 if (of_getprop_uint32(sc->sc_phandle, (k), (v))) { \ 152 aprint_error_dev(sc->sc_dev, \ 153 "missing property '%s'\n", (k)); \ 154 return EIO; \ 155 } 156 157 PROPGET("nvidia,hssync-start-delay", &sc->sc_hssync_start_delay); 158 PROPGET("nvidia,idle-wait-delay", &sc->sc_idle_wait_delay); 159 PROPGET("nvidia,elastic-limit", &sc->sc_elastic_limit); 160 PROPGET("nvidia,term-range-adj", &sc->sc_term_range_adj); 161 PROPGET("nvidia,xcvr-setup", &sc->sc_xcvr_setup); 162 PROPGET("nvidia,xcvr-lsfslew", &sc->sc_xcvr_lsfslew); 163 PROPGET("nvidia,xcvr-lsrslew", &sc->sc_xcvr_lsrslew); 164 PROPGET("nvidia,hssquelch-level", &sc->sc_hssquelch_level); 165 PROPGET("nvidia,hsdiscon-level", &sc->sc_hsdiscon_level); 166 PROPGET("nvidia,xcvr-hsslew", &sc->sc_xcvr_hsslew); 167 168 return 0; 169 #undef PROPGET 170 } 171 172 static void 173 tegra_usbphy_utmip_init(struct tegra_usbphy_softc *sc) 174 { 175 bus_space_tag_t bst = sc->sc_bst; 176 bus_space_handle_t bsh = sc->sc_bsh; 177 int retry; 178 179 /* Put UTMIP PHY into reset before programming UTMIP config registers */ 180 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG, 181 TEGRA_EHCI_SUSP_CTRL_UTMIP_RESET, 0); 182 183 /* Enable UTMIP PHY mode */ 184 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG, 185 TEGRA_EHCI_SUSP_CTRL_UTMIP_PHY_ENB, 0); 186 187 /* Stop crystal clock */ 188 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_MISC_CFG1_REG, 189 0, TEGRA_EHCI_UTMIP_MISC_CFG1_PHY_XTAL_CLOCKEN); 190 delay(1); 191 192 /* Clear session status */ 193 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_PHY_VBUS_SENSORS_REG, 194 0, 195 TEGRA_EHCI_PHY_VBUS_SENSORS_B_VLD_SW_VALUE | 196 TEGRA_EHCI_PHY_VBUS_SENSORS_B_VLD_SW_EN); 197 198 /* PLL configuration */ 199 tegra_car_utmip_init(); 200 201 /* Transceiver configuration */ 202 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG0_REG, 203 __SHIFTIN(4, TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP) | 204 __SHIFTIN(3, TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP_MSB) | 205 __SHIFTIN(sc->sc_xcvr_hsslew, 206 TEGRA_EHCI_UTMIP_XCVR_CFG0_HSSLEW_MSB), 207 TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP | 208 TEGRA_EHCI_UTMIP_XCVR_CFG0_SETUP_MSB | 209 TEGRA_EHCI_UTMIP_XCVR_CFG0_HSSLEW_MSB); 210 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG1_REG, 211 __SHIFTIN(sc->sc_term_range_adj, 212 TEGRA_EHCI_UTMIP_XCVR_CFG1_TERM_RANGE_ADJ), 213 TEGRA_EHCI_UTMIP_XCVR_CFG1_TERM_RANGE_ADJ); 214 215 if (sc->sc_port == 0) { 216 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG0_REG, 217 TEGRA_EHCI_UTMIP_BIAS_CFG0_HSDISCON_LEVEL_MSB | 218 __SHIFTIN(sc->sc_hsdiscon_level, 219 TEGRA_EHCI_UTMIP_BIAS_CFG0_HSDISCON_LEVEL), 220 TEGRA_EHCI_UTMIP_BIAS_CFG0_HSDISCON_LEVEL); 221 } 222 223 /* Misc config */ 224 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_MISC_CFG0_REG, 225 0, 226 TEGRA_EHCI_UTMIP_MISC_CFG0_SUSPEND_EXIT_ON_EDGE); 227 228 /* BIAS cell power down lag */ 229 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG1_REG, 230 __SHIFTIN(5, TEGRA_EHCI_UTMIP_BIAS_CFG1_PDTRK_COUNT), 231 TEGRA_EHCI_UTMIP_BIAS_CFG1_PDTRK_COUNT); 232 233 /* Debounce config */ 234 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_DEBOUNCE_CFG0_REG, 235 __SHIFTIN(0x7530, TEGRA_EHCI_UTMIP_DEBOUNCE_CFG0_A), 236 TEGRA_EHCI_UTMIP_DEBOUNCE_CFG0_A); 237 238 /* Transmit signal preamble config */ 239 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_TX_CFG0_REG, 240 TEGRA_EHCI_UTMIP_TX_CFG0_FS_PREAMBLE_J, 0); 241 242 /* Power-down battery charger circuit */ 243 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BAT_CHRG_CFG0_REG, 244 TEGRA_EHCI_UTMIP_BAT_CHRG_CFG0_PD_CHRG, 0); 245 246 /* Select low speed bias method */ 247 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG0_REG, 248 0, TEGRA_EHCI_UTMIP_XCVR_CFG0_LSBIAS_SEL); 249 250 /* High speed receive config */ 251 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_HSRX_CFG0_REG, 252 __SHIFTIN(sc->sc_idle_wait_delay, 253 TEGRA_EHCI_UTMIP_HSRX_CFG0_IDLE_WAIT) | 254 __SHIFTIN(sc->sc_elastic_limit, 255 TEGRA_EHCI_UTMIP_HSRX_CFG0_ELASTIC_LIMIT), 256 TEGRA_EHCI_UTMIP_HSRX_CFG0_IDLE_WAIT | 257 TEGRA_EHCI_UTMIP_HSRX_CFG0_ELASTIC_LIMIT); 258 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_HSRX_CFG1_REG, 259 __SHIFTIN(sc->sc_hssync_start_delay, 260 TEGRA_EHCI_UTMIP_HSRX_CFG1_SYNC_START_DLY), 261 TEGRA_EHCI_UTMIP_HSRX_CFG1_SYNC_START_DLY); 262 263 /* Start crystal clock */ 264 delay(1); 265 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_MISC_CFG1_REG, 266 TEGRA_EHCI_UTMIP_MISC_CFG1_PHY_XTAL_CLOCKEN, 0); 267 268 /* Clear port PLL powerdown status */ 269 tegra_car_utmip_enable(sc->sc_port); 270 271 /* Bring UTMIP PHY out of reset */ 272 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG, 273 0, TEGRA_EHCI_SUSP_CTRL_UTMIP_RESET); 274 for (retry = 100000; retry > 0; retry--) { 275 const uint32_t susp = bus_space_read_4(bst, bsh, 276 TEGRA_EHCI_SUSP_CTRL_REG); 277 if (susp & TEGRA_EHCI_SUSP_CTRL_PHY_CLK_VALID) 278 break; 279 delay(1); 280 } 281 if (retry == 0) { 282 aprint_error_dev(sc->sc_dev, "PHY clock is not valid\n"); 283 return; 284 } 285 286 /* Disable ICUSB transceiver */ 287 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_ICUSB_CTRL_REG, 288 0, 289 TEGRA_EHCI_ICUSB_CTRL_ENB1); 290 291 /* Power up UTMPI transceiver */ 292 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG0_REG, 293 0, 294 TEGRA_EHCI_UTMIP_XCVR_CFG0_PD_POWERDOWN | 295 TEGRA_EHCI_UTMIP_XCVR_CFG0_PD2_POWERDOWN | 296 TEGRA_EHCI_UTMIP_XCVR_CFG0_PDZI_POWERDOWN); 297 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_XCVR_CFG1_REG, 298 0, 299 TEGRA_EHCI_UTMIP_XCVR_CFG1_PDDISC_POWERDOWN | 300 TEGRA_EHCI_UTMIP_XCVR_CFG1_PDCHRP_POWERDOWN | 301 TEGRA_EHCI_UTMIP_XCVR_CFG1_PDDR_POWERDOWN); 302 303 if (sc->sc_port == 0) { 304 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG0_REG, 305 0, TEGRA_EHCI_UTMIP_BIAS_CFG0_BIASPD); 306 delay(25); 307 tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_BIAS_CFG1_REG, 308 0, TEGRA_EHCI_UTMIP_BIAS_CFG1_PDTRK_POWERDOWN); 309 } 310 } 311