1 /* $OpenBSD: omehci.c,v 1.4 2016/08/11 01:53:18 jsg Exp $ */ 2 3 /* 4 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /*- 20 * Copyright (c) 2011 21 * Ben Gray <ben.r.gray@gmail.com>. 22 * All rights reserved. 23 * 24 * Redistribution and use in source and binary forms, with or without 25 * modification, are permitted provided that the following conditions 26 * are met: 27 * 1. Redistributions of source code must retain the above copyright 28 * notice, this list of conditions and the following disclaimer. 29 * 2. Redistributions in binary form must reproduce the above copyright 30 * notice, this list of conditions and the following disclaimer in the 31 * documentation and/or other materials provided with the distribution. 32 * 33 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 */ 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/device.h> 49 #include <sys/kernel.h> 50 #include <sys/rwlock.h> 51 #include <sys/timeout.h> 52 53 #include <machine/intr.h> 54 #include <machine/bus.h> 55 #include <machine/fdt.h> 56 57 #include <dev/usb/usb.h> 58 #include <dev/usb/usbdi.h> 59 #include <dev/usb/usbdivar.h> 60 #include <dev/usb/usb_mem.h> 61 62 #include <armv7/armv7/armv7var.h> 63 #include <armv7/omap/prcmvar.h> 64 #include <armv7/omap/omgpiovar.h> 65 #include <armv7/omap/omehcivar.h> 66 67 #include <dev/ofw/openfirm.h> 68 #include <dev/ofw/fdt.h> 69 70 #include <dev/usb/ehcireg.h> 71 #include <dev/usb/ehcivar.h> 72 73 int omehci_match(struct device *, void *, void *); 74 void omehci_attach(struct device *, struct device *, void *); 75 int omehci_detach(struct device *, int); 76 int omehci_activate(struct device *, int); 77 78 struct omehci_softc { 79 struct ehci_softc sc; 80 void *sc_ih; 81 bus_space_handle_t uhh_ioh; 82 bus_space_handle_t tll_ioh; 83 84 uint32_t ehci_rev; 85 uint32_t tll_avail; 86 87 uint32_t port_mode[OMAP_HS_USB_PORTS]; 88 uint32_t phy_reset[OMAP_HS_USB_PORTS]; 89 uint32_t reset_gpio_pin[OMAP_HS_USB_PORTS]; 90 91 void (*early_init)(void); 92 }; 93 94 int omehci_init(struct omehci_softc *); 95 void omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port); 96 void omehci_enable(struct omehci_softc *); 97 void omehci_disable(struct omehci_softc *); 98 void omehci_utmi_init(struct omehci_softc *sc, unsigned int en_mask); 99 void misc_setup(struct omehci_softc *sc); 100 void omehci_phy_reset(uint32_t on, uint32_t _delay); 101 void omehci_uhh_init(struct omehci_softc *sc); 102 void omehci_v4_early_init(void); 103 104 struct cfattach omehci_ca = { 105 sizeof (struct omehci_softc), omehci_match, omehci_attach, 106 omehci_detach, omehci_activate 107 }; 108 109 struct cfdriver omehci_cd = { 110 NULL, "omehci", DV_DULL 111 }; 112 113 int 114 omehci_match(struct device *parent, void *match, void *aux) 115 { 116 struct fdt_attach_args *faa = aux; 117 118 return OF_is_compatible(faa->fa_node, "ti,usbhs-host"); 119 } 120 121 void 122 omehci_attach(struct device *parent, struct device *self, void *aux) 123 { 124 struct omehci_softc *sc = (struct omehci_softc *)self; 125 struct fdt_attach_args *faa = aux; 126 usbd_status r; 127 char *devname = sc->sc.sc_bus.bdev.dv_xname; 128 uint32_t i; 129 char port_mode[16]; 130 char name[32]; 131 int node; 132 uint32_t reg[2]; 133 134 if (faa->fa_nreg < 1) 135 return; 136 137 sc->sc.iot = faa->fa_iot; 138 sc->sc.sc_bus.dmatag = faa->fa_dmat; 139 140 /* set defaults */ 141 for (i = 0; i < OMAP_HS_USB_PORTS; i++) { 142 sc->phy_reset[i] = 0; 143 sc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN; 144 sc->reset_gpio_pin[i] = -1; 145 } 146 147 switch (board_id) 148 { 149 case BOARD_ID_OMAP4_PANDA: 150 sc->tll_avail = 0; 151 sc->early_init = omehci_v4_early_init; 152 break; 153 default: 154 break; 155 } 156 157 strlcpy(name, "portX-mode", sizeof(name)); 158 159 for (i = 0; i < OMAP_HS_USB_PORTS; i++) { 160 name[4] = '1' + i; 161 memset(port_mode, 0, sizeof(port_mode)); 162 163 if (OF_getprop(faa->fa_node, name, port_mode, 164 sizeof(port_mode)) == -1) 165 continue; 166 167 if (strcmp(port_mode, "ehci-phy") == 0) 168 sc->port_mode[i] = EHCI_HCD_OMAP_MODE_PHY; 169 if (strcmp(port_mode, "ehci-hsic") == 0) 170 sc->port_mode[i] = EHCI_HCD_OMAP_MODE_HSIC; 171 if (strcmp(port_mode, "ehci-tll") == 0) 172 sc->port_mode[i] = EHCI_HCD_OMAP_MODE_TLL ; 173 } 174 175 for (node = OF_child(faa->fa_node); node; node = OF_peer(node)) { 176 if (OF_is_compatible(node, "ti,ehci-omap")) 177 break; 178 } 179 180 if (node == 0) 181 panic("could not find ehci child node"); 182 183 if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) != sizeof(reg)) 184 return; 185 186 /* Map I/O space */ 187 if (bus_space_map(sc->sc.iot, reg[0], reg[1], 0, &sc->sc.ioh)) { 188 printf(": cannot map mem space\n"); 189 goto out; 190 } 191 sc->sc.sc_size = reg[1]; 192 193 if (bus_space_map(sc->sc.iot, faa->fa_reg[0].addr, faa->fa_reg[0].size, 194 0, &sc->uhh_ioh)) { 195 printf(": cannot map mem space\n"); 196 goto mem0; 197 } 198 199 #if 0 200 if (sc->tll_avail && 201 bus_space_map(sc->sc.iot, aa->aa_dev->mem[2].addr, 202 aa->aa_dev->mem[2].size, 0, &sc->tll_ioh)) { 203 printf(": cannot map mem space\n"); 204 goto mem1; 205 } 206 #endif 207 208 printf("\n"); 209 210 if (sc->early_init) 211 sc->early_init(); 212 213 if (omehci_init(sc)) 214 return; 215 216 /* Disable interrupts, so we don't get any spurious ones. */ 217 sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH); 218 EOWRITE2(&sc->sc, EHCI_USBINTR, 0); 219 220 sc->sc_ih = arm_intr_establish_fdt(node, IPL_USB, 221 ehci_intr, &sc->sc, devname); 222 if (sc->sc_ih == NULL) { 223 printf(": unable to establish interrupt\n"); 224 printf("XXX - disable ehci and prcm"); 225 goto mem2; 226 } 227 228 strlcpy(sc->sc.sc_vendor, "TI OMAP", sizeof(sc->sc.sc_vendor)); 229 r = ehci_init(&sc->sc); 230 if (r != USBD_NORMAL_COMPLETION) { 231 printf("%s: init failed, error=%d\n", devname, r); 232 printf("XXX - disable ehci and prcm"); 233 goto intr; 234 } 235 236 config_found(self, &sc->sc.sc_bus, usbctlprint); 237 238 goto out; 239 240 intr: 241 arm_intr_disestablish(sc->sc_ih); 242 sc->sc_ih = NULL; 243 mem2: 244 #if 0 245 bus_space_unmap(sc->sc.iot, sc->tll_ioh, aa->aa_dev->mem[2].size); 246 mem1: 247 #endif 248 bus_space_unmap(sc->sc.iot, sc->uhh_ioh, faa->fa_reg[0].size); 249 mem0: 250 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 251 sc->sc.sc_size = 0; 252 out: 253 return; 254 } 255 256 int 257 omehci_init(struct omehci_softc *sc) 258 { 259 uint32_t i = 0, reg; 260 uint32_t reset_performed = 0; 261 uint32_t timeout = 0; 262 uint32_t tll_ch_mask = 0; 263 264 /* enable high speed usb host clock */ 265 prcm_enablemodule(PRCM_USB); 266 267 /* Hold the PHY in reset while configuring */ 268 for (i = 0; i < OMAP_HS_USB_PORTS; i++) { 269 if (sc->phy_reset[i]) { 270 /* Configure the GPIO to drive low (hold in reset) */ 271 if (sc->reset_gpio_pin[i] != -1) { 272 omgpio_set_dir(sc->reset_gpio_pin[i], 273 OMGPIO_DIR_OUT); 274 omgpio_clear_bit(sc->reset_gpio_pin[i]); 275 reset_performed = 1; 276 } 277 } 278 } 279 280 /* Hold the PHY in RESET for enough time till DIR is high */ 281 if (reset_performed) 282 delay(10); 283 284 /* Read the UHH revision */ 285 sc->ehci_rev = bus_space_read_4(sc->sc.iot, sc->uhh_ioh, 286 OMAP_USBHOST_UHH_REVISION); 287 288 /* Initilise the low level interface module(s) */ 289 if (sc->ehci_rev == OMAP_EHCI_REV1) { 290 /* Enable the USB TLL */ 291 prcm_enablemodule(PRCM_USBTLL); 292 293 /* Perform TLL soft reset, and wait until reset is complete */ 294 bus_space_write_4(sc->sc.iot, sc->tll_ioh, 295 OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET); 296 297 /* Set the timeout to 100ms*/ 298 timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); 299 300 /* Wait for TLL reset to complete */ 301 while ((bus_space_read_4(sc->sc.iot, sc->tll_ioh, 302 OMAP_USBTLL_SYSSTATUS) & TLL_SYSSTATUS_RESETDONE) 303 == 0x00) { 304 305 /* Sleep for a tick */ 306 delay(10); 307 308 if (timeout-- == 0) { 309 return 1; 310 } 311 } 312 313 bus_space_write_4(sc->sc.iot, sc->tll_ioh, 314 OMAP_USBTLL_SYSCONFIG, 315 TLL_SYSCONFIG_ENAWAKEUP | TLL_SYSCONFIG_AUTOIDLE | 316 TLL_SYSCONFIG_SIDLE_SMART_IDLE | TLL_SYSCONFIG_CACTIVITY); 317 } else if (sc->ehci_rev == OMAP_EHCI_REV2) { 318 /* For OMAP44xx devices you have to enable the per-port clocks: 319 * PHY_MODE - External ULPI clock 320 * TTL_MODE - Internal UTMI clock 321 * HSIC_MODE - Internal 480Mhz and 60Mhz clocks 322 */ 323 if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) { 324 //ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK); 325 prcm_enablemodule(PRCM_USBP1_PHY); 326 } else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) 327 prcm_enablemodule(PRCM_USBP1_UTMI); 328 else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC) 329 prcm_enablemodule(PRCM_USBP1_HSIC); 330 331 if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) { 332 //ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK); 333 prcm_enablemodule(PRCM_USBP2_PHY); 334 } else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) 335 prcm_enablemodule(PRCM_USBP2_UTMI); 336 else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC) 337 prcm_enablemodule(PRCM_USBP2_HSIC); 338 } 339 340 /* Put UHH in SmartIdle/SmartStandby mode */ 341 reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh, 342 OMAP_USBHOST_UHH_SYSCONFIG); 343 if (sc->ehci_rev == OMAP_EHCI_REV1) { 344 reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK | 345 UHH_SYSCONFIG_MIDLEMODE_MASK); 346 reg |= (UHH_SYSCONFIG_ENAWAKEUP | 347 UHH_SYSCONFIG_AUTOIDLE | 348 UHH_SYSCONFIG_CLOCKACTIVITY | 349 UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE | 350 UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY); 351 } else if (sc->ehci_rev == OMAP_EHCI_REV2) { 352 reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK; 353 reg |= UHH_SYSCONFIG_IDLEMODE_NOIDLE; 354 reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK; 355 reg |= UHH_SYSCONFIG_STANDBYMODE_NOSTDBY; 356 } 357 bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_SYSCONFIG, 358 reg); 359 360 reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh, 361 OMAP_USBHOST_UHH_HOSTCONFIG); 362 363 /* Setup ULPI bypass and burst configurations */ 364 reg |= (UHH_HOSTCONFIG_ENA_INCR4 | 365 UHH_HOSTCONFIG_ENA_INCR8 | 366 UHH_HOSTCONFIG_ENA_INCR16); 367 reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN; 368 369 if (sc->ehci_rev == OMAP_EHCI_REV1) { 370 if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) 371 reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS; 372 if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) 373 reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS; 374 if (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) 375 reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS; 376 377 /* Bypass the TLL module for PHY mode operation */ 378 if ((sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) || 379 (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) || 380 (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) 381 reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS; 382 else 383 reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS; 384 } else if (sc->ehci_rev == OMAP_EHCI_REV2) { 385 reg |= UHH_HOSTCONFIG_APP_START_CLK; 386 387 /* Clear port mode fields for PHY mode*/ 388 reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK; 389 reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK; 390 391 if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) 392 reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY; 393 else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC) 394 reg |= UHH_HOSTCONFIG_P1_MODE_HSIC; 395 396 if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) 397 reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY; 398 else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC) 399 reg |= UHH_HOSTCONFIG_P2_MODE_HSIC; 400 } 401 402 bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_HOSTCONFIG, reg); 403 404 /* If any of the ports are configured in TLL mode, enable them */ 405 for (i = 0; i < OMAP_HS_USB_PORTS; i++) 406 if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY) 407 tll_ch_mask |= 1 << i; 408 409 /* Enable UTMI mode for required TLL channels */ 410 #ifdef notyet 411 if (tll_ch_mask) 412 omap_ehci_utmi_init(sc, tll_ch_mask); 413 #endif 414 415 /* Release the PHY reset signal now we have configured everything */ 416 if (reset_performed) { 417 /* Delay for 10ms */ 418 delay(10000); 419 420 /* Release reset */ 421 for (i = 0; i < 3; i++) { 422 if (sc->phy_reset[i] && (sc->reset_gpio_pin[i] != -1)) 423 omgpio_set_bit(sc->reset_gpio_pin[i]); 424 } 425 } 426 427 /* Set the interrupt threshold control, it controls the maximum rate at 428 * which the host controller issues interrupts. We set it to 1 microframe 429 * at startup - the default is 8 mircoframes (equates to 1ms). 430 */ 431 reg = bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD); 432 reg &= 0xff00ffff; 433 reg |= (1 << 16); 434 bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD, reg); 435 436 /* Soft reset the PHY using PHY reset command over ULPI */ 437 for (i = 0; i < OMAP_HS_USB_PORTS; i++) 438 if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY) 439 omehci_soft_phy_reset(sc, i); 440 441 return(0); 442 } 443 444 void 445 omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port) 446 { 447 unsigned long timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); 448 uint32_t reg; 449 450 reg = ULPI_FUNC_CTRL_RESET 451 /* FUNCTION_CTRL_SET register */ 452 | (ULPI_SET(ULPI_FUNC_CTRL) << OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT) 453 /* Write */ 454 | (2 << OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT) 455 /* PORTn */ 456 | ((port + 1) << OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT) 457 /* start ULPI access*/ 458 | (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT); 459 460 bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI, reg); 461 462 timeout += 1000000; 463 /* Wait for ULPI access completion */ 464 while ((bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI) 465 & (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT))) { 466 467 /* Sleep for a tick */ 468 delay(10); 469 470 if (timeout-- == 0) { 471 printf("PHY reset operation timed out\n"); 472 break; 473 } 474 } 475 } 476 477 int 478 omehci_detach(struct device *self, int flags) 479 { 480 struct omehci_softc *sc = (struct omehci_softc *)self; 481 int rv; 482 483 rv = ehci_detach(self, flags); 484 if (rv) 485 return (rv); 486 487 if (sc->sc_ih != NULL) { 488 arm_intr_disestablish(sc->sc_ih); 489 sc->sc_ih = NULL; 490 } 491 492 if (sc->sc.sc_size) { 493 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 494 sc->sc.sc_size = 0; 495 } 496 497 /* XXX: stop clock */ 498 499 return (0); 500 } 501 502 int 503 omehci_activate(struct device *self, int act) 504 { 505 struct omehci_softc *sc = (struct omehci_softc *)self; 506 507 switch (act) { 508 case DVACT_SUSPEND: 509 sc->sc.sc_bus.use_polling++; 510 /* FIXME */ 511 sc->sc.sc_bus.use_polling--; 512 break; 513 case DVACT_RESUME: 514 sc->sc.sc_bus.use_polling++; 515 /* FIXME */ 516 sc->sc.sc_bus.use_polling--; 517 break; 518 case DVACT_POWERDOWN: 519 ehci_reset(&sc->sc); 520 break; 521 } 522 return 0; 523 } 524 525 void 526 omehci_v4_early_init() 527 { 528 omgpio_set_dir(1, OMGPIO_DIR_OUT); 529 omgpio_clear_bit(1); 530 omgpio_set_dir(62, OMGPIO_DIR_OUT); 531 omgpio_clear_bit(62); 532 533 /* wait for power down */ 534 delay(1000); 535 536 omgpio_set_bit(1); 537 omgpio_set_bit(62); 538 539 /* wait until powered up */ 540 delay(1000); 541 } 542