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