1 /* $OpenBSD: omehci.c,v 1.3 2014/05/19 13:11:31 mpi 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 56 #include <dev/usb/usb.h> 57 #include <dev/usb/usbdi.h> 58 #include <dev/usb/usbdivar.h> 59 #include <dev/usb/usb_mem.h> 60 61 #include <armv7/armv7/armv7var.h> 62 #include <armv7/omap/prcmvar.h> 63 #include <armv7/omap/omgpiovar.h> 64 #include <armv7/omap/omehcivar.h> 65 66 #include <dev/usb/ehcireg.h> 67 #include <dev/usb/ehcivar.h> 68 69 void omehci_attach(struct device *, struct device *, void *); 70 int omehci_detach(struct device *, int); 71 int omehci_activate(struct device *, int); 72 73 struct omehci_softc { 74 struct ehci_softc sc; 75 void *sc_ih; 76 bus_space_handle_t uhh_ioh; 77 bus_space_handle_t tll_ioh; 78 79 uint32_t ehci_rev; 80 uint32_t tll_avail; 81 82 uint32_t port_mode[OMAP_HS_USB_PORTS]; 83 uint32_t phy_reset[OMAP_HS_USB_PORTS]; 84 uint32_t reset_gpio_pin[OMAP_HS_USB_PORTS]; 85 86 void (*early_init)(void); 87 }; 88 89 int omehci_init(struct omehci_softc *); 90 void omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port); 91 void omehci_enable(struct omehci_softc *); 92 void omehci_disable(struct omehci_softc *); 93 void omehci_utmi_init(struct omehci_softc *sc, unsigned int en_mask); 94 void misc_setup(struct omehci_softc *sc); 95 void omehci_phy_reset(uint32_t on, uint32_t _delay); 96 void omehci_uhh_init(struct omehci_softc *sc); 97 void omehci_v4_early_init(void); 98 99 struct cfattach omehci_ca = { 100 sizeof (struct omehci_softc), NULL, omehci_attach, 101 omehci_detach, omehci_activate 102 }; 103 104 void 105 omehci_attach(struct device *parent, struct device *self, void *aux) 106 { 107 struct omehci_softc *sc = (struct omehci_softc *)self; 108 struct armv7_attach_args *aa = aux; 109 usbd_status r; 110 char *devname = sc->sc.sc_bus.bdev.dv_xname; 111 uint32_t i; 112 113 sc->sc.iot = aa->aa_iot; 114 sc->sc.sc_bus.dmatag = aa->aa_dmat; 115 sc->sc.sc_size = aa->aa_dev->mem[0].size; 116 117 /* set defaults */ 118 for (i = 0; i < 3; i++) { 119 sc->phy_reset[i] = 0; 120 sc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN; 121 sc->reset_gpio_pin[i] = -1; 122 } 123 124 switch (board_id) 125 { 126 case BOARD_ID_OMAP4_PANDA: 127 sc->tll_avail = 0; 128 sc->port_mode[0] = EHCI_HCD_OMAP_MODE_PHY; 129 sc->early_init = omehci_v4_early_init; 130 break; 131 default: 132 break; 133 } 134 135 /* Map I/O space */ 136 if (bus_space_map(sc->sc.iot, aa->aa_dev->mem[0].addr, 137 aa->aa_dev->mem[0].size, 0, &sc->sc.ioh)) { 138 printf(": cannot map mem space\n"); 139 goto out; 140 } 141 142 if (bus_space_map(sc->sc.iot, aa->aa_dev->mem[1].addr, 143 aa->aa_dev->mem[1].size, 0, &sc->uhh_ioh)) { 144 printf(": cannot map mem space\n"); 145 goto mem0; 146 } 147 148 if (sc->tll_avail && 149 bus_space_map(sc->sc.iot, aa->aa_dev->mem[2].addr, 150 aa->aa_dev->mem[2].size, 0, &sc->tll_ioh)) { 151 printf(": cannot map mem space\n"); 152 goto mem1; 153 } 154 155 printf("\n"); 156 157 if (sc->early_init) 158 sc->early_init(); 159 160 if (omehci_init(sc)) 161 return; 162 163 /* Disable interrupts, so we don't get any spurious ones. */ 164 sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH); 165 EOWRITE2(&sc->sc, EHCI_USBINTR, 0); 166 167 sc->sc_ih = arm_intr_establish(aa->aa_dev->irq[0], IPL_USB, 168 ehci_intr, &sc->sc, devname); 169 if (sc->sc_ih == NULL) { 170 printf(": unable to establish interrupt\n"); 171 printf("XXX - disable ehci and prcm"); 172 goto mem2; 173 } 174 175 strlcpy(sc->sc.sc_vendor, "TI OMAP", sizeof(sc->sc.sc_vendor)); 176 r = ehci_init(&sc->sc); 177 if (r != USBD_NORMAL_COMPLETION) { 178 printf("%s: init failed, error=%d\n", devname, r); 179 printf("XXX - disable ehci and prcm"); 180 goto intr; 181 } 182 183 config_found(self, &sc->sc.sc_bus, usbctlprint); 184 185 goto out; 186 187 intr: 188 arm_intr_disestablish(sc->sc_ih); 189 sc->sc_ih = NULL; 190 mem2: 191 bus_space_unmap(sc->sc.iot, sc->tll_ioh, aa->aa_dev->mem[2].size); 192 mem1: 193 bus_space_unmap(sc->sc.iot, sc->uhh_ioh, aa->aa_dev->mem[1].size); 194 mem0: 195 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 196 sc->sc.sc_size = 0; 197 out: 198 return; 199 } 200 201 int 202 omehci_init(struct omehci_softc *sc) 203 { 204 uint32_t i = 0, reg; 205 uint32_t reset_performed = 0; 206 uint32_t timeout = 0; 207 uint32_t tll_ch_mask = 0; 208 209 /* enable high speed usb host clock */ 210 prcm_enablemodule(PRCM_USB); 211 212 /* Hold the PHY in reset while configuring */ 213 for (i = 0; i < OMAP_HS_USB_PORTS; i++) { 214 if (sc->phy_reset[i]) { 215 /* Configure the GPIO to drive low (hold in reset) */ 216 if (sc->reset_gpio_pin[i] != -1) { 217 omgpio_set_dir(sc->reset_gpio_pin[i], 218 OMGPIO_DIR_OUT); 219 omgpio_clear_bit(sc->reset_gpio_pin[i]); 220 reset_performed = 1; 221 } 222 } 223 } 224 225 /* Hold the PHY in RESET for enough time till DIR is high */ 226 if (reset_performed) 227 delay(10); 228 229 /* Read the UHH revision */ 230 sc->ehci_rev = bus_space_read_4(sc->sc.iot, sc->uhh_ioh, 231 OMAP_USBHOST_UHH_REVISION); 232 233 /* Initilise the low level interface module(s) */ 234 if (sc->ehci_rev == OMAP_EHCI_REV1) { 235 /* Enable the USB TLL */ 236 prcm_enablemodule(PRCM_USBTLL); 237 238 /* Perform TLL soft reset, and wait until reset is complete */ 239 bus_space_write_4(sc->sc.iot, sc->tll_ioh, 240 OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET); 241 242 /* Set the timeout to 100ms*/ 243 timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); 244 245 /* Wait for TLL reset to complete */ 246 while ((bus_space_read_4(sc->sc.iot, sc->tll_ioh, 247 OMAP_USBTLL_SYSSTATUS) & TLL_SYSSTATUS_RESETDONE) 248 == 0x00) { 249 250 /* Sleep for a tick */ 251 delay(10); 252 253 if (timeout-- == 0) { 254 return 1; 255 } 256 } 257 258 bus_space_write_4(sc->sc.iot, sc->tll_ioh, 259 OMAP_USBTLL_SYSCONFIG, 260 TLL_SYSCONFIG_ENAWAKEUP | TLL_SYSCONFIG_AUTOIDLE | 261 TLL_SYSCONFIG_SIDLE_SMART_IDLE | TLL_SYSCONFIG_CACTIVITY); 262 } else if (sc->ehci_rev == OMAP_EHCI_REV2) { 263 /* For OMAP44xx devices you have to enable the per-port clocks: 264 * PHY_MODE - External ULPI clock 265 * TTL_MODE - Internal UTMI clock 266 * HSIC_MODE - Internal 480Mhz and 60Mhz clocks 267 */ 268 if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) { 269 //ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK); 270 prcm_enablemodule(PRCM_USBP1_PHY); 271 } else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) 272 prcm_enablemodule(PRCM_USBP1_UTMI); 273 else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC) 274 prcm_enablemodule(PRCM_USBP1_HSIC); 275 276 if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) { 277 //ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK); 278 prcm_enablemodule(PRCM_USBP2_PHY); 279 } else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) 280 prcm_enablemodule(PRCM_USBP2_UTMI); 281 else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC) 282 prcm_enablemodule(PRCM_USBP2_HSIC); 283 } 284 285 /* Put UHH in SmartIdle/SmartStandby mode */ 286 reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh, 287 OMAP_USBHOST_UHH_SYSCONFIG); 288 if (sc->ehci_rev == OMAP_EHCI_REV1) { 289 reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK | 290 UHH_SYSCONFIG_MIDLEMODE_MASK); 291 reg |= (UHH_SYSCONFIG_ENAWAKEUP | 292 UHH_SYSCONFIG_AUTOIDLE | 293 UHH_SYSCONFIG_CLOCKACTIVITY | 294 UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE | 295 UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY); 296 } else if (sc->ehci_rev == OMAP_EHCI_REV2) { 297 reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK; 298 reg |= UHH_SYSCONFIG_IDLEMODE_NOIDLE; 299 reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK; 300 reg |= UHH_SYSCONFIG_STANDBYMODE_NOSTDBY; 301 } 302 bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_SYSCONFIG, 303 reg); 304 305 reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh, 306 OMAP_USBHOST_UHH_HOSTCONFIG); 307 308 /* Setup ULPI bypass and burst configurations */ 309 reg |= (UHH_HOSTCONFIG_ENA_INCR4 | 310 UHH_HOSTCONFIG_ENA_INCR8 | 311 UHH_HOSTCONFIG_ENA_INCR16); 312 reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN; 313 314 if (sc->ehci_rev == OMAP_EHCI_REV1) { 315 if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) 316 reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS; 317 if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) 318 reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS; 319 if (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) 320 reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS; 321 322 /* Bypass the TLL module for PHY mode operation */ 323 if ((sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) || 324 (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) || 325 (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) 326 reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS; 327 else 328 reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS; 329 } else if (sc->ehci_rev == OMAP_EHCI_REV2) { 330 reg |= UHH_HOSTCONFIG_APP_START_CLK; 331 332 /* Clear port mode fields for PHY mode*/ 333 reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK; 334 reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK; 335 336 if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) 337 reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY; 338 else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC) 339 reg |= UHH_HOSTCONFIG_P1_MODE_HSIC; 340 341 if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) 342 reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY; 343 else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC) 344 reg |= UHH_HOSTCONFIG_P2_MODE_HSIC; 345 } 346 347 bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_HOSTCONFIG, reg); 348 349 /* If any of the ports are configured in TLL mode, enable them */ 350 for (i = 0; i < OMAP_HS_USB_PORTS; i++) 351 if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY) 352 tll_ch_mask |= 1 << i; 353 354 /* Enable UTMI mode for required TLL channels */ 355 #ifdef notyet 356 if (tll_ch_mask) 357 omap_ehci_utmi_init(sc, tll_ch_mask); 358 #endif 359 360 /* Release the PHY reset signal now we have configured everything */ 361 if (reset_performed) { 362 /* Delay for 10ms */ 363 delay(10000); 364 365 /* Release reset */ 366 for (i = 0; i < 3; i++) { 367 if (sc->phy_reset[i] && (sc->reset_gpio_pin[i] != -1)) 368 omgpio_set_bit(sc->reset_gpio_pin[i]); 369 } 370 } 371 372 /* Set the interrupt threshold control, it controls the maximum rate at 373 * which the host controller issues interrupts. We set it to 1 microframe 374 * at startup - the default is 8 mircoframes (equates to 1ms). 375 */ 376 reg = bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD); 377 reg &= 0xff00ffff; 378 reg |= (1 << 16); 379 bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD, reg); 380 381 /* Soft reset the PHY using PHY reset command over ULPI */ 382 for (i = 0; i < OMAP_HS_USB_PORTS; i++) 383 if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY) 384 omehci_soft_phy_reset(sc, i); 385 386 return(0); 387 } 388 389 void 390 omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port) 391 { 392 unsigned long timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); 393 uint32_t reg; 394 395 reg = ULPI_FUNC_CTRL_RESET 396 /* FUNCTION_CTRL_SET register */ 397 | (ULPI_SET(ULPI_FUNC_CTRL) << OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT) 398 /* Write */ 399 | (2 << OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT) 400 /* PORTn */ 401 | ((port + 1) << OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT) 402 /* start ULPI access*/ 403 | (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT); 404 405 bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI, reg); 406 407 timeout += 1000000; 408 /* Wait for ULPI access completion */ 409 while ((bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI) 410 & (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT))) { 411 412 /* Sleep for a tick */ 413 delay(10); 414 415 if (timeout-- == 0) { 416 printf("PHY reset operation timed out\n"); 417 break; 418 } 419 } 420 } 421 422 int 423 omehci_detach(struct device *self, int flags) 424 { 425 struct omehci_softc *sc = (struct omehci_softc *)self; 426 int rv; 427 428 rv = ehci_detach(self, flags); 429 if (rv) 430 return (rv); 431 432 if (sc->sc_ih != NULL) { 433 arm_intr_disestablish(sc->sc_ih); 434 sc->sc_ih = NULL; 435 } 436 437 if (sc->sc.sc_size) { 438 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 439 sc->sc.sc_size = 0; 440 } 441 442 /* XXX: stop clock */ 443 444 return (0); 445 } 446 447 int 448 omehci_activate(struct device *self, int act) 449 { 450 struct omehci_softc *sc = (struct omehci_softc *)self; 451 452 switch (act) { 453 case DVACT_SUSPEND: 454 sc->sc.sc_bus.use_polling++; 455 /* FIXME */ 456 sc->sc.sc_bus.use_polling--; 457 break; 458 case DVACT_RESUME: 459 sc->sc.sc_bus.use_polling++; 460 /* FIXME */ 461 sc->sc.sc_bus.use_polling--; 462 break; 463 case DVACT_POWERDOWN: 464 ehci_reset(&sc->sc); 465 break; 466 } 467 return 0; 468 } 469 470 void 471 omehci_v4_early_init() 472 { 473 omgpio_set_dir(1, OMGPIO_DIR_OUT); 474 omgpio_clear_bit(1); 475 omgpio_set_dir(62, OMGPIO_DIR_OUT); 476 omgpio_clear_bit(62); 477 478 /* wait for power down */ 479 delay(1000); 480 481 omgpio_set_bit(1); 482 omgpio_set_bit(62); 483 484 /* wait until powered up */ 485 delay(1000); 486 } 487