uboot/drivers/usb/musb-new/da8xx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Texas Instruments da8xx "glue layer"
   4 *
   5 * Copyright (c) 2019, by Texas Instruments
   6 *
   7 * Based on the DA8xx "glue layer" code.
   8 * Copyright (c) 2008-2019, MontaVista Software, Inc. <source@mvista.com>
   9 *
  10 * DT support
  11 * Copyright (c) 2016 Petr Kulhavy <petr@barix.com>
  12 * This file is part of the Inventra Controller Driver for Linux.
  13 *
  14 */
  15
  16#include <common.h>
  17#include <dm.h>
  18#include <dm/device-internal.h>
  19#include <dm/lists.h>
  20#include <asm/arch/hardware.h>
  21#include <asm/arch/da8xx-usb.h>
  22#include <linux/usb/otg.h>
  23#include <asm/omap_musb.h>
  24#include <generic-phy.h>
  25#include "linux-compat.h"
  26#include "musb_core.h"
  27#include "musb_uboot.h"
  28
  29/* USB 2.0 OTG module registers */
  30#define DA8XX_USB_REVISION_REG  0x00
  31#define DA8XX_USB_CTRL_REG      0x04
  32#define DA8XX_USB_STAT_REG      0x08
  33#define DA8XX_USB_EMULATION_REG 0x0c
  34#define DA8XX_USB_SRP_FIX_TIME_REG 0x18
  35#define DA8XX_USB_INTR_SRC_REG  0x20
  36#define DA8XX_USB_INTR_SRC_SET_REG 0x24
  37#define DA8XX_USB_INTR_SRC_CLEAR_REG 0x28
  38#define DA8XX_USB_INTR_MASK_REG 0x2c
  39#define DA8XX_USB_INTR_MASK_SET_REG 0x30
  40#define DA8XX_USB_INTR_MASK_CLEAR_REG 0x34
  41#define DA8XX_USB_INTR_SRC_MASKED_REG 0x38
  42#define DA8XX_USB_END_OF_INTR_REG 0x3c
  43#define DA8XX_USB_GENERIC_RNDIS_EP_SIZE_REG(n) (0x50 + (((n) - 1) << 2))
  44
  45/* Control register bits */
  46#define DA8XX_SOFT_RESET_MASK   1
  47
  48#define DA8XX_USB_TX_EP_MASK    0x1f            /* EP0 + 4 Tx EPs */
  49#define DA8XX_USB_RX_EP_MASK    0x1e            /* 4 Rx EPs */
  50
  51/* USB interrupt register bits */
  52#define DA8XX_INTR_USB_SHIFT    16
  53#define DA8XX_INTR_USB_MASK     (0x1ff << DA8XX_INTR_USB_SHIFT) /* 8 Mentor */
  54                                        /* interrupts and DRVVBUS interrupt */
  55#define DA8XX_INTR_DRVVBUS      0x100
  56#define DA8XX_INTR_RX_SHIFT     8
  57#define DA8XX_INTR_RX_MASK      (DA8XX_USB_RX_EP_MASK << DA8XX_INTR_RX_SHIFT)
  58#define DA8XX_INTR_TX_SHIFT     0
  59#define DA8XX_INTR_TX_MASK      (DA8XX_USB_TX_EP_MASK << DA8XX_INTR_TX_SHIFT)
  60
  61#define DA8XX_MENTOR_CORE_OFFSET 0x400
  62
  63static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
  64{
  65        struct musb             *musb = hci;
  66        void __iomem            *reg_base = musb->ctrl_base;
  67        unsigned long           flags;
  68        irqreturn_t             ret = IRQ_NONE;
  69        u32                     status;
  70
  71        spin_lock_irqsave(&musb->lock, flags);
  72
  73        /*
  74         * NOTE: DA8XX shadows the Mentor IRQs.  Don't manage them through
  75         * the Mentor registers (except for setup), use the TI ones and EOI.
  76         */
  77
  78        /* Acknowledge and handle non-CPPI interrupts */
  79        status = musb_readl(reg_base, DA8XX_USB_INTR_SRC_MASKED_REG);
  80        if (!status)
  81                goto eoi;
  82
  83        musb_writel(reg_base, DA8XX_USB_INTR_SRC_CLEAR_REG, status);
  84        dev_dbg(musb->controller, "USB IRQ %08x\n", status);
  85
  86        musb->int_rx = (status & DA8XX_INTR_RX_MASK) >> DA8XX_INTR_RX_SHIFT;
  87        musb->int_tx = (status & DA8XX_INTR_TX_MASK) >> DA8XX_INTR_TX_SHIFT;
  88        musb->int_usb = (status & DA8XX_INTR_USB_MASK) >> DA8XX_INTR_USB_SHIFT;
  89
  90        /*
  91         * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
  92         * DA8xx's missing ID change IRQ.  We need an ID change IRQ to
  93         * switch appropriately between halves of the OTG state machine.
  94         * Managing DEVCTL.Session per Mentor docs requires that we know its
  95         * value but DEVCTL.BDevice is invalid without DEVCTL.Session set.
  96         * Also, DRVVBUS pulses for SRP (but not at 5 V)...
  97         */
  98        if (status & (DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT)) {
  99                int drvvbus = musb_readl(reg_base, DA8XX_USB_STAT_REG);
 100                void __iomem *mregs = musb->mregs;
 101                u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
 102                int err;
 103
 104                err = musb->int_usb & MUSB_INTR_VBUSERROR;
 105                if (err) {
 106                        /*
 107                         * The Mentor core doesn't debounce VBUS as needed
 108                         * to cope with device connect current spikes. This
 109                         * means it's not uncommon for bus-powered devices
 110                         * to get VBUS errors during enumeration.
 111                         *
 112                         * This is a workaround, but newer RTL from Mentor
 113                         * seems to allow a better one: "re"-starting sessions
 114                         * without waiting for VBUS to stop registering in
 115                         * devctl.
 116                         */
 117                        musb->int_usb &= ~MUSB_INTR_VBUSERROR;
 118                        WARNING("VBUS error workaround (delay coming)\n");
 119                } else if (drvvbus) {
 120                        MUSB_HST_MODE(musb);
 121                        musb->port1_status |= USB_PORT_STAT_POWER;
 122                } else if (!(musb->int_usb & MUSB_INTR_BABBLE)) {
 123                        /*
 124                         * When babble condition happens, drvvbus interrupt
 125                         * is also generated. Ignore this drvvbus interrupt
 126                         * and let babble interrupt handler recovers the
 127                         * controller; otherwise, the host-mode flag is lost
 128                         * due to the MUSB_DEV_MODE() call below and babble
 129                         * recovery logic will not be called.
 130                         */
 131                        musb->is_active = 0;
 132                        MUSB_DEV_MODE(musb);
 133                        musb->port1_status &= ~USB_PORT_STAT_POWER;
 134                }
 135                ret = IRQ_HANDLED;
 136        }
 137
 138        if (musb->int_tx || musb->int_rx || musb->int_usb)
 139                ret |= musb_interrupt(musb);
 140eoi:
 141        /* EOI needs to be written for the IRQ to be re-asserted. */
 142        if (ret == IRQ_HANDLED || status)
 143                musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0);
 144
 145        spin_unlock_irqrestore(&musb->lock, flags);
 146
 147        return ret;
 148}
 149
 150static int da8xx_musb_init(struct musb *musb)
 151{
 152        u32  revision;
 153        void __iomem *reg_base = musb->ctrl_base;
 154
 155        int ret;
 156
 157        /* reset the controller */
 158        writel(0x1, &da8xx_usb_regs->control);
 159        udelay(50);
 160
 161        /* Returns zero if e.g. not clocked */
 162        revision = readl(&da8xx_usb_regs->revision);
 163        if (revision == 0)
 164                return -ENODEV;
 165
 166        /* Disable all interrupts */
 167        writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK |
 168                DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_set);
 169
 170        musb->mregs += DA8XX_MENTOR_CORE_OFFSET;
 171
 172        /* NOTE: IRQs are in mixed mode, not bypass to pure MUSB */
 173        debug("DA8xx OTG revision %08x, control %02x\n", revision,
 174              musb_readb(reg_base, DA8XX_USB_CTRL_REG));
 175
 176        musb->isr = da8xx_musb_interrupt;
 177        return 0;
 178}
 179
 180static int da8xx_musb_exit(struct musb *musb)
 181{
 182        /* flush any interrupts */
 183        writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK |
 184                DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_clr);
 185        writel(0, &da8xx_usb_regs->eoi);
 186
 187        return 0;
 188}
 189
 190/**
 191 * da8xx_musb_enable - enable interrupts
 192 */
 193static int da8xx_musb_enable(struct musb *musb)
 194{
 195        void __iomem *reg_base = musb->ctrl_base;
 196        u32 mask;
 197
 198        /* Workaround: setup IRQs through both register sets. */
 199        mask = ((musb->epmask & DA8XX_USB_TX_EP_MASK) << DA8XX_INTR_TX_SHIFT) |
 200               ((musb->epmask & DA8XX_USB_RX_EP_MASK) << DA8XX_INTR_RX_SHIFT) |
 201               DA8XX_INTR_USB_MASK;
 202        musb_writel(reg_base, DA8XX_USB_INTR_MASK_SET_REG, mask);
 203
 204        /* Force the DRVVBUS IRQ so we can start polling for ID change. */
 205        musb_writel(reg_base, DA8XX_USB_INTR_SRC_SET_REG,
 206                    DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT);
 207
 208        return 0;
 209}
 210
 211/**
 212 * da8xx_musb_disable - disable HDRC and flush interrupts
 213 */
 214static void da8xx_musb_disable(struct musb *musb)
 215{
 216        void __iomem *reg_base = musb->ctrl_base;
 217
 218        musb_writel(reg_base, DA8XX_USB_INTR_MASK_CLEAR_REG,
 219                    DA8XX_INTR_USB_MASK |
 220                    DA8XX_INTR_TX_MASK | DA8XX_INTR_RX_MASK);
 221        musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0);
 222}
 223
 224void da8xx_musb_reset(struct udevice *dev)
 225{
 226        void *reg_base = dev_read_addr_ptr(dev);
 227
 228        /* Reset the controller */
 229        musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK);
 230}
 231
 232void da8xx_musb_clear_irq(struct udevice *dev)
 233{
 234        /* flush any interrupts */
 235        writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK |
 236                DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_clr);
 237        writel(0, &da8xx_usb_regs->eoi);
 238}
 239
 240const struct musb_platform_ops da8xx_ops = {
 241        .init           = da8xx_musb_init,
 242        .exit           = da8xx_musb_exit,
 243        .enable         = da8xx_musb_enable,
 244        .disable        = da8xx_musb_disable,
 245};
 246
 247struct da8xx_musb_platdata {
 248        void *base;
 249        void *ctrl_mod_base;
 250        struct musb_hdrc_platform_data plat;
 251        struct musb_hdrc_config musb_config;
 252        struct omap_musb_board_data otg_board_data;
 253        struct phy phy;
 254};
 255
 256static int da8xx_musb_ofdata_to_platdata(struct udevice *dev)
 257{
 258        struct da8xx_musb_platdata *platdata = dev_get_platdata(dev);
 259        const void *fdt = gd->fdt_blob;
 260        int node = dev_of_offset(dev);
 261
 262        platdata->base = (void *)dev_read_addr_ptr(dev);
 263        platdata->musb_config.multipoint = 1;
 264        platdata->musb_config.dyn_fifo = 1;
 265        platdata->musb_config.num_eps = 5;
 266        platdata->musb_config.ram_bits = 10;
 267        platdata->plat.power = fdtdec_get_int(fdt, node, "power", 50);
 268        platdata->otg_board_data.interface_type = MUSB_INTERFACE_UTMI;
 269        platdata->plat.mode = MUSB_HOST;
 270        platdata->otg_board_data.dev = dev;
 271        platdata->plat.config = &platdata->musb_config;
 272        platdata->plat.platform_ops = &da8xx_ops;
 273        platdata->plat.board_data = &platdata->otg_board_data;
 274        platdata->otg_board_data.clear_irq = da8xx_musb_clear_irq;
 275        platdata->otg_board_data.reset = da8xx_musb_reset;
 276        return 0;
 277}
 278
 279static int da8xx_musb_probe(struct udevice *dev)
 280{
 281        struct musb_host_data *host = dev_get_priv(dev);
 282        struct da8xx_musb_platdata *platdata = dev_get_platdata(dev);
 283        struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
 284        struct omap_musb_board_data *otg_board_data;
 285        int ret;
 286        void *base = dev_read_addr_ptr(dev);
 287
 288        /* Get the phy info from the device tree */
 289        ret = generic_phy_get_by_name(dev, "usb-phy", &platdata->phy);
 290        if (ret)
 291                return ret;
 292
 293        /* Initialize the phy */
 294        ret = generic_phy_init(&platdata->phy);
 295        if (ret)
 296                return ret;
 297
 298        /* enable psc for usb2.0 */
 299        lpsc_on(33);
 300
 301        /* Enable phy */
 302        generic_phy_power_on(&platdata->phy);
 303
 304        priv->desc_before_addr = true;
 305        otg_board_data = &platdata->otg_board_data;
 306
 307        host->host = musb_init_controller(&platdata->plat,
 308                                          (struct device *)otg_board_data,
 309                                          platdata->base);
 310        if (!host->host) {
 311                ret = -ENODEV;
 312                goto shutdown; /* Shutdown what we started */
 313        }
 314
 315        ret = musb_lowlevel_init(host);
 316
 317        if (ret == 0)
 318                return 0;
 319shutdown:
 320        /* Turn off the phy if we fail */
 321        generic_phy_power_off(&platdata->phy);
 322        lpsc_disable(33);
 323        return ret;
 324}
 325
 326static int da8xx_musb_remove(struct udevice *dev)
 327{
 328        struct musb_host_data *host = dev_get_priv(dev);
 329
 330        musb_stop(host->host);
 331
 332        return 0;
 333}
 334
 335static const struct udevice_id da8xx_musb_ids[] = {
 336        { .compatible = "ti,da830-musb" },
 337        { }
 338};
 339
 340U_BOOT_DRIVER(da8xx_musb) = {
 341        .name   = "da8xx-musb",
 342        .id             = UCLASS_USB,
 343        .of_match = da8xx_musb_ids,
 344        .ofdata_to_platdata = da8xx_musb_ofdata_to_platdata,
 345        .probe = da8xx_musb_probe,
 346        .remove = da8xx_musb_remove,
 347        .ops = &musb_usb_ops,
 348        .platdata_auto_alloc_size = sizeof(struct da8xx_musb_platdata),
 349        .priv_auto_alloc_size = sizeof(struct musb_host_data),
 350};
 351