linux/drivers/usb/host/ehci-ps3.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  PS3 EHCI Host Controller driver
   4 *
   5 *  Copyright (C) 2006 Sony Computer Entertainment Inc.
   6 *  Copyright 2006 Sony Corp.
   7 */
   8
   9#include <asm/firmware.h>
  10#include <asm/ps3.h>
  11
  12static void ps3_ehci_setup_insnreg(struct ehci_hcd *ehci)
  13{
  14        /* PS3 HC internal setup register offsets. */
  15
  16        enum ps3_ehci_hc_insnreg {
  17                ps3_ehci_hc_insnreg01 = 0x084,
  18                ps3_ehci_hc_insnreg02 = 0x088,
  19                ps3_ehci_hc_insnreg03 = 0x08c,
  20        };
  21
  22        /* PS3 EHCI HC errata fix 316 - The PS3 EHCI HC will reset its
  23         * internal INSNREGXX setup regs back to the chip default values
  24         * on Host Controller Reset (CMD_RESET) or Light Host Controller
  25         * Reset (CMD_LRESET).  The work-around for this is for the HC
  26         * driver to re-initialise these regs when ever the HC is reset.
  27         */
  28
  29        /* Set burst transfer counts to 256 out, 32 in. */
  30
  31        writel_be(0x01000020, (void __iomem *)ehci->regs +
  32                ps3_ehci_hc_insnreg01);
  33
  34        /* Enable burst transfer counts. */
  35
  36        writel_be(0x00000001, (void __iomem *)ehci->regs +
  37                ps3_ehci_hc_insnreg03);
  38}
  39
  40static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
  41{
  42        int result;
  43        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
  44
  45        ehci->big_endian_mmio = 1;
  46        ehci->caps = hcd->regs;
  47
  48        result = ehci_setup(hcd);
  49        if (result)
  50                return result;
  51
  52        ps3_ehci_setup_insnreg(ehci);
  53
  54        return result;
  55}
  56
  57static const struct hc_driver ps3_ehci_hc_driver = {
  58        .description            = hcd_name,
  59        .product_desc           = "PS3 EHCI Host Controller",
  60        .hcd_priv_size          = sizeof(struct ehci_hcd),
  61        .irq                    = ehci_irq,
  62        .flags                  = HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
  63        .reset                  = ps3_ehci_hc_reset,
  64        .start                  = ehci_run,
  65        .stop                   = ehci_stop,
  66        .shutdown               = ehci_shutdown,
  67        .urb_enqueue            = ehci_urb_enqueue,
  68        .urb_dequeue            = ehci_urb_dequeue,
  69        .endpoint_disable       = ehci_endpoint_disable,
  70        .endpoint_reset         = ehci_endpoint_reset,
  71        .get_frame_number       = ehci_get_frame,
  72        .hub_status_data        = ehci_hub_status_data,
  73        .hub_control            = ehci_hub_control,
  74#if defined(CONFIG_PM)
  75        .bus_suspend            = ehci_bus_suspend,
  76        .bus_resume             = ehci_bus_resume,
  77#endif
  78        .relinquish_port        = ehci_relinquish_port,
  79        .port_handed_over       = ehci_port_handed_over,
  80
  81        .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
  82};
  83
  84static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
  85{
  86        int result;
  87        struct usb_hcd *hcd;
  88        unsigned int virq;
  89        static u64 dummy_mask;
  90
  91        if (usb_disabled()) {
  92                result = -ENODEV;
  93                goto fail_start;
  94        }
  95
  96        result = ps3_open_hv_device(dev);
  97
  98        if (result) {
  99                dev_dbg(&dev->core, "%s:%d: ps3_open_hv_device failed\n",
 100                        __func__, __LINE__);
 101                goto fail_open;
 102        }
 103
 104        result = ps3_dma_region_create(dev->d_region);
 105
 106        if (result) {
 107                dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: "
 108                        "(%d)\n", __func__, __LINE__, result);
 109                BUG_ON("check region type");
 110                goto fail_dma_region;
 111        }
 112
 113        result = ps3_mmio_region_create(dev->m_region);
 114
 115        if (result) {
 116                dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
 117                        __func__, __LINE__);
 118                result = -EPERM;
 119                goto fail_mmio_region;
 120        }
 121
 122        dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
 123                __LINE__, dev->m_region->lpar_addr);
 124
 125        result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
 126
 127        if (result) {
 128                dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
 129                        __func__, __LINE__, virq);
 130                result = -EPERM;
 131                goto fail_irq;
 132        }
 133
 134        dummy_mask = DMA_BIT_MASK(32);
 135        dev->core.dma_mask = &dummy_mask;
 136        dma_set_coherent_mask(&dev->core, dummy_mask);
 137
 138        hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev_name(&dev->core));
 139
 140        if (!hcd) {
 141                dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
 142                        __LINE__);
 143                result = -ENOMEM;
 144                goto fail_create_hcd;
 145        }
 146
 147        hcd->rsrc_start = dev->m_region->lpar_addr;
 148        hcd->rsrc_len = dev->m_region->len;
 149
 150        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name))
 151                dev_dbg(&dev->core, "%s:%d: request_mem_region failed\n",
 152                        __func__, __LINE__);
 153
 154        hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
 155
 156        if (!hcd->regs) {
 157                dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
 158                        __LINE__);
 159                result = -EPERM;
 160                goto fail_ioremap;
 161        }
 162
 163        dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
 164                (unsigned long)hcd->rsrc_start);
 165        dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len   %lxh\n", __func__, __LINE__,
 166                (unsigned long)hcd->rsrc_len);
 167        dev_dbg(&dev->core, "%s:%d: hcd->regs       %lxh\n", __func__, __LINE__,
 168                (unsigned long)hcd->regs);
 169        dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
 170                (unsigned long)virq);
 171
 172        ps3_system_bus_set_drvdata(dev, hcd);
 173
 174        result = usb_add_hcd(hcd, virq, 0);
 175
 176        if (result) {
 177                dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
 178                        __func__, __LINE__, result);
 179                goto fail_add_hcd;
 180        }
 181
 182        device_wakeup_enable(hcd->self.controller);
 183        return result;
 184
 185fail_add_hcd:
 186        iounmap(hcd->regs);
 187fail_ioremap:
 188        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 189        usb_put_hcd(hcd);
 190fail_create_hcd:
 191        ps3_io_irq_destroy(virq);
 192fail_irq:
 193        ps3_free_mmio_region(dev->m_region);
 194fail_mmio_region:
 195        ps3_dma_region_free(dev->d_region);
 196fail_dma_region:
 197        ps3_close_hv_device(dev);
 198fail_open:
 199fail_start:
 200        return result;
 201}
 202
 203static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
 204{
 205        unsigned int tmp;
 206        struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
 207
 208        BUG_ON(!hcd);
 209
 210        dev_dbg(&dev->core, "%s:%d: regs %p\n", __func__, __LINE__, hcd->regs);
 211        dev_dbg(&dev->core, "%s:%d: irq %u\n", __func__, __LINE__, hcd->irq);
 212
 213        tmp = hcd->irq;
 214
 215        usb_remove_hcd(hcd);
 216
 217        ps3_system_bus_set_drvdata(dev, NULL);
 218
 219        BUG_ON(!hcd->regs);
 220        iounmap(hcd->regs);
 221
 222        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 223        usb_put_hcd(hcd);
 224
 225        ps3_io_irq_destroy(tmp);
 226        ps3_free_mmio_region(dev->m_region);
 227
 228        ps3_dma_region_free(dev->d_region);
 229        ps3_close_hv_device(dev);
 230
 231        return 0;
 232}
 233
 234static int __init ps3_ehci_driver_register(struct ps3_system_bus_driver *drv)
 235{
 236        return firmware_has_feature(FW_FEATURE_PS3_LV1)
 237                ? ps3_system_bus_driver_register(drv)
 238                : 0;
 239}
 240
 241static void ps3_ehci_driver_unregister(struct ps3_system_bus_driver *drv)
 242{
 243        if (firmware_has_feature(FW_FEATURE_PS3_LV1))
 244                ps3_system_bus_driver_unregister(drv);
 245}
 246
 247MODULE_ALIAS(PS3_MODULE_ALIAS_EHCI);
 248
 249static struct ps3_system_bus_driver ps3_ehci_driver = {
 250        .core.name = "ps3-ehci-driver",
 251        .core.owner = THIS_MODULE,
 252        .match_id = PS3_MATCH_ID_EHCI,
 253        .probe = ps3_ehci_probe,
 254        .remove = ps3_ehci_remove,
 255        .shutdown = ps3_ehci_remove,
 256};
 257