linux/drivers/usb/host/ohci-ps3.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  PS3 OHCI 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 int ps3_ohci_hc_reset(struct usb_hcd *hcd)
  13{
  14        struct ohci_hcd *ohci = hcd_to_ohci(hcd);
  15
  16        ohci->flags |= OHCI_QUIRK_BE_MMIO;
  17        ohci_hcd_init(ohci);
  18        return ohci_init(ohci);
  19}
  20
  21static int ps3_ohci_hc_start(struct usb_hcd *hcd)
  22{
  23        int result;
  24        struct ohci_hcd *ohci = hcd_to_ohci(hcd);
  25
  26        /* Handle root hub init quirk in spider south bridge. */
  27        /* Also set PwrOn2PwrGood to 0x7f (254ms). */
  28
  29        ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM,
  30                &ohci->regs->roothub.a);
  31        ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b);
  32
  33        result = ohci_run(ohci);
  34
  35        if (result < 0) {
  36                dev_err(hcd->self.controller, "can't start %s\n",
  37                        hcd->self.bus_name);
  38                ohci_stop(hcd);
  39        }
  40
  41        return result;
  42}
  43
  44static const struct hc_driver ps3_ohci_hc_driver = {
  45        .description            = hcd_name,
  46        .product_desc           = "PS3 OHCI Host Controller",
  47        .hcd_priv_size          = sizeof(struct ohci_hcd),
  48        .irq                    = ohci_irq,
  49        .flags                  = HCD_MEMORY | HCD_USB11,
  50        .reset                  = ps3_ohci_hc_reset,
  51        .start                  = ps3_ohci_hc_start,
  52        .stop                   = ohci_stop,
  53        .shutdown               = ohci_shutdown,
  54        .urb_enqueue            = ohci_urb_enqueue,
  55        .urb_dequeue            = ohci_urb_dequeue,
  56        .endpoint_disable       = ohci_endpoint_disable,
  57        .get_frame_number       = ohci_get_frame,
  58        .hub_status_data        = ohci_hub_status_data,
  59        .hub_control            = ohci_hub_control,
  60        .start_port_reset       = ohci_start_port_reset,
  61#if defined(CONFIG_PM)
  62        .bus_suspend            = ohci_bus_suspend,
  63        .bus_resume             = ohci_bus_resume,
  64#endif
  65};
  66
  67static int ps3_ohci_probe(struct ps3_system_bus_device *dev)
  68{
  69        int result;
  70        struct usb_hcd *hcd;
  71        unsigned int virq;
  72        static u64 dummy_mask;
  73
  74        if (usb_disabled()) {
  75                result = -ENODEV;
  76                goto fail_start;
  77        }
  78
  79        result = ps3_open_hv_device(dev);
  80
  81        if (result) {
  82                dev_dbg(&dev->core, "%s:%d: ps3_open_hv_device failed: %s\n",
  83                        __func__, __LINE__, ps3_result(result));
  84                result = -EPERM;
  85                goto fail_open;
  86        }
  87
  88        result = ps3_dma_region_create(dev->d_region);
  89
  90        if (result) {
  91                dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: "
  92                        "(%d)\n", __func__, __LINE__, result);
  93                BUG_ON("check region type");
  94                goto fail_dma_region;
  95        }
  96
  97        result = ps3_mmio_region_create(dev->m_region);
  98
  99        if (result) {
 100                dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
 101                        __func__, __LINE__);
 102                result = -EPERM;
 103                goto fail_mmio_region;
 104        }
 105
 106        dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
 107                __LINE__, dev->m_region->lpar_addr);
 108
 109        result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
 110
 111        if (result) {
 112                dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
 113                        __func__, __LINE__, virq);
 114                result = -EPERM;
 115                goto fail_irq;
 116        }
 117
 118        dummy_mask = DMA_BIT_MASK(32);
 119        dev->core.dma_mask = &dummy_mask;
 120        dma_set_coherent_mask(&dev->core, dummy_mask);
 121
 122        hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev_name(&dev->core));
 123
 124        if (!hcd) {
 125                dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
 126                        __LINE__);
 127                result = -ENOMEM;
 128                goto fail_create_hcd;
 129        }
 130
 131        hcd->rsrc_start = dev->m_region->lpar_addr;
 132        hcd->rsrc_len = dev->m_region->len;
 133
 134        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name))
 135                dev_dbg(&dev->core, "%s:%d: request_mem_region failed\n",
 136                        __func__, __LINE__);
 137
 138        hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
 139
 140        if (!hcd->regs) {
 141                dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
 142                        __LINE__);
 143                result = -EPERM;
 144                goto fail_ioremap;
 145        }
 146
 147        dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
 148                (unsigned long)hcd->rsrc_start);
 149        dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len   %lxh\n", __func__, __LINE__,
 150                (unsigned long)hcd->rsrc_len);
 151        dev_dbg(&dev->core, "%s:%d: hcd->regs       %lxh\n", __func__, __LINE__,
 152                (unsigned long)hcd->regs);
 153        dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
 154                (unsigned long)virq);
 155
 156        ps3_system_bus_set_drvdata(dev, hcd);
 157
 158        result = usb_add_hcd(hcd, virq, 0);
 159
 160        if (result) {
 161                dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
 162                        __func__, __LINE__, result);
 163                goto fail_add_hcd;
 164        }
 165
 166        device_wakeup_enable(hcd->self.controller);
 167        return result;
 168
 169fail_add_hcd:
 170        iounmap(hcd->regs);
 171fail_ioremap:
 172        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 173        usb_put_hcd(hcd);
 174fail_create_hcd:
 175        ps3_io_irq_destroy(virq);
 176fail_irq:
 177        ps3_free_mmio_region(dev->m_region);
 178fail_mmio_region:
 179        ps3_dma_region_free(dev->d_region);
 180fail_dma_region:
 181        ps3_close_hv_device(dev);
 182fail_open:
 183fail_start:
 184        return result;
 185}
 186
 187static int ps3_ohci_remove(struct ps3_system_bus_device *dev)
 188{
 189        unsigned int tmp;
 190        struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
 191
 192        BUG_ON(!hcd);
 193
 194        dev_dbg(&dev->core, "%s:%d: regs %p\n", __func__, __LINE__, hcd->regs);
 195        dev_dbg(&dev->core, "%s:%d: irq %u\n", __func__, __LINE__, hcd->irq);
 196
 197        tmp = hcd->irq;
 198
 199        ohci_shutdown(hcd);
 200        usb_remove_hcd(hcd);
 201
 202        ps3_system_bus_set_drvdata(dev, NULL);
 203
 204        BUG_ON(!hcd->regs);
 205        iounmap(hcd->regs);
 206
 207        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 208        usb_put_hcd(hcd);
 209
 210        ps3_io_irq_destroy(tmp);
 211        ps3_free_mmio_region(dev->m_region);
 212
 213        ps3_dma_region_free(dev->d_region);
 214        ps3_close_hv_device(dev);
 215
 216        return 0;
 217}
 218
 219static int __init ps3_ohci_driver_register(struct ps3_system_bus_driver *drv)
 220{
 221        return firmware_has_feature(FW_FEATURE_PS3_LV1)
 222                ? ps3_system_bus_driver_register(drv)
 223                : 0;
 224}
 225
 226static void ps3_ohci_driver_unregister(struct ps3_system_bus_driver *drv)
 227{
 228        if (firmware_has_feature(FW_FEATURE_PS3_LV1))
 229                ps3_system_bus_driver_unregister(drv);
 230}
 231
 232MODULE_ALIAS(PS3_MODULE_ALIAS_OHCI);
 233
 234static struct ps3_system_bus_driver ps3_ohci_driver = {
 235        .core.name = "ps3-ohci-driver",
 236        .core.owner = THIS_MODULE,
 237        .match_id = PS3_MATCH_ID_OHCI,
 238        .probe = ps3_ohci_probe,
 239        .remove = ps3_ohci_remove,
 240        .shutdown = ps3_ohci_remove,
 241};
 242