1168404Spjd/*- 2168404Spjd * Copyright (c) 2013-2014 Ruslan Bukin <br@bsdpad.com> 3168404Spjd * All rights reserved. 4168404Spjd * 5168404Spjd * Redistribution and use in source and binary forms, with or without 6168404Spjd * modification, are permitted provided that the following conditions 7168404Spjd * are met: 8168404Spjd * 1. Redistributions of source code must retain the above copyright 9168404Spjd * notice, this list of conditions and the following disclaimer. 10168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 11168404Spjd * notice, this list of conditions and the following disclaimer in the 12168404Spjd * documentation and/or other materials provided with the distribution. 13168404Spjd * 14168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17168404Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22219089Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23332528Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24339114Smav * SUCH DAMAGE. 25260835Sdelphij */ 26329490Smav 27168404Spjd#ifdef USB_GLOBAL_INCLUDE_FILE 28168404Spjd#include USB_GLOBAL_INCLUDE_FILE 29168404Spjd#else 30168404Spjd#include <sys/cdefs.h> 31168404Spjd__FBSDID("$FreeBSD: stable/11/sys/arm/samsung/exynos/exynos5_ehci.c 346524 2019-04-22 04:56:41Z ian $"); 32168404Spjd 33168404Spjd#include "opt_bus.h" 34168404Spjd 35168404Spjd#include <sys/param.h> 36168404Spjd#include <sys/systm.h> 37168404Spjd#include <sys/kernel.h> 38168404Spjd#include <sys/module.h> 39168404Spjd#include <sys/bus.h> 40168404Spjd#include <sys/condvar.h> 41168404Spjd#include <sys/rman.h> 42168404Spjd#include <sys/gpio.h> 43168404Spjd 44168404Spjd#include <dev/ofw/ofw_bus.h> 45168404Spjd#include <dev/ofw/ofw_bus_subr.h> 46168404Spjd 47168404Spjd#include <dev/usb/usb.h> 48168404Spjd#include <dev/usb/usbdi.h> 49168404Spjd#include <dev/usb/usb_busdma.h> 50168404Spjd#include <dev/usb/usb_process.h> 51185029Spjd#include <dev/usb/usb_controller.h> 52185029Spjd#include <dev/usb/usb_bus.h> 53168404Spjd#include <dev/usb/controller/ehci.h> 54168404Spjd#include <dev/usb/controller/ehcireg.h> 55168404Spjd 56168404Spjd#include <machine/bus.h> 57185029Spjd#include <machine/resource.h> 58168404Spjd 59168404Spjd#include <arm/samsung/exynos/exynos5_common.h> 60168404Spjd#include <arm/samsung/exynos/exynos5_pmu.h> 61168404Spjd 62251631Sdelphij#include "gpio_if.h" 63168404Spjd 64168404Spjd#include "opt_platform.h" 65168404Spjd#endif 66251631Sdelphij 67168404Spjd/* GPIO control */ 68168404Spjd#define GPIO_OUTPUT 1 69168404Spjd#define GPIO_INPUT 0 70168404Spjd#define PIN_USB 161 71168404Spjd 72168404Spjd/* SYSREG */ 73168404Spjd#define EXYNOS5_SYSREG_USB2_PHY 0x0 74168404Spjd#define USB2_MODE_HOST 0x1 75168404Spjd 76168404Spjd/* USB HOST */ 77168404Spjd#define HOST_CTRL_CLK_24MHZ (5 << 16) 78168404Spjd#define HOST_CTRL_CLK_MASK (7 << 16) 79185029Spjd#define HOST_CTRL_SIDDQ (1 << 6) 80321535Smav#define HOST_CTRL_SLEEP (1 << 5) 81251631Sdelphij#define HOST_CTRL_SUSPEND (1 << 4) 82168404Spjd#define HOST_CTRL_RESET_LINK (1 << 1) 83321535Smav#define HOST_CTRL_RESET_PHY (1 << 0) 84168404Spjd#define HOST_CTRL_RESET_PHY_ALL (1U << 31) 85286774Smav 86286774Smav/* Forward declarations */ 87286774Smavstatic int exynos_ehci_attach(device_t dev); 88168404Spjdstatic int exynos_ehci_detach(device_t dev); 89168404Spjdstatic int exynos_ehci_probe(device_t dev); 90168404Spjd 91168404Spjdstruct exynos_ehci_softc { 92168404Spjd device_t dev; 93168404Spjd ehci_softc_t base; 94168404Spjd struct resource *res[4]; 95168404Spjd bus_space_tag_t host_bst; 96321535Smav bus_space_tag_t sysreg_bst; 97168404Spjd bus_space_handle_t host_bsh; 98321535Smav bus_space_handle_t sysreg_bsh; 99168404Spjd 100168404Spjd}; 101168404Spjd 102168404Spjdstatic struct resource_spec exynos_ehci_spec[] = { 103168404Spjd { SYS_RES_MEMORY, 0, RF_ACTIVE }, 104185029Spjd { SYS_RES_MEMORY, 1, RF_ACTIVE }, 105286570Smav { SYS_RES_MEMORY, 2, RF_ACTIVE }, 106185029Spjd { SYS_RES_IRQ, 0, RF_ACTIVE }, 107185029Spjd { -1, 0 } 108185029Spjd}; 109185029Spjd 110185029Spjdstatic device_method_t ehci_methods[] = { 111185029Spjd /* Device interface */ 112168404Spjd DEVMETHOD(device_probe, exynos_ehci_probe), 113168404Spjd DEVMETHOD(device_attach, exynos_ehci_attach), 114307265Smav DEVMETHOD(device_detach, exynos_ehci_detach), 115307265Smav DEVMETHOD(device_suspend, bus_generic_suspend), 116307265Smav DEVMETHOD(device_resume, bus_generic_resume), 117307265Smav DEVMETHOD(device_shutdown, bus_generic_shutdown), 118307265Smav 119307265Smav /* Bus interface */ 120307265Smav DEVMETHOD(bus_print_child, bus_generic_print_child), 121307265Smav 122307265Smav { 0, 0 } 123307265Smav}; 124307265Smav 125307265Smav/* kobj_class definition */ 126307265Smavstatic driver_t ehci_driver = { 127307265Smav "ehci", 128307265Smav ehci_methods, 129307265Smav sizeof(struct exynos_ehci_softc) 130321535Smav}; 131321610Smav 132321535Smavstatic devclass_t ehci_devclass; 133321535Smav 134321610SmavDRIVER_MODULE(exynos_ehci, simplebus, ehci_driver, ehci_devclass, 0, 0); 135321610SmavMODULE_DEPEND(exynos_ehci, usb, 1, 1, 1); 136321535Smav 137321535Smav/* 138321610Smav * Public methods 139321535Smav */ 140321535Smavstatic int 141321535Smavexynos_ehci_probe(device_t dev) 142321535Smav{ 143321535Smav 144321535Smav if (!ofw_bus_status_okay(dev)) 145321535Smav return (ENXIO); 146321535Smav 147321535Smav if (ofw_bus_is_compatible(dev, "exynos,usb-ehci") == 0) 148307265Smav return (ENXIO); 149307265Smav 150321535Smav device_set_desc(dev, "Exynos integrated USB controller"); 151321535Smav return (BUS_PROBE_DEFAULT); 152321535Smav} 153321535Smav 154321535Smavstatic int 155321535Smavgpio_ctrl(struct exynos_ehci_softc *esc, int dir, int power) 156321535Smav{ 157307265Smav device_t gpio_dev; 158321535Smav 159321535Smav /* Get the GPIO device, we need this to give power to USB */ 160321535Smav gpio_dev = devclass_get_device(devclass_find("gpio"), 0); 161321535Smav if (gpio_dev == NULL) { 162321535Smav device_printf(esc->dev, "cant find gpio_dev\n"); 163307265Smav return (1); 164321535Smav } 165321535Smav 166321535Smav if (power) 167321535Smav GPIO_PIN_SET(gpio_dev, PIN_USB, GPIO_PIN_HIGH); 168321535Smav else 169321535Smav GPIO_PIN_SET(gpio_dev, PIN_USB, GPIO_PIN_LOW); 170321535Smav 171321535Smav if (dir) 172321535Smav GPIO_PIN_SETFLAGS(gpio_dev, PIN_USB, GPIO_PIN_OUTPUT); 173321535Smav else 174321535Smav GPIO_PIN_SETFLAGS(gpio_dev, PIN_USB, GPIO_PIN_INPUT); 175321535Smav 176321535Smav return (0); 177321610Smav} 178321535Smav 179321535Smavstatic int 180321535Smavreset_hsic_hub(struct exynos_ehci_softc *esc, phandle_t hub) 181321535Smav{ 182321535Smav device_t gpio_dev; 183321535Smav pcell_t pin; 184321535Smav 185321535Smav /* TODO: check that hub is compatible with "smsc,usb3503" */ 186321535Smav if (!OF_hasprop(hub, "freebsd,reset-gpio")) { 187321535Smav return (1); 188321535Smav } 189321535Smav 190307265Smav if (OF_getencprop(hub, "freebsd,reset-gpio", &pin, sizeof(pin)) < 0) { 191307265Smav device_printf(esc->dev, 192321535Smav "failed to decode reset GPIO pin number for HSIC hub\n"); 193321535Smav return (1); 194321610Smav } 195321610Smav 196321535Smav /* Get the GPIO device, we need this to give power to USB */ 197321535Smav gpio_dev = devclass_get_device(devclass_find("gpio"), 0); 198321535Smav if (gpio_dev == NULL) { 199321535Smav device_printf(esc->dev, "Cant find gpio device\n"); 200321535Smav return (1); 201307265Smav } 202307265Smav 203321535Smav GPIO_PIN_SET(gpio_dev, pin, GPIO_PIN_LOW); 204321535Smav DELAY(100); 205307265Smav GPIO_PIN_SET(gpio_dev, pin, GPIO_PIN_HIGH); 206307265Smav 207307265Smav return (0); 208307265Smav} 209307265Smav 210307265Smavstatic int 211307265Smavphy_init(struct exynos_ehci_softc *esc) 212307265Smav{ 213307265Smav int reg; 214307265Smav phandle_t hub; 215307265Smav 216307265Smav gpio_ctrl(esc, GPIO_INPUT, 1); 217307265Smav 218307265Smav /* set USB HOST mode */ 219321610Smav bus_space_write_4(esc->sysreg_bst, esc->sysreg_bsh, 220307265Smav EXYNOS5_SYSREG_USB2_PHY, USB2_MODE_HOST); 221307265Smav 222307265Smav /* Power ON phy */ 223307265Smav usb2_phy_power_on(); 224307265Smav 225307265Smav reg = bus_space_read_4(esc->host_bst, esc->host_bsh, 0x0); 226307265Smav reg &= ~(HOST_CTRL_CLK_MASK | 227307265Smav HOST_CTRL_RESET_PHY | 228307265Smav HOST_CTRL_RESET_PHY_ALL | 229307265Smav HOST_CTRL_SIDDQ | 230307265Smav HOST_CTRL_SUSPEND | 231307265Smav HOST_CTRL_SLEEP); 232307265Smav 233321610Smav reg |= (HOST_CTRL_CLK_24MHZ | 234307265Smav HOST_CTRL_RESET_LINK); 235321535Smav bus_space_write_4(esc->host_bst, esc->host_bsh, 0x0, reg); 236321535Smav 237321535Smav DELAY(10); 238321610Smav 239321535Smav reg = bus_space_read_4(esc->host_bst, esc->host_bsh, 0x0); 240321535Smav reg &= ~(HOST_CTRL_RESET_LINK); 241321535Smav bus_space_write_4(esc->host_bst, esc->host_bsh, 0x0, reg); 242321535Smav 243307265Smav if ((hub = OF_finddevice("/hsichub")) != 0) { 244321610Smav reset_hsic_hub(esc, hub); 245321610Smav } 246321535Smav 247307265Smav gpio_ctrl(esc, GPIO_OUTPUT, 1); 248307265Smav 249307265Smav return (0); 250321535Smav} 251307265Smav 252307265Smavstatic int 253307265Smavexynos_ehci_attach(device_t dev) 254307265Smav{ 255168404Spjd struct exynos_ehci_softc *esc; 256168404Spjd ehci_softc_t *sc; 257307265Smav bus_space_handle_t bsh; 258251478Sdelphij int err; 259307265Smav 260168404Spjd esc = device_get_softc(dev); 261168404Spjd esc->dev = dev; 262168404Spjd sc = &esc->base; 263185029Spjd sc->sc_bus.parent = dev; 264219089Spjd sc->sc_bus.devices = sc->sc_devices; 265258632Savg sc->sc_bus.devices_max = EHCI_MAX_DEVICES; 266321610Smav sc->sc_bus.dma_bits = 32; 267286763Smav 268321610Smav if (bus_alloc_resources(dev, exynos_ehci_spec, esc->res)) { 269168404Spjd device_printf(dev, "could not allocate resources\n"); 270168404Spjd return (ENXIO); 271297633Strasz } 272168404Spjd 273168404Spjd /* EHCI registers */ 274168404Spjd sc->sc_io_tag = rman_get_bustag(esc->res[0]); 275248572Ssmh bsh = rman_get_bushandle(esc->res[0]); 276219089Spjd sc->sc_io_size = rman_get_size(esc->res[0]); 277168404Spjd 278332540Smav /* EHCI HOST ctrl registers */ 279332540Smav esc->host_bst = rman_get_bustag(esc->res[1]); 280168404Spjd esc->host_bsh = rman_get_bushandle(esc->res[1]); 281272483Ssmh 282191902Skmacy /* SYSREG */ 283240133Smm esc->sysreg_bst = rman_get_bustag(esc->res[2]); 284240133Smm esc->sysreg_bsh = rman_get_bushandle(esc->res[2]); 285240133Smm 286240133Smm /* get all DMA memory */ 287240133Smm if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(dev), 288240133Smm &ehci_iterate_hw_softc)) 289240133Smm return (ENXIO); 290240133Smm 291286763Smav /* 292286763Smav * Set handle to USB related registers subregion used by 293286763Smav * generic EHCI driver. 294286763Smav */ 295168404Spjd err = bus_space_subregion(sc->sc_io_tag, bsh, 0x0, 296301997Skib sc->sc_io_size, &sc->sc_io_hdl); 297301997Skib if (err != 0) 298301997Skib return (ENXIO); 299301997Skib 300286625Smav phy_init(esc); 301168404Spjd 302258632Savg /* Setup interrupt handler */ 303286763Smav err = bus_setup_intr(dev, esc->res[3], INTR_TYPE_BIO | INTR_MPSAFE, 304286763Smav NULL, (driver_intr_t *)ehci_interrupt, sc, 305286763Smav &sc->sc_intr_hdl); 306286763Smav if (err) { 307286763Smav device_printf(dev, "Could not setup irq, " 308258632Savg "%d\n", err); 309286763Smav return (1); 310258632Savg } 311168404Spjd 312168404Spjd /* Add USB device */ 313168404Spjd sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); 314332528Smav if (!sc->sc_bus.bdev) { 315338346Smarkj device_printf(dev, "Could not add USB device\n"); 316332528Smav err = bus_teardown_intr(dev, esc->res[3], 317321610Smav sc->sc_intr_hdl); 318286763Smav if (err) 319286763Smav device_printf(dev, "Could not tear down irq," 320208373Smm " %d\n", err); 321208373Smm return (1); 322208373Smm } 323208373Smm device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 324286625Smav 325208373Smm strlcpy(sc->sc_vendor, "Samsung", sizeof(sc->sc_vendor)); 326168404Spjd 327286625Smav err = ehci_init(sc); 328286625Smav if (!err) { 329286625Smav sc->sc_flags |= EHCI_SCFLG_DONEINIT; 330286625Smav err = device_probe_and_attach(sc->sc_bus.bdev); 331286625Smav } else { 332286625Smav device_printf(dev, "USB init failed err=%d\n", err); 333286625Smav 334286625Smav device_delete_child(dev, sc->sc_bus.bdev); 335286625Smav sc->sc_bus.bdev = NULL; 336286625Smav 337286625Smav err = bus_teardown_intr(dev, esc->res[3], 338286625Smav sc->sc_intr_hdl); 339168404Spjd if (err) 340168404Spjd device_printf(dev, "Could not tear down irq," 341168404Spjd " %d\n", err); 342339034Ssef return (1); 343339034Ssef } 344168404Spjd return (0); 345258632Savg} 346258632Savg 347258632Savgstatic int 348258632Savgexynos_ehci_detach(device_t dev) 349258632Savg{ 350208373Smm struct exynos_ehci_softc *esc; 351287702Sdelphij ehci_softc_t *sc; 352168404Spjd int err; 353168404Spjd 354185029Spjd esc = device_get_softc(dev); 355185029Spjd sc = &esc->base; 356185029Spjd 357185029Spjd if (sc->sc_flags & EHCI_SCFLG_DONEINIT) 358286762Smav return (0); 359331383Smav 360331383Smav /* 361331383Smav * only call ehci_detach() after ehci_init() 362331383Smav */ 363331383Smav if (sc->sc_flags & EHCI_SCFLG_DONEINIT) { 364286762Smav ehci_detach(sc); 365286762Smav sc->sc_flags &= ~EHCI_SCFLG_DONEINIT; 366185029Spjd } 367185029Spjd 368185029Spjd /* 369275780Sdelphij * Disable interrupts that might have been switched on in 370208373Smm * ehci_init. 371208373Smm */ 372323667Sbapt if (sc->sc_io_tag && sc->sc_io_hdl) 373208373Smm bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, 374269230Sdelphij EHCI_USBINTR, 0); 375272483Ssmh 376185029Spjd if (esc->res[3] && sc->sc_intr_hdl) { 377302265Ssmh err = bus_teardown_intr(dev, esc->res[3], 378302265Ssmh sc->sc_intr_hdl); 379302265Ssmh if (err) { 380307265Smav device_printf(dev, "Could not tear down irq," 381307265Smav " %d\n", err); 382270759Ssmh return (err); 383275748Sdelphij } 384302265Ssmh sc->sc_intr_hdl = NULL; 385302265Ssmh } 386323667Sbapt 387270759Ssmh if (sc->sc_bus.bdev) { 388302265Ssmh device_delete_child(dev, sc->sc_bus.bdev); 389270759Ssmh sc->sc_bus.bdev = NULL; 390270759Ssmh } 391270759Ssmh 392270759Ssmh /* During module unload there are lots of children leftover */ 393272483Ssmh device_delete_children(dev); 394270759Ssmh 395270759Ssmh bus_release_resources(dev, exynos_ehci_spec, esc->res); 396270759Ssmh 397270759Ssmh return (0); 398185029Spjd} 399275780Sdelphij