uboot/drivers/usb/host/ehci-omap.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2011 Ilya Yanok, Emcraft Systems
   3 * (C) Copyright 2004-2008
   4 * Texas Instruments, <www.ti.com>
   5 *
   6 * Derived from Beagle Board code by
   7 *      Sunil Kumar <sunilsaini05@gmail.com>
   8 *      Shashi Ranjan <shashiranjanmca05@gmail.com>
   9 *
  10 *
  11 * SPDX-License-Identifier:     GPL-2.0+
  12 */
  13
  14#include <common.h>
  15#include <usb.h>
  16#include <usb/ulpi.h>
  17#include <errno.h>
  18#include <asm/io.h>
  19#include <asm/gpio.h>
  20#include <asm/arch/ehci.h>
  21#include <asm/ehci-omap.h>
  22
  23#include "ehci.h"
  24
  25static struct omap_uhh *const uhh = (struct omap_uhh *)OMAP_UHH_BASE;
  26static struct omap_usbtll *const usbtll = (struct omap_usbtll *)OMAP_USBTLL_BASE;
  27static struct omap_ehci *const ehci = (struct omap_ehci *)OMAP_EHCI_BASE;
  28
  29static int omap_uhh_reset(void)
  30{
  31        int timeout = 0;
  32        u32 rev;
  33
  34        rev = readl(&uhh->rev);
  35
  36        /* Soft RESET */
  37        writel(OMAP_UHH_SYSCONFIG_SOFTRESET, &uhh->sysc);
  38
  39        switch (rev) {
  40        case OMAP_USBHS_REV1:
  41                /* Wait for soft RESET to complete */
  42                while (!(readl(&uhh->syss) & 0x1)) {
  43                        if (timeout > 100) {
  44                                printf("%s: RESET timeout\n", __func__);
  45                                return -1;
  46                        }
  47                        udelay(10);
  48                        timeout++;
  49                }
  50
  51                /* Set No-Idle, No-Standby */
  52                writel(OMAP_UHH_SYSCONFIG_VAL, &uhh->sysc);
  53                break;
  54
  55        default:        /* Rev. 2 onwards */
  56
  57                udelay(2); /* Need to wait before accessing SYSCONFIG back */
  58
  59                /* Wait for soft RESET to complete */
  60                while ((readl(&uhh->sysc) & 0x1)) {
  61                        if (timeout > 100) {
  62                                printf("%s: RESET timeout\n", __func__);
  63                                return -1;
  64                        }
  65                        udelay(10);
  66                        timeout++;
  67                }
  68
  69                writel(OMAP_UHH_SYSCONFIG_VAL, &uhh->sysc);
  70                break;
  71        }
  72
  73        return 0;
  74}
  75
  76static int omap_ehci_tll_reset(void)
  77{
  78        unsigned long init = get_timer(0);
  79
  80        /* perform TLL soft reset, and wait until reset is complete */
  81        writel(OMAP_USBTLL_SYSCONFIG_SOFTRESET, &usbtll->sysc);
  82
  83        /* Wait for TLL reset to complete */
  84        while (!(readl(&usbtll->syss) & OMAP_USBTLL_SYSSTATUS_RESETDONE))
  85                if (get_timer(init) > CONFIG_SYS_HZ) {
  86                        debug("OMAP EHCI error: timeout resetting TLL\n");
  87                        return -EL3RST;
  88        }
  89
  90        return 0;
  91}
  92
  93static void omap_usbhs_hsic_init(int port)
  94{
  95        unsigned int reg;
  96
  97        /* Enable channels now */
  98        reg = readl(&usbtll->channel_conf + port);
  99
 100        setbits_le32(&reg, (OMAP_TLL_CHANNEL_CONF_CHANMODE_TRANSPARENT_UTMI
 101                | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
 102                | OMAP_TLL_CHANNEL_CONF_DRVVBUS
 103                | OMAP_TLL_CHANNEL_CONF_CHRGVBUS
 104                | OMAP_TLL_CHANNEL_CONF_CHANEN));
 105
 106        writel(reg, &usbtll->channel_conf + port);
 107}
 108
 109#ifdef CONFIG_USB_ULPI
 110static void omap_ehci_soft_phy_reset(int port)
 111{
 112        struct ulpi_viewport ulpi_vp;
 113
 114        ulpi_vp.viewport_addr = (u32)&ehci->insreg05_utmi_ulpi;
 115        ulpi_vp.port_num = port;
 116
 117        ulpi_reset(&ulpi_vp);
 118}
 119#else
 120static void omap_ehci_soft_phy_reset(int port)
 121{
 122        return;
 123}
 124#endif
 125
 126#if defined(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO) || \
 127        defined(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO) || \
 128        defined(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO)
 129/* controls PHY(s) reset signal(s) */
 130static inline void omap_ehci_phy_reset(int on, int delay)
 131{
 132        /*
 133         * Refer ISSUE1:
 134         * Hold the PHY in RESET for enough time till
 135         * PHY is settled and ready
 136         */
 137        if (delay && !on)
 138                udelay(delay);
 139#ifdef CONFIG_OMAP_EHCI_PHY1_RESET_GPIO
 140        gpio_request(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO, "USB PHY1 reset");
 141        gpio_direction_output(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO, !on);
 142#endif
 143#ifdef CONFIG_OMAP_EHCI_PHY2_RESET_GPIO
 144        gpio_request(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO, "USB PHY2 reset");
 145        gpio_direction_output(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO, !on);
 146#endif
 147#ifdef CONFIG_OMAP_EHCI_PHY3_RESET_GPIO
 148        gpio_request(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO, "USB PHY3 reset");
 149        gpio_direction_output(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO, !on);
 150#endif
 151
 152        /* Hold the PHY in RESET for enough time till DIR is high */
 153        /* Refer: ISSUE1 */
 154        if (delay && on)
 155                udelay(delay);
 156}
 157#else
 158#define omap_ehci_phy_reset(on, delay)  do {} while (0)
 159#endif
 160
 161/* Reset is needed otherwise the kernel-driver will throw an error. */
 162int omap_ehci_hcd_stop(void)
 163{
 164        debug("Resetting OMAP EHCI\n");
 165        omap_ehci_phy_reset(1, 0);
 166
 167        if (omap_uhh_reset() < 0)
 168                return -1;
 169
 170        if (omap_ehci_tll_reset() < 0)
 171                return -1;
 172
 173        return 0;
 174}
 175
 176/*
 177 * Initialize the OMAP EHCI controller and PHY.
 178 * Based on "drivers/usb/host/ehci-omap.c" from Linux 3.1
 179 * See there for additional Copyrights.
 180 */
 181int omap_ehci_hcd_init(int index, struct omap_usbhs_board_data *usbhs_pdata,
 182                       struct ehci_hccr **hccr, struct ehci_hcor **hcor)
 183{
 184        int ret;
 185        unsigned int i, reg = 0, rev = 0;
 186
 187        debug("Initializing OMAP EHCI\n");
 188
 189        ret = board_usb_init(index, USB_INIT_HOST);
 190        if (ret < 0)
 191                return ret;
 192
 193        /* Put the PHY in RESET */
 194        omap_ehci_phy_reset(1, 10);
 195
 196        ret = omap_uhh_reset();
 197        if (ret < 0)
 198                return ret;
 199
 200        ret = omap_ehci_tll_reset();
 201        if (ret)
 202                return ret;
 203
 204        writel(OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
 205                OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
 206                OMAP_USBTLL_SYSCONFIG_CACTIVITY, &usbtll->sysc);
 207
 208        /* Put UHH in NoIdle/NoStandby mode */
 209        writel(OMAP_UHH_SYSCONFIG_VAL, &uhh->sysc);
 210
 211        /* setup ULPI bypass and burst configurations */
 212        clrsetbits_le32(&reg, OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN,
 213                (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN |
 214                OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN |
 215                OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN));
 216
 217        rev = readl(&uhh->rev);
 218        if (rev == OMAP_USBHS_REV1) {
 219                if (is_ehci_phy_mode(usbhs_pdata->port_mode[0]))
 220                        clrbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS);
 221                else
 222                        setbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS);
 223
 224                if (is_ehci_phy_mode(usbhs_pdata->port_mode[1]))
 225                        clrbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS);
 226                else
 227                        setbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS);
 228
 229                if (is_ehci_phy_mode(usbhs_pdata->port_mode[2]))
 230                        clrbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS);
 231                else
 232                        setbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS);
 233        } else if (rev == OMAP_USBHS_REV2) {
 234
 235                clrsetbits_le32(&reg, (OMAP_P1_MODE_CLEAR | OMAP_P2_MODE_CLEAR),
 236                                        OMAP4_UHH_HOSTCONFIG_APP_START_CLK);
 237
 238                /* Clear port mode fields for PHY mode */
 239
 240                if (is_ehci_hsic_mode(usbhs_pdata->port_mode[0]))
 241                        setbits_le32(&reg, OMAP_P1_MODE_HSIC);
 242
 243                if (is_ehci_hsic_mode(usbhs_pdata->port_mode[1]))
 244                        setbits_le32(&reg, OMAP_P2_MODE_HSIC);
 245
 246        } else if (rev == OMAP_USBHS_REV2_1) {
 247
 248                clrsetbits_le32(&reg,
 249                                (OMAP_P1_MODE_CLEAR |
 250                                 OMAP_P2_MODE_CLEAR |
 251                                 OMAP_P3_MODE_CLEAR),
 252                                OMAP4_UHH_HOSTCONFIG_APP_START_CLK);
 253
 254                /* Clear port mode fields for PHY mode */
 255
 256                if (is_ehci_hsic_mode(usbhs_pdata->port_mode[0]))
 257                        setbits_le32(&reg, OMAP_P1_MODE_HSIC);
 258
 259                if (is_ehci_hsic_mode(usbhs_pdata->port_mode[1]))
 260                        setbits_le32(&reg, OMAP_P2_MODE_HSIC);
 261
 262                if (is_ehci_hsic_mode(usbhs_pdata->port_mode[2]))
 263                        setbits_le32(&reg, OMAP_P3_MODE_HSIC);
 264        }
 265
 266        debug("OMAP UHH_REVISION 0x%x\n", rev);
 267        writel(reg, &uhh->hostconfig);
 268
 269        for (i = 0; i < OMAP_HS_USB_PORTS; i++)
 270                if (is_ehci_hsic_mode(usbhs_pdata->port_mode[i]))
 271                        omap_usbhs_hsic_init(i);
 272
 273        omap_ehci_phy_reset(0, 10);
 274
 275        /*
 276         * An undocumented "feature" in the OMAP3 EHCI controller,
 277         * causes suspended ports to be taken out of suspend when
 278         * the USBCMD.Run/Stop bit is cleared (for example when
 279         * we do ehci_bus_suspend).
 280         * This breaks suspend-resume if the root-hub is allowed
 281         * to suspend. Writing 1 to this undocumented register bit
 282         * disables this feature and restores normal behavior.
 283         */
 284        writel(EHCI_INSNREG04_DISABLE_UNSUSPEND, &ehci->insreg04);
 285
 286        for (i = 0; i < OMAP_HS_USB_PORTS; i++)
 287                if (is_ehci_phy_mode(usbhs_pdata->port_mode[i]))
 288                        omap_ehci_soft_phy_reset(i);
 289
 290        *hccr = (struct ehci_hccr *)(OMAP_EHCI_BASE);
 291        *hcor = (struct ehci_hcor *)(OMAP_EHCI_BASE + 0x10);
 292
 293        debug("OMAP EHCI init done\n");
 294        return 0;
 295}
 296