1 /* $NetBSD: octeon_xhci.c,v 1.9 2022/09/29 07:00:46 skrll Exp $ */ 2 /* $OpenBSD: octxhci.c,v 1.4 2019/09/29 04:32:23 visa Exp $ */ 3 4 /* 5 * Copyright (c) 2017 Visa Hankala 6 * Copyright (c) 2020 Jared McNeill <jmcneill (at) invisible.ca> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 /* 22 * Driver for OCTEON USB3 controller bridge. 23 */ 24 25 #include <sys/param.h> 26 #include <sys/systm.h> 27 #include <sys/device.h> 28 29 #include <mips/cavium/octeonvar.h> 30 31 #include <mips/cavium/dev/octeon_xhcireg.h> 32 33 #include <dev/usb/usb.h> 34 #include <dev/usb/usbdi.h> 35 #include <dev/usb/usbdivar.h> 36 #include <dev/usb/usb_mem.h> 37 #include <dev/usb/xhcireg.h> 38 #include <dev/usb/xhcivar.h> 39 40 #include <dev/fdt/fdtvar.h> 41 42 #define XCTL_RD_8(sc, reg) \ 43 bus_space_read_8((sc)->sc_iot, (sc)->sc_ioh, (reg)) 44 #define XCTL_WR_8(sc, reg, val) \ 45 bus_space_write_8((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 46 47 struct octxhci_softc { 48 struct xhci_softc sc_xhci; 49 bus_space_tag_t sc_iot; 50 bus_space_handle_t sc_ioh; 51 struct fdtbus_gpio_pin *sc_power_gpio; 52 int sc_unit; 53 }; 54 55 static int octxhci_match(device_t, cfdata_t, void *); 56 static void octxhci_attach(device_t, device_t, void *); 57 58 static int octxhci_dwc3_init(struct xhci_softc *); 59 static void octxhci_uctl_init(struct octxhci_softc *, uint64_t, uint64_t); 60 61 static void octxhci_bus_io_init(bus_space_tag_t, void *); 62 63 static struct mips_bus_space octxhci_bus_tag; 64 65 CFATTACH_DECL_NEW(octxhci, sizeof(struct octxhci_softc), 66 octxhci_match, octxhci_attach, NULL, NULL); 67 68 static const struct device_compatible_entry compat_data[] = { 69 { .compat = "cavium,octeon-7130-usb-uctl" }, 70 DEVICE_COMPAT_EOL 71 }; 72 73 int 74 octxhci_match(device_t parent, cfdata_t cf, void *aux) 75 { 76 struct fdt_attach_args * const faa = aux; 77 78 return of_compatible_match(faa->faa_phandle, compat_data); 79 } 80 81 void 82 octxhci_attach(device_t parent, device_t self, void *aux) 83 { 84 struct octxhci_softc *osc = device_private(self); 85 struct xhci_softc *sc = &osc->sc_xhci; 86 struct fdt_attach_args * const faa = aux; 87 const int phandle = faa->faa_phandle; 88 const char *clock_type_hs; 89 const char *clock_type_ss; 90 u_int clock_freq, clock_sel; 91 char intrstr[128]; 92 int child, error; 93 bus_addr_t addr; 94 bus_size_t size; 95 void *ih; 96 97 osc->sc_iot = faa->faa_bst; 98 99 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 100 aprint_error(": couldn't get bridge registers\n"); 101 return; 102 } 103 if (bus_space_map(osc->sc_iot, addr, size, 0, &osc->sc_ioh) != 0) { 104 aprint_error(": couldn't map bridge registers\n"); 105 return; 106 } 107 osc->sc_power_gpio = fdtbus_gpio_acquire(phandle, "power", 108 GPIO_PIN_OUTPUT); 109 osc->sc_unit = (addr >> 24) & 0x1; 110 111 octxhci_bus_io_init(&octxhci_bus_tag, NULL); 112 113 sc->sc_dev = self; 114 sc->sc_bus.ub_hcpriv = sc; 115 sc->sc_bus.ub_dmatag = faa->faa_dmat; 116 sc->sc_iot = &octxhci_bus_tag; 117 sc->sc_ios = size; 118 119 child = of_find_bycompat(phandle, "synopsys,dwc3"); 120 if (child == -1) { 121 aprint_error(": couldn't find dwc3 child node\n"); 122 return; 123 } 124 if (fdtbus_get_reg(child, 0, &addr, &size) != 0) { 125 aprint_error(": couldn't get xhci registers\n"); 126 return; 127 } 128 if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) { 129 aprint_error(": couldn't map xhci registers\n"); 130 return; 131 } 132 133 if (of_getprop_uint32(phandle, "refclk-frequency", &clock_freq) != 0) { 134 aprint_error(": couldn't get refclk-frequency property\n"); 135 return; 136 } 137 clock_type_hs = fdtbus_get_string(phandle, "refclk-type-hs"); 138 if (clock_type_hs == NULL) { 139 aprint_error(": couldn't get refclk-type-hs property\n"); 140 return; 141 } 142 clock_type_ss = fdtbus_get_string(phandle, "refclk-type-ss"); 143 if (clock_type_ss == NULL) { 144 aprint_error(": couldn't get refclk-type-ss property\n"); 145 return; 146 } 147 148 clock_sel = 0; 149 if (strcmp(clock_type_ss, "dlmc_ref_clk1") == 0) 150 clock_sel |= 1; 151 if (strcmp(clock_type_hs, "pll_ref_clk") == 0) 152 clock_sel |= 2; 153 154 octxhci_uctl_init(osc, clock_freq, clock_sel); 155 156 if (octxhci_dwc3_init(sc) != 0) { 157 /* Error message has been printed already. */ 158 return; 159 } 160 161 if (!fdtbus_intr_str(child, 0, intrstr, sizeof(intrstr))) { 162 aprint_error_dev(self, "failed to decode interrupt\n"); 163 return; 164 } 165 166 ih = fdtbus_intr_establish(child, 0, IPL_USB, FDT_INTR_MPSAFE, 167 xhci_intr, sc); 168 if (ih == NULL) { 169 aprint_error_dev(self, "couldn't establish interrupt on %s\n", 170 intrstr); 171 return; 172 } 173 aprint_normal_dev(self, "interrupting on %s\n", intrstr); 174 175 sc->sc_bus.ub_revision = USBREV_3_0; 176 error = xhci_init(sc); 177 if (error != 0) { 178 aprint_error_dev(self, "init failed, error = %d\n", error); 179 return; 180 } 181 182 sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint, CFARGS_NONE); 183 sc->sc_child2 = config_found(self, &sc->sc_bus2, usbctlprint, 184 CFARGS_NONE); 185 } 186 187 void 188 octxhci_uctl_init(struct octxhci_softc *sc, uint64_t clock_freq, 189 uint64_t clock_sel) 190 { 191 static const uint32_t clock_divs[] = { 1, 2, 4, 6, 8, 16, 24, 32 }; 192 uint64_t i, val; 193 uint64_t ioclock = octeon_ioclock_speed(); 194 uint64_t mpll_mult; 195 uint64_t refclk_fsel; 196 #if notyet 197 int output_sel; 198 #endif 199 200 /* 201 * Put the bridge controller, USB core, PHY, and clock divider 202 * into reset. 203 */ 204 val = XCTL_RD_8(sc, XCTL_CTL); 205 val |= XCTL_CTL_UCTL_RST; 206 val |= XCTL_CTL_UAHC_RST; 207 val |= XCTL_CTL_UPHY_RST; 208 XCTL_WR_8(sc, XCTL_CTL, val); 209 val = XCTL_RD_8(sc, XCTL_CTL); 210 val |= XCTL_CTL_CLKDIV_RST; 211 XCTL_WR_8(sc, XCTL_CTL, val); 212 213 /* Select IO clock divisor. */ 214 for (i = 0; i < __arraycount(clock_divs); i++) { 215 if (ioclock / clock_divs[i] < 300000000) 216 break; 217 } 218 219 /* Update the divisor and enable the clock. */ 220 val = XCTL_RD_8(sc, XCTL_CTL); 221 val &= ~XCTL_CTL_CLKDIV_SEL; 222 val |= (i << XCTL_CTL_CLKDIV_SEL_SHIFT) & XCTL_CTL_CLKDIV_SEL; 223 val |= XCTL_CTL_CLK_EN; 224 XCTL_WR_8(sc, XCTL_CTL, val); 225 226 /* Take the clock divider out of reset. */ 227 val = XCTL_RD_8(sc, XCTL_CTL); 228 val &= ~XCTL_CTL_CLKDIV_RST; 229 XCTL_WR_8(sc, XCTL_CTL, val); 230 231 /* Select the reference clock. */ 232 switch (clock_freq) { 233 case 50000000: 234 refclk_fsel = 0x07; 235 mpll_mult = 0x32; 236 break; 237 case 125000000: 238 refclk_fsel = 0x07; 239 mpll_mult = 0x28; 240 break; 241 case 100000000: 242 default: 243 if (clock_sel < 2) 244 refclk_fsel = 0x27; 245 else 246 refclk_fsel = 0x07; 247 mpll_mult = 0x19; 248 break; 249 } 250 251 /* Set the clock and power up PHYs. */ 252 val = XCTL_RD_8(sc, XCTL_CTL); 253 val &= ~XCTL_CTL_REFCLK_SEL; 254 val |= clock_sel << XCTL_CTL_REFCLK_SEL_SHIFT; 255 val &= ~XCTL_CTL_REFCLK_DIV2; 256 val &= ~XCTL_CTL_REFCLK_FSEL; 257 val |= refclk_fsel << XCTL_CTL_REFCLK_FSEL_SHIFT; 258 val &= ~XCTL_CTL_MPLL_MULT; 259 val |= mpll_mult << XCTL_CTL_MPLL_MULT_SHIFT; 260 val |= XCTL_CTL_SSC_EN; 261 val |= XCTL_CTL_REFCLK_SSP_EN; 262 val |= XCTL_CTL_SSPOWER_EN; 263 val |= XCTL_CTL_HSPOWER_EN; 264 XCTL_WR_8(sc, XCTL_CTL, val); 265 266 delay(100); 267 268 /* Take the bridge out of reset. */ 269 val = XCTL_RD_8(sc, XCTL_CTL); 270 val &= ~XCTL_CTL_UCTL_RST; 271 XCTL_WR_8(sc, XCTL_CTL, val); 272 273 delay(100); 274 275 #if notyet 276 if (sc->sc_power_gpio[0] != 0) { 277 if (sc->sc_unit == 0) 278 output_sel = GPIO_CONFIG_MD_USB0_VBUS_CTRL; 279 else 280 output_sel = GPIO_CONFIG_MD_USB1_VBUS_CTRL; 281 gpio_controller_config_pin(sc->sc_power_gpio, 282 GPIO_CONFIG_OUTPUT | output_sel); 283 284 /* Enable port power control. */ 285 val = XCTL_RD_8(sc, XCTL_HOST_CFG); 286 val |= XCTL_HOST_CFG_PPC_EN; 287 if (sc->sc_power_gpio[2] & GPIO_ACTIVE_LOW) 288 val &= ~XCTL_HOST_CFG_PPC_ACTIVE_HIGH_EN; 289 else 290 val |= XCTL_HOST_CFG_PPC_ACTIVE_HIGH_EN; 291 XCTL_WR_8(sc, XCTL_HOST_CFG, val); 292 } else { 293 /* Disable port power control. */ 294 val = XCTL_RD_8(sc, XCTL_HOST_CFG); 295 val &= ~XCTL_HOST_CFG_PPC_EN; 296 XCTL_WR_8(sc, XCTL_HOST_CFG, val); 297 } 298 #else 299 /* Disable port power control. */ 300 val = XCTL_RD_8(sc, XCTL_HOST_CFG); 301 val &= ~XCTL_HOST_CFG_PPC_EN; 302 XCTL_WR_8(sc, XCTL_HOST_CFG, val); 303 #endif 304 305 /* Enable host-only mode. */ 306 val = XCTL_RD_8(sc, XCTL_CTL); 307 val &= ~XCTL_CTL_DRD_MODE; 308 XCTL_WR_8(sc, XCTL_CTL, val); 309 310 delay(100); 311 312 /* Take the USB core out of reset. */ 313 val = XCTL_RD_8(sc, XCTL_CTL); 314 val &= ~XCTL_CTL_UAHC_RST; 315 XCTL_WR_8(sc, XCTL_CTL, val); 316 317 delay(100); 318 319 val = XCTL_RD_8(sc, XCTL_CTL); 320 val |= XCTL_CTL_CSCLK_EN; 321 XCTL_WR_8(sc, XCTL_CTL, val); 322 323 /* Take the PHY out of reset. */ 324 val = XCTL_RD_8(sc, XCTL_CTL); 325 val &= ~XCTL_CTL_UPHY_RST; 326 XCTL_WR_8(sc, XCTL_CTL, val); 327 (void)XCTL_RD_8(sc, XCTL_CTL); 328 329 /* Fix endianness. */ 330 val = XCTL_RD_8(sc, XCTL_SHIM_CFG); 331 val &= ~XCTL_SHIM_CFG_CSR_BYTE_SWAP; 332 val &= ~XCTL_SHIM_CFG_DMA_BYTE_SWAP; 333 val |= __SHIFTIN(XCTL_SHIM_ENDIAN_BIG, XCTL_SHIM_CFG_DMA_BYTE_SWAP); 334 val |= __SHIFTIN(XCTL_SHIM_ENDIAN_BIG, XCTL_SHIM_CFG_CSR_BYTE_SWAP); 335 XCTL_WR_8(sc, XCTL_SHIM_CFG, val); 336 (void)XCTL_RD_8(sc, XCTL_SHIM_CFG); 337 } 338 339 int 340 octxhci_dwc3_init(struct xhci_softc *sc) 341 { 342 bus_space_handle_t ioh = sc->sc_ioh; 343 uint32_t rev; 344 uint32_t val; 345 346 val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GSNPSID); 347 if ((val & 0xffff0000u) != 0x55330000u) { 348 aprint_error(": no DWC3 core (DWC3_GSNPSID=%08x)\n", val); 349 return EIO; 350 } 351 rev = val & 0xffffu; 352 aprint_normal(": DWC3 rev 0x%04x\n", rev); 353 354 val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GUSB3PIPECTL(0)); 355 val &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX; 356 val |= DWC3_GUSB3PIPECTL_SUSPHY; 357 bus_space_write_4(sc->sc_iot, ioh, DWC3_GUSB3PIPECTL(0), val); 358 359 val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GUSB2PHYCFG(0)); 360 val |= DWC3_GUSB2PHYCFG_SUSPHY; 361 bus_space_write_4(sc->sc_iot, ioh, DWC3_GUSB2PHYCFG(0), val); 362 363 /* Set the controller into host mode. */ 364 val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GCTL); 365 val &= ~DWC3_GCTL_PRTCAP_MASK; 366 val |= DWC3_GCTL_PRTCAP_HOST; 367 bus_space_write_4(sc->sc_iot, ioh, DWC3_GCTL, val); 368 369 val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GCTL); 370 val &= ~DWC3_GCTL_SCALEDOWN_MASK; 371 val &= ~DWC3_GCTL_DISSCRAMBLE; 372 if (rev >= DWC3_REV_210A && rev <= DWC3_REV_250A) 373 val |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC; 374 else 375 val &= ~DWC3_GCTL_DSBLCLKGTNG; 376 bus_space_write_4(sc->sc_iot, ioh, DWC3_GCTL, val); 377 378 return 0; 379 } 380 381 /* ---- bus_space(9) */ 382 #define CHIP octxhci 383 #define CHIP_IO 384 #define CHIP_LITTLE_ENDIAN 385 386 #define CHIP_W1_BUS_START(v) 0x0000000000000000ULL 387 #define CHIP_W1_BUS_END(v) 0x7fffffffffffffffULL 388 #define CHIP_W1_SYS_START(v) 0x8000000000000000ULL 389 #define CHIP_W1_SYS_END(v) 0xffffffffffffffffULL 390 391 #include <mips/mips/bus_space_alignstride_chipdep.c> 392