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