ohci-ps3.c (5898B)
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_DMA | 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 void 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 217static int __init ps3_ohci_driver_register(struct ps3_system_bus_driver *drv) 218{ 219 return firmware_has_feature(FW_FEATURE_PS3_LV1) 220 ? ps3_system_bus_driver_register(drv) 221 : 0; 222} 223 224static void ps3_ohci_driver_unregister(struct ps3_system_bus_driver *drv) 225{ 226 if (firmware_has_feature(FW_FEATURE_PS3_LV1)) 227 ps3_system_bus_driver_unregister(drv); 228} 229 230MODULE_ALIAS(PS3_MODULE_ALIAS_OHCI); 231 232static struct ps3_system_bus_driver ps3_ohci_driver = { 233 .core.name = "ps3-ohci-driver", 234 .core.owner = THIS_MODULE, 235 .match_id = PS3_MATCH_ID_OHCI, 236 .probe = ps3_ohci_probe, 237 .remove = ps3_ohci_remove, 238 .shutdown = ps3_ohci_remove, 239};