1258057Sbr/*- 2258057Sbr * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com> 3258057Sbr * All rights reserved. 4258057Sbr * 5258057Sbr * Redistribution and use in source and binary forms, with or without 6258057Sbr * modification, are permitted provided that the following conditions 7258057Sbr * are met: 8258057Sbr * 1. Redistributions of source code must retain the above copyright 9258057Sbr * notice, this list of conditions and the following disclaimer. 10258057Sbr * 2. Redistributions in binary form must reproduce the above copyright 11258057Sbr * notice, this list of conditions and the following disclaimer in the 12258057Sbr * documentation and/or other materials provided with the distribution. 13258057Sbr * 14258057Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15258057Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16258057Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17258057Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18258057Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19258057Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20258057Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21258057Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22258057Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23258057Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24258057Sbr * SUCH DAMAGE. 25258057Sbr */ 26258057Sbr 27258057Sbr/* 28258057Sbr * Vybrid Family Universal Serial Bus (USB) Controller 29258057Sbr * Chapter 44-45, Vybrid Reference Manual, Rev. 5, 07/2013 30258057Sbr */ 31258057Sbr 32258057Sbr#include <sys/cdefs.h> 33258057Sbr__FBSDID("$FreeBSD$"); 34258057Sbr 35258057Sbr#include "opt_bus.h" 36258057Sbr 37258057Sbr#include <sys/param.h> 38258057Sbr#include <sys/systm.h> 39258057Sbr#include <sys/kernel.h> 40258057Sbr#include <sys/module.h> 41258057Sbr#include <sys/bus.h> 42258057Sbr#include <sys/condvar.h> 43258057Sbr#include <sys/rman.h> 44258057Sbr#include <sys/gpio.h> 45258057Sbr 46258057Sbr#include <dev/ofw/ofw_bus.h> 47258057Sbr#include <dev/ofw/ofw_bus_subr.h> 48258057Sbr 49258057Sbr#include <dev/usb/usb.h> 50258057Sbr#include <dev/usb/usbdi.h> 51258057Sbr#include <dev/usb/usb_busdma.h> 52258057Sbr#include <dev/usb/usb_process.h> 53258057Sbr#include <dev/usb/usb_controller.h> 54258057Sbr#include <dev/usb/usb_bus.h> 55258057Sbr#include <dev/usb/controller/ehci.h> 56258057Sbr#include <dev/usb/controller/ehcireg.h> 57258057Sbr 58258057Sbr#include <dev/fdt/fdt_common.h> 59258057Sbr 60258057Sbr#include <machine/bus.h> 61258057Sbr#include <machine/resource.h> 62258057Sbr 63258057Sbr#include "gpio_if.h" 64258057Sbr#include "opt_platform.h" 65258057Sbr 66258057Sbr#define ENUTMILEVEL3 (1 << 15) 67258057Sbr#define ENUTMILEVEL2 (1 << 14) 68258057Sbr 69258057Sbr#define GPIO_USB_PWR 134 70258057Sbr 71258057Sbr#define USB_ID 0x000 /* Identification register */ 72258057Sbr#define USB_HWGENERAL 0x004 /* Hardware General */ 73258057Sbr#define USB_HWHOST 0x008 /* Host Hardware Parameters */ 74258057Sbr#define USB_HWDEVICE 0x00C /* Device Hardware Parameters */ 75258057Sbr#define USB_HWTXBUF 0x010 /* TX Buffer Hardware Parameters */ 76258057Sbr#define USB_HWRXBUF 0x014 /* RX Buffer Hardware Parameters */ 77258057Sbr#define USB_HCSPARAMS 0x104 /* Host Controller Structural Parameters */ 78258057Sbr 79258057Sbr#define USBPHY_PWD 0x00 /* PHY Power-Down Register */ 80258057Sbr#define USBPHY_PWD_SET 0x04 /* PHY Power-Down Register */ 81258057Sbr#define USBPHY_PWD_CLR 0x08 /* PHY Power-Down Register */ 82258057Sbr#define USBPHY_PWD_TOG 0x0C /* PHY Power-Down Register */ 83258057Sbr#define USBPHY_TX 0x10 /* PHY Transmitter Control Register */ 84258057Sbr#define USBPHY_RX 0x20 /* PHY Receiver Control Register */ 85258057Sbr#define USBPHY_RX_SET 0x24 /* PHY Receiver Control Register */ 86258057Sbr#define USBPHY_RX_CLR 0x28 /* PHY Receiver Control Register */ 87258057Sbr#define USBPHY_RX_TOG 0x2C /* PHY Receiver Control Register */ 88258057Sbr#define USBPHY_CTRL 0x30 /* PHY General Control Register */ 89258057Sbr#define USBPHY_CTRL_SET 0x34 /* PHY General Control Register */ 90258057Sbr#define USBPHY_CTRL_CLR 0x38 /* PHY General Control Register */ 91258057Sbr#define USBPHY_CTRL_TOG 0x3C /* PHY General Control Register */ 92258057Sbr#define USBPHY_STATUS 0x40 /* PHY Status Register */ 93258057Sbr#define USBPHY_DEBUG 0x50 /* PHY Debug Register */ 94258057Sbr#define USBPHY_DEBUG_SET 0x54 /* PHY Debug Register */ 95258057Sbr#define USBPHY_DEBUG_CLR 0x58 /* PHY Debug Register */ 96258057Sbr#define USBPHY_DEBUG_TOG 0x5C /* PHY Debug Register */ 97258057Sbr#define USBPHY_DEBUG0_STATUS 0x60 /* UTMI Debug Status Register 0 */ 98258057Sbr#define USBPHY_DEBUG1 0x70 /* UTMI Debug Status Register 1 */ 99258057Sbr#define USBPHY_DEBUG1_SET 0x74 /* UTMI Debug Status Register 1 */ 100258057Sbr#define USBPHY_DEBUG1_CLR 0x78 /* UTMI Debug Status Register 1 */ 101258057Sbr#define USBPHY_DEBUG1_TOG 0x7C /* UTMI Debug Status Register 1 */ 102258057Sbr#define USBPHY_VERSION 0x80 /* UTMI RTL Version */ 103258057Sbr#define USBPHY_IP 0x90 /* PHY IP Block Register */ 104258057Sbr#define USBPHY_IP_SET 0x94 /* PHY IP Block Register */ 105258057Sbr#define USBPHY_IP_CLR 0x98 /* PHY IP Block Register */ 106258057Sbr#define USBPHY_IP_TOG 0x9C /* PHY IP Block Register */ 107258057Sbr 108258057Sbr#define USBPHY_CTRL_SFTRST (1 << 31) 109258057Sbr#define USBPHY_CTRL_CLKGATE (1 << 30) 110258057Sbr#define USBPHY_DEBUG_CLKGATE (1 << 30) 111258057Sbr 112258057Sbr#define PHY_READ4(_sc, _reg) \ 113258057Sbr bus_space_read_4(_sc->bst_phy, _sc->bsh_phy, _reg) 114258057Sbr#define PHY_WRITE4(_sc, _reg, _val) \ 115258057Sbr bus_space_write_4(_sc->bst_phy, _sc->bsh_phy, _reg, _val) 116258057Sbr 117258057Sbr#define USBC_READ4(_sc, _reg) \ 118258057Sbr bus_space_read_4(_sc->bst_usbc, _sc->bsh_usbc, _reg) 119258057Sbr#define USBC_WRITE4(_sc, _reg, _val) \ 120258057Sbr bus_space_write_4(_sc->bst_usbc, _sc->bsh_usbc, _reg, _val) 121258057Sbr 122258057Sbr/* Forward declarations */ 123258057Sbrstatic int vybrid_ehci_attach(device_t dev); 124258057Sbrstatic int vybrid_ehci_detach(device_t dev); 125258057Sbrstatic int vybrid_ehci_probe(device_t dev); 126258057Sbr 127258057Sbrstruct vybrid_ehci_softc { 128258057Sbr ehci_softc_t base; 129258057Sbr device_t dev; 130258057Sbr struct resource *res[6]; 131258057Sbr bus_space_tag_t bst_phy; 132258057Sbr bus_space_handle_t bsh_phy; 133258057Sbr bus_space_tag_t bst_usbc; 134258057Sbr bus_space_handle_t bsh_usbc; 135258057Sbr}; 136258057Sbr 137258057Sbrstatic struct resource_spec vybrid_ehci_spec[] = { 138258057Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 139258057Sbr { SYS_RES_MEMORY, 1, RF_ACTIVE }, 140258057Sbr { SYS_RES_MEMORY, 2, RF_ACTIVE }, 141258057Sbr { SYS_RES_IRQ, 0, RF_ACTIVE }, 142258057Sbr { -1, 0 } 143258057Sbr}; 144258057Sbr 145258057Sbrstatic device_method_t ehci_methods[] = { 146258057Sbr /* Device interface */ 147258057Sbr DEVMETHOD(device_probe, vybrid_ehci_probe), 148258057Sbr DEVMETHOD(device_attach, vybrid_ehci_attach), 149258057Sbr DEVMETHOD(device_detach, vybrid_ehci_detach), 150258057Sbr DEVMETHOD(device_suspend, bus_generic_suspend), 151258057Sbr DEVMETHOD(device_resume, bus_generic_resume), 152258057Sbr DEVMETHOD(device_shutdown, bus_generic_shutdown), 153258057Sbr 154258057Sbr /* Bus interface */ 155258057Sbr DEVMETHOD(bus_print_child, bus_generic_print_child), 156258057Sbr 157258057Sbr { 0, 0 } 158258057Sbr}; 159258057Sbr 160258057Sbr/* kobj_class definition */ 161258057Sbrstatic driver_t ehci_driver = { 162258057Sbr "ehci", 163258057Sbr ehci_methods, 164258057Sbr sizeof(ehci_softc_t) 165258057Sbr}; 166258057Sbr 167258057Sbrstatic devclass_t ehci_devclass; 168258057Sbr 169258057SbrDRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0); 170258057SbrMODULE_DEPEND(ehci, usb, 1, 1, 1); 171258057Sbr 172258057Sbr/* 173258057Sbr * Public methods 174258057Sbr */ 175258057Sbrstatic int 176258057Sbrvybrid_ehci_probe(device_t dev) 177258057Sbr{ 178258057Sbr 179266152Sian if (!ofw_bus_status_okay(dev)) 180266152Sian return (ENXIO); 181266152Sian 182258057Sbr if (ofw_bus_is_compatible(dev, "fsl,mvf600-usb-ehci") == 0) 183258057Sbr return (ENXIO); 184258057Sbr 185258057Sbr device_set_desc(dev, "Vybrid Family integrated USB controller"); 186258057Sbr return (BUS_PROBE_DEFAULT); 187258057Sbr} 188258057Sbr 189258057Sbrstatic int 190258057Sbrphy_init(struct vybrid_ehci_softc *esc) 191258057Sbr{ 192258057Sbr device_t sc_gpio_dev; 193258057Sbr int reg; 194258057Sbr 195258057Sbr /* Reset phy */ 196258057Sbr reg = PHY_READ4(esc, USBPHY_CTRL); 197258057Sbr reg |= (USBPHY_CTRL_SFTRST); 198258057Sbr PHY_WRITE4(esc, USBPHY_CTRL, reg); 199258057Sbr 200258057Sbr /* Minimum reset time */ 201258057Sbr DELAY(10000); 202258057Sbr 203258057Sbr reg &= ~(USBPHY_CTRL_SFTRST | USBPHY_CTRL_CLKGATE); 204258057Sbr PHY_WRITE4(esc, USBPHY_CTRL, reg); 205258057Sbr 206258057Sbr reg = (ENUTMILEVEL2 | ENUTMILEVEL3); 207258057Sbr PHY_WRITE4(esc, USBPHY_CTRL_SET, reg); 208258057Sbr 209258057Sbr /* Get the GPIO device, we need this to give power to USB */ 210258057Sbr sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0); 211258057Sbr if (sc_gpio_dev == NULL) { 212258057Sbr device_printf(esc->dev, "Error: failed to get the GPIO dev\n"); 213258057Sbr return (1); 214258057Sbr } 215258057Sbr 216258057Sbr /* Give power to USB */ 217258057Sbr GPIO_PIN_SETFLAGS(sc_gpio_dev, GPIO_USB_PWR, GPIO_PIN_OUTPUT); 218258057Sbr GPIO_PIN_SET(sc_gpio_dev, GPIO_USB_PWR, GPIO_PIN_HIGH); 219258057Sbr 220258057Sbr /* Power up PHY */ 221258057Sbr PHY_WRITE4(esc, USBPHY_PWD, 0x00); 222258057Sbr 223258057Sbr /* Ungate clocks */ 224258057Sbr reg = PHY_READ4(esc, USBPHY_DEBUG); 225258057Sbr reg &= ~(USBPHY_DEBUG_CLKGATE); 226258057Sbr PHY_WRITE4(esc, USBPHY_DEBUG, reg); 227258057Sbr 228258057Sbr#if 0 229258057Sbr printf("USBPHY_CTRL == 0x%08x\n", 230258057Sbr PHY_READ4(esc, USBPHY_CTRL)); 231258057Sbr printf("USBPHY_IP == 0x%08x\n", 232258057Sbr PHY_READ4(esc, USBPHY_IP)); 233258057Sbr printf("USBPHY_STATUS == 0x%08x\n", 234258057Sbr PHY_READ4(esc, USBPHY_STATUS)); 235258057Sbr printf("USBPHY_DEBUG == 0x%08x\n", 236258057Sbr PHY_READ4(esc, USBPHY_DEBUG)); 237258057Sbr printf("USBPHY_DEBUG0_STATUS == 0x%08x\n", 238258057Sbr PHY_READ4(esc, USBPHY_DEBUG0_STATUS)); 239258057Sbr printf("USBPHY_DEBUG1 == 0x%08x\n", 240258057Sbr PHY_READ4(esc, USBPHY_DEBUG1)); 241258057Sbr#endif 242258057Sbr 243258057Sbr return (0); 244258057Sbr} 245258057Sbr 246258057Sbrstatic int 247258057Sbrvybrid_ehci_attach(device_t dev) 248258057Sbr{ 249258057Sbr struct vybrid_ehci_softc *esc; 250258057Sbr ehci_softc_t *sc; 251258057Sbr bus_space_handle_t bsh; 252258057Sbr int err; 253258057Sbr int reg; 254258057Sbr 255258057Sbr esc = device_get_softc(dev); 256258057Sbr esc->dev = dev; 257258057Sbr 258258057Sbr sc = &esc->base; 259258057Sbr sc->sc_bus.parent = dev; 260258057Sbr sc->sc_bus.devices = sc->sc_devices; 261258057Sbr sc->sc_bus.devices_max = EHCI_MAX_DEVICES; 262258057Sbr 263258057Sbr if (bus_alloc_resources(dev, vybrid_ehci_spec, esc->res)) { 264258057Sbr device_printf(dev, "could not allocate resources\n"); 265258057Sbr return (ENXIO); 266258057Sbr } 267258057Sbr 268258057Sbr /* EHCI registers */ 269258057Sbr sc->sc_io_tag = rman_get_bustag(esc->res[0]); 270258057Sbr bsh = rman_get_bushandle(esc->res[0]); 271258057Sbr sc->sc_io_size = rman_get_size(esc->res[0]); 272258057Sbr 273258057Sbr esc->bst_usbc = rman_get_bustag(esc->res[1]); 274258057Sbr esc->bsh_usbc = rman_get_bushandle(esc->res[1]); 275258057Sbr 276258057Sbr esc->bst_phy = rman_get_bustag(esc->res[2]); 277258057Sbr esc->bsh_phy = rman_get_bushandle(esc->res[2]); 278258057Sbr 279258057Sbr /* get all DMA memory */ 280258057Sbr if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(dev), 281258057Sbr &ehci_iterate_hw_softc)) 282258057Sbr return (ENXIO); 283258057Sbr 284258057Sbr#if 0 285258057Sbr printf("USBx_HCSPARAMS is 0x%08x\n", 286258057Sbr bus_space_read_4(sc->sc_io_tag, bsh, USB_HCSPARAMS)); 287258057Sbr printf("USB_ID == 0x%08x\n", 288258057Sbr bus_space_read_4(sc->sc_io_tag, bsh, USB_ID)); 289258057Sbr printf("USB_HWGENERAL == 0x%08x\n", 290258057Sbr bus_space_read_4(sc->sc_io_tag, bsh, USB_HWGENERAL)); 291258057Sbr printf("USB_HWHOST == 0x%08x\n", 292258057Sbr bus_space_read_4(sc->sc_io_tag, bsh, USB_HWHOST)); 293258057Sbr printf("USB_HWDEVICE == 0x%08x\n", 294258057Sbr bus_space_read_4(sc->sc_io_tag, bsh, USB_HWDEVICE)); 295258057Sbr printf("USB_HWTXBUF == 0x%08x\n", 296258057Sbr bus_space_read_4(sc->sc_io_tag, bsh, USB_HWTXBUF)); 297258057Sbr printf("USB_HWRXBUF == 0x%08x\n", 298258057Sbr bus_space_read_4(sc->sc_io_tag, bsh, USB_HWRXBUF)); 299258057Sbr#endif 300258057Sbr 301258057Sbr if (phy_init(esc)) { 302258057Sbr device_printf(dev, "Could not setup PHY\n"); 303258057Sbr return (1); 304258057Sbr } 305258057Sbr 306258057Sbr /* 307258057Sbr * Set handle to USB related registers subregion used by 308258057Sbr * generic EHCI driver. 309258057Sbr */ 310258057Sbr err = bus_space_subregion(sc->sc_io_tag, bsh, 0x100, 311258057Sbr sc->sc_io_size, &sc->sc_io_hdl); 312258057Sbr if (err != 0) 313258057Sbr return (ENXIO); 314258057Sbr 315258057Sbr /* Setup interrupt handler */ 316258057Sbr err = bus_setup_intr(dev, esc->res[3], INTR_TYPE_BIO | INTR_MPSAFE, 317258057Sbr NULL, (driver_intr_t *)ehci_interrupt, sc, 318258057Sbr &sc->sc_intr_hdl); 319258057Sbr if (err) { 320258057Sbr device_printf(dev, "Could not setup irq, " 321258057Sbr "%d\n", err); 322258057Sbr return (1); 323258057Sbr } 324258057Sbr 325258057Sbr /* Add USB device */ 326258057Sbr sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); 327258057Sbr if (!sc->sc_bus.bdev) { 328258057Sbr device_printf(dev, "Could not add USB device\n"); 329258057Sbr err = bus_teardown_intr(dev, esc->res[5], 330258057Sbr sc->sc_intr_hdl); 331258057Sbr if (err) 332258057Sbr device_printf(dev, "Could not tear down irq," 333258057Sbr " %d\n", err); 334258057Sbr return (1); 335258057Sbr } 336258057Sbr device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 337258057Sbr 338258057Sbr strlcpy(sc->sc_vendor, "Freescale", sizeof(sc->sc_vendor)); 339258057Sbr 340258057Sbr /* Set host mode */ 341258057Sbr reg = bus_space_read_4(sc->sc_io_tag, sc->sc_io_hdl, 0xA8); 342258057Sbr reg |= 0x3; 343258057Sbr bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, 0xA8, reg); 344258057Sbr 345258057Sbr /* Set flags */ 346258057Sbr sc->sc_flags |= EHCI_SCFLG_SETMODE | EHCI_SCFLG_NORESTERM; 347258057Sbr 348258057Sbr err = ehci_init(sc); 349258057Sbr if (!err) { 350258057Sbr sc->sc_flags |= EHCI_SCFLG_DONEINIT; 351258057Sbr err = device_probe_and_attach(sc->sc_bus.bdev); 352258057Sbr } else { 353258057Sbr device_printf(dev, "USB init failed err=%d\n", err); 354258057Sbr 355258057Sbr device_delete_child(dev, sc->sc_bus.bdev); 356258057Sbr sc->sc_bus.bdev = NULL; 357258057Sbr 358258057Sbr err = bus_teardown_intr(dev, esc->res[5], 359258057Sbr sc->sc_intr_hdl); 360258057Sbr if (err) 361258057Sbr device_printf(dev, "Could not tear down irq," 362258057Sbr " %d\n", err); 363258057Sbr return (1); 364258057Sbr } 365258057Sbr return (0); 366258057Sbr} 367258057Sbr 368258057Sbrstatic int 369258057Sbrvybrid_ehci_detach(device_t dev) 370258057Sbr{ 371258057Sbr struct vybrid_ehci_softc *esc; 372258057Sbr ehci_softc_t *sc; 373258057Sbr int err; 374258057Sbr 375258057Sbr esc = device_get_softc(dev); 376258057Sbr sc = &esc->base; 377258057Sbr 378258057Sbr if (sc->sc_flags & EHCI_SCFLG_DONEINIT) 379258057Sbr return (0); 380258057Sbr 381258057Sbr /* 382258057Sbr * only call ehci_detach() after ehci_init() 383258057Sbr */ 384258057Sbr if (sc->sc_flags & EHCI_SCFLG_DONEINIT) { 385258057Sbr ehci_detach(sc); 386258057Sbr sc->sc_flags &= ~EHCI_SCFLG_DONEINIT; 387258057Sbr } 388258057Sbr 389258057Sbr /* 390258057Sbr * Disable interrupts that might have been switched on in 391258057Sbr * ehci_init. 392258057Sbr */ 393258057Sbr if (sc->sc_io_tag && sc->sc_io_hdl) 394258057Sbr bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, 395258057Sbr EHCI_USBINTR, 0); 396258057Sbr 397258057Sbr if (esc->res[5] && sc->sc_intr_hdl) { 398258057Sbr err = bus_teardown_intr(dev, esc->res[5], 399258057Sbr sc->sc_intr_hdl); 400258057Sbr if (err) { 401258057Sbr device_printf(dev, "Could not tear down irq," 402258057Sbr " %d\n", err); 403258057Sbr return (err); 404258057Sbr } 405258057Sbr sc->sc_intr_hdl = NULL; 406258057Sbr } 407258057Sbr 408258057Sbr if (sc->sc_bus.bdev) { 409258057Sbr device_delete_child(dev, sc->sc_bus.bdev); 410258057Sbr sc->sc_bus.bdev = NULL; 411258057Sbr } 412258057Sbr 413258057Sbr /* During module unload there are lots of children leftover */ 414258057Sbr device_delete_children(dev); 415258057Sbr 416258057Sbr bus_release_resources(dev, vybrid_ehci_spec, esc->res); 417258057Sbr 418258057Sbr return (0); 419258057Sbr} 420