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