linux/drivers/usb/host/bcma-hcd.c
<<
>>
Prefs
   1/*
   2 * Broadcom specific Advanced Microcontroller Bus
   3 * Broadcom USB-core driver (BCMA bus glue)
   4 *
   5 * Copyright 2011-2015 Hauke Mehrtens <hauke@hauke-m.de>
   6 * Copyright 2015 Felix Fietkau <nbd@openwrt.org>
   7 *
   8 * Based on ssb-ohci driver
   9 * Copyright 2007 Michael Buesch <m@bues.ch>
  10 *
  11 * Derived from the OHCI-PCI driver
  12 * Copyright 1999 Roman Weissgaerber
  13 * Copyright 2000-2002 David Brownell
  14 * Copyright 1999 Linus Torvalds
  15 * Copyright 1999 Gregory P. Smith
  16 *
  17 * Derived from the USBcore related parts of Broadcom-SB
  18 * Copyright 2005-2011 Broadcom Corporation
  19 *
  20 * Licensed under the GNU/GPL. See COPYING for details.
  21 */
  22#include <linux/bcma/bcma.h>
  23#include <linux/delay.h>
  24#include <linux/gpio/consumer.h>
  25#include <linux/platform_device.h>
  26#include <linux/module.h>
  27#include <linux/slab.h>
  28#include <linux/of.h>
  29#include <linux/of_gpio.h>
  30#include <linux/of_platform.h>
  31#include <linux/usb/ehci_pdriver.h>
  32#include <linux/usb/ohci_pdriver.h>
  33
  34MODULE_AUTHOR("Hauke Mehrtens");
  35MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
  36MODULE_LICENSE("GPL");
  37
  38/* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */
  39#define USB_BCMA_CLKCTLST_USB_CLK_REQ                   0x00000100
  40
  41struct bcma_hcd_device {
  42        struct bcma_device *core;
  43        struct platform_device *ehci_dev;
  44        struct platform_device *ohci_dev;
  45        struct gpio_desc *gpio_desc;
  46};
  47
  48/* Wait for bitmask in a register to get set or cleared.
  49 * timeout is in units of ten-microseconds.
  50 */
  51static int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask,
  52                          int timeout)
  53{
  54        int i;
  55        u32 val;
  56
  57        for (i = 0; i < timeout; i++) {
  58                val = bcma_read32(dev, reg);
  59                if ((val & bitmask) == bitmask)
  60                        return 0;
  61                udelay(10);
  62        }
  63
  64        return -ETIMEDOUT;
  65}
  66
  67static void bcma_hcd_4716wa(struct bcma_device *dev)
  68{
  69#ifdef CONFIG_BCMA_DRIVER_MIPS
  70        /* Work around for 4716 failures. */
  71        if (dev->bus->chipinfo.id == 0x4716) {
  72                u32 tmp;
  73
  74                tmp = bcma_cpu_clock(&dev->bus->drv_mips);
  75                if (tmp >= 480000000)
  76                        tmp = 0x1846b; /* set CDR to 0x11(fast) */
  77                else if (tmp == 453000000)
  78                        tmp = 0x1046b; /* set CDR to 0x10(slow) */
  79                else
  80                        tmp = 0;
  81
  82                /* Change Shim mdio control reg to fix host not acking at
  83                 * high frequencies
  84                 */
  85                if (tmp) {
  86                        bcma_write32(dev, 0x524, 0x1); /* write sel to enable */
  87                        udelay(500);
  88
  89                        bcma_write32(dev, 0x524, tmp);
  90                        udelay(500);
  91                        bcma_write32(dev, 0x524, 0x4ab);
  92                        udelay(500);
  93                        bcma_read32(dev, 0x528);
  94                        bcma_write32(dev, 0x528, 0x80000000);
  95                }
  96        }
  97#endif /* CONFIG_BCMA_DRIVER_MIPS */
  98}
  99
 100/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
 101static void bcma_hcd_init_chip_mips(struct bcma_device *dev)
 102{
 103        u32 tmp;
 104
 105        /*
 106         * USB 2.0 special considerations:
 107         *
 108         * 1. Since the core supports both OHCI and EHCI functions, it must
 109         *    only be reset once.
 110         *
 111         * 2. In addition to the standard SI reset sequence, the Host Control
 112         *    Register must be programmed to bring the USB core and various
 113         *    phy components out of reset.
 114         */
 115        if (!bcma_core_is_enabled(dev)) {
 116                bcma_core_enable(dev, 0);
 117                mdelay(10);
 118                if (dev->id.rev >= 5) {
 119                        /* Enable Misc PLL */
 120                        tmp = bcma_read32(dev, 0x1e0);
 121                        tmp |= 0x100;
 122                        bcma_write32(dev, 0x1e0, tmp);
 123                        if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100))
 124                                printk(KERN_EMERG "Failed to enable misc PPL!\n");
 125
 126                        /* Take out of resets */
 127                        bcma_write32(dev, 0x200, 0x4ff);
 128                        udelay(25);
 129                        bcma_write32(dev, 0x200, 0x6ff);
 130                        udelay(25);
 131
 132                        /* Make sure digital and AFE are locked in USB PHY */
 133                        bcma_write32(dev, 0x524, 0x6b);
 134                        udelay(50);
 135                        tmp = bcma_read32(dev, 0x524);
 136                        udelay(50);
 137                        bcma_write32(dev, 0x524, 0xab);
 138                        udelay(50);
 139                        tmp = bcma_read32(dev, 0x524);
 140                        udelay(50);
 141                        bcma_write32(dev, 0x524, 0x2b);
 142                        udelay(50);
 143                        tmp = bcma_read32(dev, 0x524);
 144                        udelay(50);
 145                        bcma_write32(dev, 0x524, 0x10ab);
 146                        udelay(50);
 147                        tmp = bcma_read32(dev, 0x524);
 148
 149                        if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) {
 150                                tmp = bcma_read32(dev, 0x528);
 151                                printk(KERN_EMERG
 152                                       "USB20H mdio_rddata 0x%08x\n", tmp);
 153                        }
 154                        bcma_write32(dev, 0x528, 0x80000000);
 155                        tmp = bcma_read32(dev, 0x314);
 156                        udelay(265);
 157                        bcma_write32(dev, 0x200, 0x7ff);
 158                        udelay(10);
 159
 160                        /* Take USB and HSIC out of non-driving modes */
 161                        bcma_write32(dev, 0x510, 0);
 162                } else {
 163                        bcma_write32(dev, 0x200, 0x7ff);
 164
 165                        udelay(1);
 166                }
 167
 168                bcma_hcd_4716wa(dev);
 169        }
 170}
 171
 172/**
 173 * bcma_hcd_usb20_old_arm_init - Initialize old USB 2.0 controller on ARM
 174 *
 175 * Old USB 2.0 core is identified as BCMA_CORE_USB20_HOST and was introduced
 176 * long before Northstar devices. It seems some cheaper chipsets like BCM53573
 177 * still use it.
 178 * Initialization of this old core differs between MIPS and ARM.
 179 */
 180static int bcma_hcd_usb20_old_arm_init(struct bcma_hcd_device *usb_dev)
 181{
 182        struct bcma_device *core = usb_dev->core;
 183        struct device *dev = &core->dev;
 184        struct bcma_device *pmu_core;
 185
 186        usleep_range(10000, 20000);
 187        if (core->id.rev < 5)
 188                return 0;
 189
 190        pmu_core = bcma_find_core(core->bus, BCMA_CORE_PMU);
 191        if (!pmu_core) {
 192                dev_err(dev, "Could not find PMU core\n");
 193                return -ENOENT;
 194        }
 195
 196        /* Take USB core out of reset */
 197        bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK | BCMA_IOCTL_FGC);
 198        usleep_range(100, 200);
 199        bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
 200        usleep_range(100, 200);
 201        bcma_awrite32(core, BCMA_RESET_CTL, 0);
 202        usleep_range(100, 200);
 203        bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK);
 204        usleep_range(100, 200);
 205
 206        /* Enable Misc PLL */
 207        bcma_write32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT |
 208                                          BCMA_CLKCTLST_HQCLKREQ |
 209                                          USB_BCMA_CLKCTLST_USB_CLK_REQ);
 210        usleep_range(100, 200);
 211
 212        bcma_write32(core, 0x510, 0xc7f85000);
 213        bcma_write32(core, 0x510, 0xc7f85003);
 214        usleep_range(300, 600);
 215
 216        /* Program USB PHY PLL parameters */
 217        bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x6);
 218        bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x005360c1);
 219        usleep_range(100, 200);
 220        bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x7);
 221        bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x0);
 222        usleep_range(100, 200);
 223        bcma_set32(pmu_core, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
 224        usleep_range(100, 200);
 225
 226        bcma_write32(core, 0x510, 0x7f8d007);
 227        udelay(1000);
 228
 229        /* Take controller out of reset */
 230        bcma_write32(core, 0x200, 0x4ff);
 231        usleep_range(25, 50);
 232        bcma_write32(core, 0x200, 0x6ff);
 233        usleep_range(25, 50);
 234        bcma_write32(core, 0x200, 0x7ff);
 235        usleep_range(25, 50);
 236
 237        of_platform_default_populate(dev->of_node, NULL, dev);
 238
 239        return 0;
 240}
 241
 242static void bcma_hcd_usb20_ns_init_hc(struct bcma_device *dev)
 243{
 244        u32 val;
 245
 246        /* Set packet buffer OUT threshold */
 247        val = bcma_read32(dev, 0x94);
 248        val &= 0xffff;
 249        val |= 0x80 << 16;
 250        bcma_write32(dev, 0x94, val);
 251
 252        /* Enable break memory transfer */
 253        val = bcma_read32(dev, 0x9c);
 254        val |= 1;
 255        bcma_write32(dev, 0x9c, val);
 256
 257        /*
 258         * Broadcom initializes PHY and then waits to ensure HC is ready to be
 259         * configured. In our case the order is reversed. We just initialized
 260         * controller and we let HCD initialize PHY, so let's wait (sleep) now.
 261         */
 262        usleep_range(1000, 2000);
 263}
 264
 265/**
 266 * bcma_hcd_usb20_ns_init - Initialize Northstar USB 2.0 controller
 267 */
 268static int bcma_hcd_usb20_ns_init(struct bcma_hcd_device *bcma_hcd)
 269{
 270        struct bcma_device *core = bcma_hcd->core;
 271        struct bcma_chipinfo *ci = &core->bus->chipinfo;
 272        struct device *dev = &core->dev;
 273
 274        bcma_core_enable(core, 0);
 275
 276        if (ci->id == BCMA_CHIP_ID_BCM4707 ||
 277            ci->id == BCMA_CHIP_ID_BCM53018)
 278                bcma_hcd_usb20_ns_init_hc(core);
 279
 280        of_platform_default_populate(dev->of_node, NULL, dev);
 281
 282        return 0;
 283}
 284
 285static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val)
 286{
 287        struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
 288
 289        if (IS_ERR_OR_NULL(usb_dev->gpio_desc))
 290                return;
 291
 292        gpiod_set_value(usb_dev->gpio_desc, val);
 293}
 294
 295static const struct usb_ehci_pdata ehci_pdata = {
 296};
 297
 298static const struct usb_ohci_pdata ohci_pdata = {
 299};
 300
 301static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev,
 302                                                    const char *name, u32 addr,
 303                                                    const void *data,
 304                                                    size_t size)
 305{
 306        struct platform_device *hci_dev;
 307        struct resource hci_res[2];
 308        int ret;
 309
 310        memset(hci_res, 0, sizeof(hci_res));
 311
 312        hci_res[0].start = addr;
 313        hci_res[0].end = hci_res[0].start + 0x1000 - 1;
 314        hci_res[0].flags = IORESOURCE_MEM;
 315
 316        hci_res[1].start = dev->irq;
 317        hci_res[1].flags = IORESOURCE_IRQ;
 318
 319        hci_dev = platform_device_alloc(name, 0);
 320        if (!hci_dev)
 321                return ERR_PTR(-ENOMEM);
 322
 323        hci_dev->dev.parent = &dev->dev;
 324        hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
 325
 326        ret = platform_device_add_resources(hci_dev, hci_res,
 327                                            ARRAY_SIZE(hci_res));
 328        if (ret)
 329                goto err_alloc;
 330        if (data)
 331                ret = platform_device_add_data(hci_dev, data, size);
 332        if (ret)
 333                goto err_alloc;
 334        ret = platform_device_add(hci_dev);
 335        if (ret)
 336                goto err_alloc;
 337
 338        return hci_dev;
 339
 340err_alloc:
 341        platform_device_put(hci_dev);
 342        return ERR_PTR(ret);
 343}
 344
 345static int bcma_hcd_usb20_init(struct bcma_hcd_device *usb_dev)
 346{
 347        struct bcma_device *dev = usb_dev->core;
 348        struct bcma_chipinfo *chipinfo = &dev->bus->chipinfo;
 349        u32 ohci_addr;
 350        int err;
 351
 352        if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32)))
 353                return -EOPNOTSUPP;
 354
 355        bcma_hcd_init_chip_mips(dev);
 356
 357        /* In AI chips EHCI is addrspace 0, OHCI is 1 */
 358        ohci_addr = dev->addr_s[0];
 359        if ((chipinfo->id == BCMA_CHIP_ID_BCM5357 ||
 360             chipinfo->id == BCMA_CHIP_ID_BCM4749)
 361            && chipinfo->rev == 0)
 362                ohci_addr = 0x18009000;
 363
 364        usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, "ohci-platform",
 365                                                 ohci_addr, &ohci_pdata,
 366                                                 sizeof(ohci_pdata));
 367        if (IS_ERR(usb_dev->ohci_dev))
 368                return PTR_ERR(usb_dev->ohci_dev);
 369
 370        usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, "ehci-platform",
 371                                                 dev->addr, &ehci_pdata,
 372                                                 sizeof(ehci_pdata));
 373        if (IS_ERR(usb_dev->ehci_dev)) {
 374                err = PTR_ERR(usb_dev->ehci_dev);
 375                goto err_unregister_ohci_dev;
 376        }
 377
 378        return 0;
 379
 380err_unregister_ohci_dev:
 381        platform_device_unregister(usb_dev->ohci_dev);
 382        return err;
 383}
 384
 385static int bcma_hcd_usb30_init(struct bcma_hcd_device *bcma_hcd)
 386{
 387        struct bcma_device *core = bcma_hcd->core;
 388        struct device *dev = &core->dev;
 389
 390        bcma_core_enable(core, 0);
 391
 392        of_platform_default_populate(dev->of_node, NULL, dev);
 393
 394        return 0;
 395}
 396
 397static int bcma_hcd_probe(struct bcma_device *core)
 398{
 399        int err;
 400        struct bcma_hcd_device *usb_dev;
 401
 402        /* TODO: Probably need checks here; is the core connected? */
 403
 404        usb_dev = devm_kzalloc(&core->dev, sizeof(struct bcma_hcd_device),
 405                               GFP_KERNEL);
 406        if (!usb_dev)
 407                return -ENOMEM;
 408        usb_dev->core = core;
 409
 410        if (core->dev.of_node)
 411                usb_dev->gpio_desc = devm_gpiod_get(&core->dev, "vcc",
 412                                                    GPIOD_OUT_HIGH);
 413
 414        switch (core->id.id) {
 415        case BCMA_CORE_USB20_HOST:
 416                if (IS_ENABLED(CONFIG_ARM))
 417                        err = bcma_hcd_usb20_old_arm_init(usb_dev);
 418                else if (IS_ENABLED(CONFIG_MIPS))
 419                        err = bcma_hcd_usb20_init(usb_dev);
 420                else
 421                        err = -ENOTSUPP;
 422                break;
 423        case BCMA_CORE_NS_USB20:
 424                err = bcma_hcd_usb20_ns_init(usb_dev);
 425                break;
 426        case BCMA_CORE_NS_USB30:
 427                err = bcma_hcd_usb30_init(usb_dev);
 428                break;
 429        default:
 430                return -ENODEV;
 431        }
 432        if (err)
 433                return err;
 434
 435        bcma_set_drvdata(core, usb_dev);
 436        return 0;
 437}
 438
 439static void bcma_hcd_remove(struct bcma_device *dev)
 440{
 441        struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
 442        struct platform_device *ohci_dev = usb_dev->ohci_dev;
 443        struct platform_device *ehci_dev = usb_dev->ehci_dev;
 444
 445        if (ohci_dev)
 446                platform_device_unregister(ohci_dev);
 447        if (ehci_dev)
 448                platform_device_unregister(ehci_dev);
 449
 450        bcma_core_disable(dev, 0);
 451}
 452
 453static void bcma_hcd_shutdown(struct bcma_device *dev)
 454{
 455        bcma_hci_platform_power_gpio(dev, false);
 456        bcma_core_disable(dev, 0);
 457}
 458
 459#ifdef CONFIG_PM
 460
 461static int bcma_hcd_suspend(struct bcma_device *dev)
 462{
 463        bcma_hci_platform_power_gpio(dev, false);
 464        bcma_core_disable(dev, 0);
 465
 466        return 0;
 467}
 468
 469static int bcma_hcd_resume(struct bcma_device *dev)
 470{
 471        bcma_hci_platform_power_gpio(dev, true);
 472        bcma_core_enable(dev, 0);
 473
 474        return 0;
 475}
 476
 477#else /* !CONFIG_PM */
 478#define bcma_hcd_suspend        NULL
 479#define bcma_hcd_resume NULL
 480#endif /* CONFIG_PM */
 481
 482static const struct bcma_device_id bcma_hcd_table[] = {
 483        BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
 484        BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB20, BCMA_ANY_REV, BCMA_ANY_CLASS),
 485        BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB30, BCMA_ANY_REV, BCMA_ANY_CLASS),
 486        {},
 487};
 488MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
 489
 490static struct bcma_driver bcma_hcd_driver = {
 491        .name           = KBUILD_MODNAME,
 492        .id_table       = bcma_hcd_table,
 493        .probe          = bcma_hcd_probe,
 494        .remove         = bcma_hcd_remove,
 495        .shutdown       = bcma_hcd_shutdown,
 496        .suspend        = bcma_hcd_suspend,
 497        .resume         = bcma_hcd_resume,
 498};
 499
 500static int __init bcma_hcd_init(void)
 501{
 502        return bcma_driver_register(&bcma_hcd_driver);
 503}
 504module_init(bcma_hcd_init);
 505
 506static void __exit bcma_hcd_exit(void)
 507{
 508        bcma_driver_unregister(&bcma_hcd_driver);
 509}
 510module_exit(bcma_hcd_exit);
 511