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