uboot/drivers/usb/host/ehci-omap.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2011 Ilya Yanok, Emcraft Systems
   4 * (C) Copyright 2004-2008
   5 * Texas Instruments, <www.ti.com>
   6 *
   7 * Derived from Beagle Board code by
   8 *      Sunil Kumar <sunilsaini05@gmail.com>
   9 *      Shashi Ranjan <shashiranjanmca05@gmail.com>
  10 *
  11 */
  12
  13#include <common.h>
  14#include <log.h>
  15#include <usb.h>
  16#include <linux/delay.h>
  17#include <usb/ulpi.h>
  18#include <errno.h>
  19#include <asm/io.h>
  20#include <asm/gpio.h>
  21#include <asm/arch/ehci.h>
  22#include <asm/ehci-omap.h>
  23#include <dm.h>
  24#include <dm/device-internal.h>
  25#include <dm/lists.h>
  26#include <power/regulator.h>
  27
  28#include "ehci.h"
  29
  30static struct omap_uhh *const uhh = (struct omap_uhh *)OMAP_UHH_BASE;
  31static struct omap_usbtll *const usbtll = (struct omap_usbtll *)OMAP_USBTLL_BASE;
  32static struct omap_ehci *const ehci = (struct omap_ehci *)OMAP_EHCI_BASE;
  33
  34static int omap_uhh_reset(void)
  35{
  36        int timeout = 0;
  37        u32 rev;
  38
  39        rev = readl(&uhh->rev);
  40
  41        /* Soft RESET */
  42        writel(OMAP_UHH_SYSCONFIG_SOFTRESET, &uhh->sysc);
  43
  44        switch (rev) {
  45        case OMAP_USBHS_REV1:
  46                /* Wait for soft RESET to complete */
  47                while (!(readl(&uhh->syss) & 0x1)) {
  48                        if (timeout > 100) {
  49                                printf("%s: RESET timeout\n", __func__);
  50                                return -1;
  51                        }
  52                        udelay(10);
  53                        timeout++;
  54                }
  55
  56                /* Set No-Idle, No-Standby */
  57                writel(OMAP_UHH_SYSCONFIG_VAL, &uhh->sysc);
  58                break;
  59
  60        default:        /* Rev. 2 onwards */
  61
  62                udelay(2); /* Need to wait before accessing SYSCONFIG back */
  63
  64                /* Wait for soft RESET to complete */
  65                while ((readl(&uhh->sysc) & 0x1)) {
  66                        if (timeout > 100) {
  67                                printf("%s: RESET timeout\n", __func__);
  68                                return -1;
  69                        }
  70                        udelay(10);
  71                        timeout++;
  72                }
  73
  74                writel(OMAP_UHH_SYSCONFIG_VAL, &uhh->sysc);
  75                break;
  76        }
  77
  78        return 0;
  79}
  80
  81static int omap_ehci_tll_reset(void)
  82{
  83        unsigned long init = get_timer(0);
  84
  85        /* perform TLL soft reset, and wait until reset is complete */
  86        writel(OMAP_USBTLL_SYSCONFIG_SOFTRESET, &usbtll->sysc);
  87
  88        /* Wait for TLL reset to complete */
  89        while (!(readl(&usbtll->syss) & OMAP_USBTLL_SYSSTATUS_RESETDONE))
  90                if (get_timer(init) > CONFIG_SYS_HZ) {
  91                        debug("OMAP EHCI error: timeout resetting TLL\n");
  92                        return -EL3RST;
  93        }
  94
  95        return 0;
  96}
  97
  98static void omap_usbhs_hsic_init(int port)
  99{
 100        unsigned int reg;
 101
 102        /* Enable channels now */
 103        reg = readl(&usbtll->channel_conf + port);
 104
 105        setbits_le32(&reg, (OMAP_TLL_CHANNEL_CONF_CHANMODE_TRANSPARENT_UTMI
 106                | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
 107                | OMAP_TLL_CHANNEL_CONF_DRVVBUS
 108                | OMAP_TLL_CHANNEL_CONF_CHRGVBUS
 109                | OMAP_TLL_CHANNEL_CONF_CHANEN));
 110
 111        writel(reg, &usbtll->channel_conf + port);
 112}
 113
 114#ifdef CONFIG_USB_ULPI
 115static void omap_ehci_soft_phy_reset(int port)
 116{
 117        struct ulpi_viewport ulpi_vp;
 118
 119        ulpi_vp.viewport_addr = (u32)&ehci->insreg05_utmi_ulpi;
 120        ulpi_vp.port_num = port;
 121
 122        ulpi_reset(&ulpi_vp);
 123}
 124#else
 125static void omap_ehci_soft_phy_reset(int port)
 126{
 127        return;
 128}
 129#endif
 130
 131#if defined(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO) || \
 132        defined(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO) || \
 133        defined(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO)
 134/* controls PHY(s) reset signal(s) */
 135static inline void omap_ehci_phy_reset(int on, int delay)
 136{
 137        /*
 138         * Refer ISSUE1:
 139         * Hold the PHY in RESET for enough time till
 140         * PHY is settled and ready
 141         */
 142        if (delay && !on)
 143                udelay(delay);
 144#ifdef CONFIG_OMAP_EHCI_PHY1_RESET_GPIO
 145        gpio_request(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO, "USB PHY1 reset");
 146        gpio_direction_output(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO, !on);
 147#endif
 148#ifdef CONFIG_OMAP_EHCI_PHY2_RESET_GPIO
 149        gpio_request(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO, "USB PHY2 reset");
 150        gpio_direction_output(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO, !on);
 151#endif
 152#ifdef CONFIG_OMAP_EHCI_PHY3_RESET_GPIO
 153        gpio_request(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO, "USB PHY3 reset");
 154        gpio_direction_output(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO, !on);
 155#endif
 156
 157        /* Hold the PHY in RESET for enough time till DIR is high */
 158        /* Refer: ISSUE1 */
 159        if (delay && on)
 160                udelay(delay);
 161}
 162#else
 163#define omap_ehci_phy_reset(on, delay)  do {} while (0)
 164#endif
 165
 166/* Reset is needed otherwise the kernel-driver will throw an error. */
 167int omap_ehci_hcd_stop(void)
 168{
 169        debug("Resetting OMAP EHCI\n");
 170        omap_ehci_phy_reset(1, 0);
 171
 172        if (omap_uhh_reset() < 0)
 173                return -1;
 174
 175        if (omap_ehci_tll_reset() < 0)
 176                return -1;
 177
 178        return 0;
 179}
 180
 181/*
 182 * Initialize the OMAP EHCI controller and PHY.
 183 * Based on "drivers/usb/host/ehci-omap.c" from Linux 3.1
 184 * See there for additional Copyrights.
 185 */
 186#if !CONFIG_IS_ENABLED(DM_USB) || !CONFIG_IS_ENABLED(OF_CONTROL)
 187
 188int omap_ehci_hcd_init(int index, struct omap_usbhs_board_data *usbhs_pdata,
 189                       struct ehci_hccr **hccr, struct ehci_hcor **hcor)
 190{
 191        *hccr = (struct ehci_hccr *)(OMAP_EHCI_BASE);
 192        *hcor = (struct ehci_hcor *)(OMAP_EHCI_BASE + 0x10);
 193#else
 194int omap_ehci_hcd_init(int index, struct omap_usbhs_board_data *usbhs_pdata)
 195{
 196#endif
 197        int ret;
 198        unsigned int i, reg = 0, rev = 0;
 199
 200        debug("Initializing OMAP EHCI\n");
 201
 202        ret = board_usb_init(index, USB_INIT_HOST);
 203        if (ret < 0)
 204                return ret;
 205
 206        /* Put the PHY in RESET */
 207        omap_ehci_phy_reset(1, 10);
 208
 209        ret = omap_uhh_reset();
 210        if (ret < 0)
 211                return ret;
 212
 213        ret = omap_ehci_tll_reset();
 214        if (ret)
 215                return ret;
 216
 217        writel(OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
 218                OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
 219                OMAP_USBTLL_SYSCONFIG_CACTIVITY, &usbtll->sysc);
 220
 221        /* Put UHH in NoIdle/NoStandby mode */
 222        writel(OMAP_UHH_SYSCONFIG_VAL, &uhh->sysc);
 223
 224        /* setup ULPI bypass and burst configurations */
 225        clrsetbits_le32(&reg, OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN,
 226                (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN |
 227                OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN |
 228                OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN));
 229
 230        rev = readl(&uhh->rev);
 231        if (rev == OMAP_USBHS_REV1) {
 232                if (is_ehci_phy_mode(usbhs_pdata->port_mode[0]))
 233                        clrbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS);
 234                else
 235                        setbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS);
 236
 237                if (is_ehci_phy_mode(usbhs_pdata->port_mode[1]))
 238                        clrbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS);
 239                else
 240                        setbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS);
 241
 242                if (is_ehci_phy_mode(usbhs_pdata->port_mode[2]))
 243                        clrbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS);
 244                else
 245                        setbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS);
 246        } else if (rev == OMAP_USBHS_REV2) {
 247
 248                clrsetbits_le32(&reg, (OMAP_P1_MODE_CLEAR | OMAP_P2_MODE_CLEAR),
 249                                        OMAP4_UHH_HOSTCONFIG_APP_START_CLK);
 250
 251                /* Clear port mode fields for PHY mode */
 252
 253                if (is_ehci_hsic_mode(usbhs_pdata->port_mode[0]))
 254                        setbits_le32(&reg, OMAP_P1_MODE_HSIC);
 255
 256                if (is_ehci_hsic_mode(usbhs_pdata->port_mode[1]))
 257                        setbits_le32(&reg, OMAP_P2_MODE_HSIC);
 258
 259        } else if (rev == OMAP_USBHS_REV2_1) {
 260
 261                clrsetbits_le32(&reg,
 262                                (OMAP_P1_MODE_CLEAR |
 263                                 OMAP_P2_MODE_CLEAR |
 264                                 OMAP_P3_MODE_CLEAR),
 265                                OMAP4_UHH_HOSTCONFIG_APP_START_CLK);
 266
 267                /* Clear port mode fields for PHY mode */
 268
 269                if (is_ehci_hsic_mode(usbhs_pdata->port_mode[0]))
 270                        setbits_le32(&reg, OMAP_P1_MODE_HSIC);
 271
 272                if (is_ehci_hsic_mode(usbhs_pdata->port_mode[1]))
 273                        setbits_le32(&reg, OMAP_P2_MODE_HSIC);
 274
 275                if (is_ehci_hsic_mode(usbhs_pdata->port_mode[2]))
 276                        setbits_le32(&reg, OMAP_P3_MODE_HSIC);
 277        }
 278
 279        debug("OMAP UHH_REVISION 0x%x\n", rev);
 280        writel(reg, &uhh->hostconfig);
 281
 282        for (i = 0; i < OMAP_HS_USB_PORTS; i++)
 283                if (is_ehci_hsic_mode(usbhs_pdata->port_mode[i]))
 284                        omap_usbhs_hsic_init(i);
 285
 286        omap_ehci_phy_reset(0, 10);
 287
 288        /*
 289         * An undocumented "feature" in the OMAP3 EHCI controller,
 290         * causes suspended ports to be taken out of suspend when
 291         * the USBCMD.Run/Stop bit is cleared (for example when
 292         * we do ehci_bus_suspend).
 293         * This breaks suspend-resume if the root-hub is allowed
 294         * to suspend. Writing 1 to this undocumented register bit
 295         * disables this feature and restores normal behavior.
 296         */
 297        writel(EHCI_INSNREG04_DISABLE_UNSUSPEND, &ehci->insreg04);
 298
 299        for (i = 0; i < OMAP_HS_USB_PORTS; i++)
 300                if (is_ehci_phy_mode(usbhs_pdata->port_mode[i]))
 301                        omap_ehci_soft_phy_reset(i);
 302
 303        debug("OMAP EHCI init done\n");
 304        return 0;
 305}
 306
 307#if CONFIG_IS_ENABLED(DM_USB)
 308
 309static struct omap_usbhs_board_data usbhs_bdata = {
 310        .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
 311        .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
 312        .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
 313};
 314
 315static void omap_usbhs_set_mode(u8 index, const char *mode)
 316{
 317        if (!strcmp(mode, "ehci-phy"))
 318                usbhs_bdata.port_mode[index] = OMAP_EHCI_PORT_MODE_PHY;
 319        else if (!strcmp(mode, "ehci-tll"))
 320                usbhs_bdata.port_mode[index] = OMAP_EHCI_PORT_MODE_TLL;
 321        else if (!strcmp(mode, "ehci-hsic"))
 322                usbhs_bdata.port_mode[index] = OMAP_EHCI_PORT_MODE_HSIC;
 323}
 324
 325static int omap_usbhs_probe(struct udevice *dev)
 326{
 327        u8 i;
 328        const char *mode;
 329        char prop[11];
 330
 331        /* Go through each port portX-mode to determing phy mode */
 332        for (i = 0; i < OMAP_HS_USB_PORTS; i++) {
 333                snprintf(prop, sizeof(prop), "port%d-mode", i + 1);
 334                mode = dev_read_string(dev, prop);
 335
 336                /* If the portX-mode exists, set the mode */
 337                if (mode)
 338                        omap_usbhs_set_mode(i, mode);
 339        }
 340
 341        return omap_ehci_hcd_init(0, &usbhs_bdata);
 342}
 343
 344static const struct udevice_id omap_usbhs_dt_ids[] = {
 345        { .compatible = "ti,usbhs-host" },
 346        { }
 347};
 348
 349U_BOOT_DRIVER(usb_omaphs_host) = {
 350        .name   = "usbhs-host",
 351        .id     = UCLASS_SIMPLE_BUS,
 352        .of_match = omap_usbhs_dt_ids,
 353        .probe  = omap_usbhs_probe,
 354        .flags  = DM_FLAG_ALLOC_PRIV_DMA,
 355};
 356
 357struct ehci_omap_priv_data {
 358        struct ehci_ctrl ctrl;
 359        struct omap_ehci *ehci;
 360#ifdef CONFIG_DM_REGULATOR
 361        struct udevice *vbus_supply;
 362#endif
 363        enum usb_init_type init_type;
 364        int portnr;
 365        struct phy phy[OMAP_HS_USB_PORTS];
 366        int nports;
 367};
 368
 369static int ehci_usb_of_to_plat(struct udevice *dev)
 370{
 371        struct usb_plat *plat = dev_get_plat(dev);
 372
 373        plat->init_type = USB_INIT_HOST;
 374
 375        return 0;
 376}
 377
 378static int omap_ehci_probe(struct udevice *dev)
 379{
 380        struct usb_plat *plat = dev_get_plat(dev);
 381        struct ehci_omap_priv_data *priv = dev_get_priv(dev);
 382        struct ehci_hccr *hccr;
 383        struct ehci_hcor *hcor;
 384
 385        priv->ehci = dev_read_addr_ptr(dev);
 386        priv->portnr = dev_seq(dev);
 387        priv->init_type = plat->init_type;
 388
 389        hccr = (struct ehci_hccr *)&priv->ehci->hccapbase;
 390        hcor = (struct ehci_hcor *)&priv->ehci->usbcmd;
 391
 392        return ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
 393}
 394
 395static const struct udevice_id omap_ehci_dt_ids[] = {
 396        { .compatible = "ti,ehci-omap" },
 397        { }
 398};
 399
 400U_BOOT_DRIVER(usb_omap_ehci) = {
 401        .name   = "omap-ehci",
 402        .id     = UCLASS_USB,
 403        .of_match = omap_ehci_dt_ids,
 404        .probe = omap_ehci_probe,
 405        .of_to_plat = ehci_usb_of_to_plat,
 406        .plat_auto      = sizeof(struct usb_plat),
 407        .priv_auto      = sizeof(struct ehci_omap_priv_data),
 408        .remove = ehci_deregister,
 409        .ops    = &ehci_usb_ops,
 410        .flags  = DM_FLAG_ALLOC_PRIV_DMA,
 411};
 412
 413#endif
 414