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