uboot/drivers/usb/musb-new/pic32.c
<<
>>
Prefs
   1/*
   2 * Microchip PIC32 MUSB "glue layer"
   3 *
   4 * Copyright (C) 2015, Microchip Technology Inc.
   5 *  Cristian Birsan <cristian.birsan@microchip.com>
   6 *  Purna Chandra Mandal <purna.mandal@microchip.com>
   7 *
   8 * SPDX-License-Identifier:     GPL-2.0+
   9 *
  10 * Based on the dsps "glue layer" code.
  11 */
  12
  13#include <common.h>
  14#include <linux/usb/musb.h>
  15#include "linux-compat.h"
  16#include "musb_core.h"
  17#include "musb_uboot.h"
  18
  19DECLARE_GLOBAL_DATA_PTR;
  20
  21#define PIC32_TX_EP_MASK        0x0f            /* EP0 + 7 Tx EPs */
  22#define PIC32_RX_EP_MASK        0x0e            /* 7 Rx EPs */
  23
  24#define MUSB_SOFTRST            0x7f
  25#define  MUSB_SOFTRST_NRST      BIT(0)
  26#define  MUSB_SOFTRST_NRSTX     BIT(1)
  27
  28#define USBCRCON                0
  29#define  USBCRCON_USBWKUPEN     BIT(0)  /* Enable Wakeup Interrupt */
  30#define  USBCRCON_USBRIE        BIT(1)  /* Enable Remote resume Interrupt */
  31#define  USBCRCON_USBIE         BIT(2)  /* Enable USB General interrupt */
  32#define  USBCRCON_SENDMONEN     BIT(3)  /* Enable Session End VBUS monitoring */
  33#define  USBCRCON_BSVALMONEN    BIT(4)  /* Enable B-Device VBUS monitoring */
  34#define  USBCRCON_ASVALMONEN    BIT(5)  /* Enable A-Device VBUS monitoring */
  35#define  USBCRCON_VBUSMONEN     BIT(6)  /* Enable VBUS monitoring */
  36#define  USBCRCON_PHYIDEN       BIT(7)  /* PHY ID monitoring enable */
  37#define  USBCRCON_USBIDVAL      BIT(8)  /* USB ID value */
  38#define  USBCRCON_USBIDOVEN     BIT(9)  /* USB ID override enable */
  39#define  USBCRCON_USBWK         BIT(24) /* USB Wakeup Status */
  40#define  USBCRCON_USBRF         BIT(25) /* USB Resume Status */
  41#define  USBCRCON_USBIF         BIT(26) /* USB General Interrupt Status */
  42
  43/* PIC32 controller data */
  44struct pic32_musb_data {
  45        struct musb_host_data mdata;
  46        struct device dev;
  47        void __iomem *musb_glue;
  48};
  49
  50#define to_pic32_musb_data(d)   \
  51        container_of(d, struct pic32_musb_data, dev)
  52
  53static void pic32_musb_disable(struct musb *musb)
  54{
  55        /* no way to shut the controller */
  56}
  57
  58static int pic32_musb_enable(struct musb *musb)
  59{
  60        /* soft reset by NRSTx */
  61        musb_writeb(musb->mregs, MUSB_SOFTRST, MUSB_SOFTRST_NRSTX);
  62        /* set mode */
  63        musb_platform_set_mode(musb, musb->board_mode);
  64
  65        return 0;
  66}
  67
  68static irqreturn_t pic32_interrupt(int irq, void *hci)
  69{
  70        struct musb  *musb = hci;
  71        irqreturn_t ret = IRQ_NONE;
  72        u32 epintr, usbintr;
  73
  74        /* ack usb core interrupts */
  75        musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
  76        if (musb->int_usb)
  77                musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
  78
  79        /* ack endpoint interrupts */
  80        musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX) & PIC32_RX_EP_MASK;
  81        if (musb->int_rx)
  82                musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
  83
  84        musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX) & PIC32_TX_EP_MASK;
  85        if (musb->int_tx)
  86                musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
  87
  88        /* drop spurious RX and TX if device is disconnected */
  89        if (musb->int_usb & MUSB_INTR_DISCONNECT) {
  90                musb->int_tx = 0;
  91                musb->int_rx = 0;
  92        }
  93
  94        if (musb->int_tx || musb->int_rx || musb->int_usb)
  95                ret = musb_interrupt(musb);
  96
  97        return ret;
  98}
  99
 100static int pic32_musb_set_mode(struct musb *musb, u8 mode)
 101{
 102        struct device *dev = musb->controller;
 103        struct pic32_musb_data *pdata = to_pic32_musb_data(dev);
 104
 105        switch (mode) {
 106        case MUSB_HOST:
 107                clrsetbits_le32(pdata->musb_glue + USBCRCON,
 108                                USBCRCON_USBIDVAL, USBCRCON_USBIDOVEN);
 109                break;
 110        case MUSB_PERIPHERAL:
 111                setbits_le32(pdata->musb_glue + USBCRCON,
 112                             USBCRCON_USBIDVAL | USBCRCON_USBIDOVEN);
 113                break;
 114        case MUSB_OTG:
 115                dev_err(dev, "support for OTG is unimplemented\n");
 116                break;
 117        default:
 118                dev_err(dev, "unsupported mode %d\n", mode);
 119                return -EINVAL;
 120        }
 121
 122        return 0;
 123}
 124
 125static int pic32_musb_init(struct musb *musb)
 126{
 127        struct pic32_musb_data *pdata = to_pic32_musb_data(musb->controller);
 128        u32 ctrl, hwvers;
 129        u8 power;
 130
 131        /* Returns zero if not clocked */
 132        hwvers = musb_read_hwvers(musb->mregs);
 133        if (!hwvers)
 134                return -ENODEV;
 135
 136        /* Reset the musb */
 137        power = musb_readb(musb->mregs, MUSB_POWER);
 138        power = power | MUSB_POWER_RESET;
 139        musb_writeb(musb->mregs, MUSB_POWER, power);
 140        mdelay(100);
 141
 142        /* Start the on-chip PHY and its PLL. */
 143        power = power & ~MUSB_POWER_RESET;
 144        musb_writeb(musb->mregs, MUSB_POWER, power);
 145
 146        musb->isr = pic32_interrupt;
 147
 148        ctrl =  USBCRCON_USBIF | USBCRCON_USBRF |
 149                USBCRCON_USBWK | USBCRCON_USBIDOVEN |
 150                USBCRCON_PHYIDEN | USBCRCON_USBIE |
 151                USBCRCON_USBRIE | USBCRCON_USBWKUPEN |
 152                USBCRCON_VBUSMONEN;
 153        writel(ctrl, pdata->musb_glue + USBCRCON);
 154
 155        return 0;
 156}
 157
 158/* PIC32 supports only 32bit read operation */
 159void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
 160{
 161        void __iomem *fifo = hw_ep->fifo;
 162        u32 val, rem = len % 4;
 163
 164        /* USB stack ensures dst is always 32bit aligned. */
 165        readsl(fifo, dst, len / 4);
 166        if (rem) {
 167                dst += len & ~0x03;
 168                val = musb_readl(fifo, 0);
 169                memcpy(dst, &val, rem);
 170        }
 171}
 172
 173const struct musb_platform_ops pic32_musb_ops = {
 174        .init           = pic32_musb_init,
 175        .set_mode       = pic32_musb_set_mode,
 176        .disable        = pic32_musb_disable,
 177        .enable         = pic32_musb_enable,
 178};
 179
 180/* PIC32 default FIFO config - fits in 8KB */
 181static struct musb_fifo_cfg pic32_musb_fifo_config[] = {
 182        { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
 183        { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
 184        { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
 185        { .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
 186        { .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, },
 187        { .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, },
 188        { .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, },
 189        { .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, },
 190        { .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, },
 191        { .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, },
 192        { .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 512, },
 193        { .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 512, },
 194        { .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 512, },
 195        { .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 512, },
 196};
 197
 198static struct musb_hdrc_config pic32_musb_config = {
 199        .fifo_cfg       = pic32_musb_fifo_config,
 200        .fifo_cfg_size  = ARRAY_SIZE(pic32_musb_fifo_config),
 201        .multipoint     = 1,
 202        .dyn_fifo       = 1,
 203        .num_eps        = 8,
 204        .ram_bits       = 11,
 205};
 206
 207/* PIC32 has one MUSB controller which can be host or gadget */
 208static struct musb_hdrc_platform_data pic32_musb_plat = {
 209        .mode           = MUSB_HOST,
 210        .config         = &pic32_musb_config,
 211        .power          = 250,          /* 500mA */
 212        .platform_ops   = &pic32_musb_ops,
 213};
 214
 215static int musb_usb_probe(struct udevice *dev)
 216{
 217        struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
 218        struct pic32_musb_data *pdata = dev_get_priv(dev);
 219        struct musb_host_data *mdata = &pdata->mdata;
 220        struct fdt_resource mc, glue;
 221        void *fdt = (void *)gd->fdt_blob;
 222        int node = dev->of_offset;
 223        void __iomem *mregs;
 224        int ret;
 225
 226        priv->desc_before_addr = true;
 227
 228        ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
 229                                     "mc", &mc);
 230        if (ret < 0) {
 231                printf("pic32-musb: resource \"mc\" not found\n");
 232                return ret;
 233        }
 234
 235        ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
 236                                     "control", &glue);
 237        if (ret < 0) {
 238                printf("pic32-musb: resource \"control\" not found\n");
 239                return ret;
 240        }
 241
 242        mregs = ioremap(mc.start, fdt_resource_size(&mc));
 243        pdata->musb_glue = ioremap(glue.start, fdt_resource_size(&glue));
 244
 245        /* init controller */
 246#ifdef CONFIG_USB_MUSB_HOST
 247        mdata->host = musb_init_controller(&pic32_musb_plat,
 248                                           &pdata->dev, mregs);
 249        if (!mdata->host)
 250                return -EIO;
 251
 252        ret = musb_lowlevel_init(mdata);
 253#else
 254        pic32_musb_plat.mode = MUSB_PERIPHERAL;
 255        ret = musb_register(&pic32_musb_plat, &pdata->dev, mregs);
 256#endif
 257        if (ret == 0)
 258                printf("PIC32 MUSB OTG\n");
 259
 260        return ret;
 261}
 262
 263static int musb_usb_remove(struct udevice *dev)
 264{
 265        struct pic32_musb_data *pdata = dev_get_priv(dev);
 266
 267        musb_stop(pdata->mdata.host);
 268
 269        return 0;
 270}
 271
 272static const struct udevice_id pic32_musb_ids[] = {
 273        { .compatible = "microchip,pic32mzda-usb" },
 274        { }
 275};
 276
 277U_BOOT_DRIVER(usb_musb) = {
 278        .name           = "pic32-musb",
 279        .id             = UCLASS_USB,
 280        .of_match       = pic32_musb_ids,
 281        .probe          = musb_usb_probe,
 282        .remove         = musb_usb_remove,
 283#ifdef CONFIG_USB_MUSB_HOST
 284        .ops            = &musb_usb_ops,
 285#endif
 286        .platdata_auto_alloc_size = sizeof(struct usb_platdata),
 287        .priv_auto_alloc_size = sizeof(struct pic32_musb_data),
 288};
 289