uboot/drivers/usb/host/xhci-dwc3.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2015 Freescale Semiconductor, Inc.
   4 *
   5 * DWC3 controller driver
   6 *
   7 * Author: Ramneek Mehresh<ramneek.mehresh@freescale.com>
   8 */
   9
  10#include <clk.h>
  11#include <common.h>
  12#include <dm.h>
  13#include <generic-phy.h>
  14#include <log.h>
  15#include <reset.h>
  16#include <usb.h>
  17#include <dwc3-uboot.h>
  18#include <linux/delay.h>
  19
  20#include <usb/xhci.h>
  21#include <asm/io.h>
  22#include <linux/usb/dwc3.h>
  23#include <linux/usb/otg.h>
  24
  25struct xhci_dwc3_plat {
  26        struct clk_bulk clks;
  27        struct phy_bulk phys;
  28        struct reset_ctl_bulk resets;
  29};
  30
  31void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
  32{
  33        clrsetbits_le32(&dwc3_reg->g_ctl,
  34                        DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG),
  35                        DWC3_GCTL_PRTCAPDIR(mode));
  36}
  37
  38static void dwc3_phy_reset(struct dwc3 *dwc3_reg)
  39{
  40        /* Assert USB3 PHY reset */
  41        setbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST);
  42
  43        /* Assert USB2 PHY reset */
  44        setbits_le32(&dwc3_reg->g_usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST);
  45
  46        mdelay(100);
  47
  48        /* Clear USB3 PHY reset */
  49        clrbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST);
  50
  51        /* Clear USB2 PHY reset */
  52        clrbits_le32(&dwc3_reg->g_usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST);
  53}
  54
  55void dwc3_core_soft_reset(struct dwc3 *dwc3_reg)
  56{
  57        /* Before Resetting PHY, put Core in Reset */
  58        setbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET);
  59
  60        /* reset USB3 phy - if required */
  61        dwc3_phy_reset(dwc3_reg);
  62
  63        mdelay(100);
  64
  65        /* After PHYs are stable we can take Core out of reset state */
  66        clrbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET);
  67}
  68
  69int dwc3_core_init(struct dwc3 *dwc3_reg)
  70{
  71        u32 reg;
  72        u32 revision;
  73        unsigned int dwc3_hwparams1;
  74
  75        revision = readl(&dwc3_reg->g_snpsid);
  76        /* This should read as U3 followed by revision number */
  77        if ((revision & DWC3_GSNPSID_MASK) != 0x55330000 &&
  78            (revision & DWC3_GSNPSID_MASK) != 0x33310000) {
  79                puts("this is not a DesignWare USB3 DRD Core\n");
  80                return -1;
  81        }
  82
  83        dwc3_core_soft_reset(dwc3_reg);
  84
  85        dwc3_hwparams1 = readl(&dwc3_reg->g_hwparams1);
  86
  87        reg = readl(&dwc3_reg->g_ctl);
  88        reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
  89        reg &= ~DWC3_GCTL_DISSCRAMBLE;
  90        switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc3_hwparams1)) {
  91        case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
  92                reg &= ~DWC3_GCTL_DSBLCLKGTNG;
  93                break;
  94        default:
  95                debug("No power optimization available\n");
  96        }
  97
  98        /*
  99         * WORKAROUND: DWC3 revisions <1.90a have a bug
 100         * where the device can fail to connect at SuperSpeed
 101         * and falls back to high-speed mode which causes
 102         * the device to enter a Connect/Disconnect loop
 103         */
 104        if ((revision & DWC3_REVISION_MASK) < 0x190a)
 105                reg |= DWC3_GCTL_U2RSTECN;
 106
 107        writel(reg, &dwc3_reg->g_ctl);
 108
 109        return 0;
 110}
 111
 112void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val)
 113{
 114        setbits_le32(&dwc3_reg->g_fladj, GFLADJ_30MHZ_REG_SEL |
 115                        GFLADJ_30MHZ(val));
 116}
 117
 118#if CONFIG_IS_ENABLED(DM_USB)
 119static int xhci_dwc3_reset_init(struct udevice *dev,
 120                                struct xhci_dwc3_plat *plat)
 121{
 122        int ret;
 123
 124        ret = reset_get_bulk(dev, &plat->resets);
 125        if (ret == -ENOTSUPP || ret == -ENOENT)
 126                return 0;
 127        else if (ret)
 128                return ret;
 129
 130        ret = reset_deassert_bulk(&plat->resets);
 131        if (ret) {
 132                reset_release_bulk(&plat->resets);
 133                return ret;
 134        }
 135
 136        return 0;
 137}
 138
 139static int xhci_dwc3_clk_init(struct udevice *dev,
 140                              struct xhci_dwc3_plat *plat)
 141{
 142        int ret;
 143
 144        ret = clk_get_bulk(dev, &plat->clks);
 145        if (ret == -ENOSYS || ret == -ENOENT)
 146                return 0;
 147        if (ret)
 148                return ret;
 149
 150        ret = clk_enable_bulk(&plat->clks);
 151        if (ret) {
 152                clk_release_bulk(&plat->clks);
 153                return ret;
 154        }
 155
 156        return 0;
 157}
 158
 159static int xhci_dwc3_probe(struct udevice *dev)
 160{
 161        struct xhci_hcor *hcor;
 162        struct xhci_hccr *hccr;
 163        struct dwc3 *dwc3_reg;
 164        enum usb_dr_mode dr_mode;
 165        struct xhci_dwc3_plat *plat = dev_get_plat(dev);
 166        const char *phy;
 167        u32 reg;
 168        int ret;
 169
 170        ret = xhci_dwc3_reset_init(dev, plat);
 171        if (ret)
 172                return ret;
 173
 174        ret = xhci_dwc3_clk_init(dev, plat);
 175        if (ret)
 176                return ret;
 177
 178        hccr = (struct xhci_hccr *)((uintptr_t)dev_remap_addr(dev));
 179        hcor = (struct xhci_hcor *)((uintptr_t)hccr +
 180                        HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
 181
 182        ret = dwc3_setup_phy(dev, &plat->phys);
 183        if (ret && (ret != -ENOTSUPP))
 184                return ret;
 185
 186        dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET);
 187
 188        dwc3_core_init(dwc3_reg);
 189
 190        /* Set dwc3 usb2 phy config */
 191        reg = readl(&dwc3_reg->g_usb2phycfg[0]);
 192
 193        phy = dev_read_string(dev, "phy_type");
 194        if (phy && strcmp(phy, "utmi_wide") == 0) {
 195                reg |= DWC3_GUSB2PHYCFG_PHYIF;
 196                reg &= ~DWC3_GUSB2PHYCFG_USBTRDTIM_MASK;
 197                reg |= DWC3_GUSB2PHYCFG_USBTRDTIM_16BIT;
 198        }
 199
 200        if (dev_read_bool(dev, "snps,dis_enblslpm-quirk"))
 201                reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
 202
 203        if (dev_read_bool(dev, "snps,dis-u2-freeclk-exists-quirk"))
 204                reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
 205
 206        if (dev_read_bool(dev, "snps,dis_u2_susphy_quirk"))
 207                reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
 208
 209        writel(reg, &dwc3_reg->g_usb2phycfg[0]);
 210
 211        dr_mode = usb_get_dr_mode(dev_ofnode(dev));
 212        if (dr_mode == USB_DR_MODE_UNKNOWN)
 213                /* by default set dual role mode to HOST */
 214                dr_mode = USB_DR_MODE_HOST;
 215
 216        dwc3_set_mode(dwc3_reg, dr_mode);
 217
 218        return xhci_register(dev, hccr, hcor);
 219}
 220
 221static int xhci_dwc3_remove(struct udevice *dev)
 222{
 223        struct xhci_dwc3_plat *plat = dev_get_plat(dev);
 224
 225        dwc3_shutdown_phy(dev, &plat->phys);
 226
 227        clk_release_bulk(&plat->clks);
 228
 229        reset_release_bulk(&plat->resets);
 230
 231        return xhci_deregister(dev);
 232}
 233
 234static const struct udevice_id xhci_dwc3_ids[] = {
 235        { .compatible = "snps,dwc3" },
 236        { }
 237};
 238
 239U_BOOT_DRIVER(xhci_dwc3) = {
 240        .name = "xhci-dwc3",
 241        .id = UCLASS_USB,
 242        .of_match = xhci_dwc3_ids,
 243        .probe = xhci_dwc3_probe,
 244        .remove = xhci_dwc3_remove,
 245        .ops = &xhci_usb_ops,
 246        .priv_auto      = sizeof(struct xhci_ctrl),
 247        .plat_auto      = sizeof(struct xhci_dwc3_plat),
 248        .flags = DM_FLAG_ALLOC_PRIV_DMA,
 249};
 250#endif
 251