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 12 static 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 21 static 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 44 static 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 67 static 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 = DMA_BIT_MASK(32); 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 dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ 119 120 hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev_name(&dev->core)); 121 122 if (!hcd) { 123 dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__, 124 __LINE__); 125 result = -ENOMEM; 126 goto fail_create_hcd; 127 } 128 129 hcd->rsrc_start = dev->m_region->lpar_addr; 130 hcd->rsrc_len = dev->m_region->len; 131 132 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) 133 dev_dbg(&dev->core, "%s:%d: request_mem_region failed\n", 134 __func__, __LINE__); 135 136 hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len); 137 138 if (!hcd->regs) { 139 dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__, 140 __LINE__); 141 result = -EPERM; 142 goto fail_ioremap; 143 } 144 145 dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__, 146 (unsigned long)hcd->rsrc_start); 147 dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__, 148 (unsigned long)hcd->rsrc_len); 149 dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__, 150 (unsigned long)hcd->regs); 151 dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, 152 (unsigned long)virq); 153 154 ps3_system_bus_set_drvdata(dev, hcd); 155 156 result = usb_add_hcd(hcd, virq, 0); 157 158 if (result) { 159 dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n", 160 __func__, __LINE__, result); 161 goto fail_add_hcd; 162 } 163 164 device_wakeup_enable(hcd->self.controller); 165 return result; 166 167 fail_add_hcd: 168 iounmap(hcd->regs); 169 fail_ioremap: 170 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 171 usb_put_hcd(hcd); 172 fail_create_hcd: 173 ps3_io_irq_destroy(virq); 174 fail_irq: 175 ps3_free_mmio_region(dev->m_region); 176 fail_mmio_region: 177 ps3_dma_region_free(dev->d_region); 178 fail_dma_region: 179 ps3_close_hv_device(dev); 180 fail_open: 181 fail_start: 182 return result; 183 } 184 185 static int ps3_ohci_remove(struct ps3_system_bus_device *dev) 186 { 187 unsigned int tmp; 188 struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev); 189 190 BUG_ON(!hcd); 191 192 dev_dbg(&dev->core, "%s:%d: regs %p\n", __func__, __LINE__, hcd->regs); 193 dev_dbg(&dev->core, "%s:%d: irq %u\n", __func__, __LINE__, hcd->irq); 194 195 tmp = hcd->irq; 196 197 ohci_shutdown(hcd); 198 usb_remove_hcd(hcd); 199 200 ps3_system_bus_set_drvdata(dev, NULL); 201 202 BUG_ON(!hcd->regs); 203 iounmap(hcd->regs); 204 205 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 206 usb_put_hcd(hcd); 207 208 ps3_io_irq_destroy(tmp); 209 ps3_free_mmio_region(dev->m_region); 210 211 ps3_dma_region_free(dev->d_region); 212 ps3_close_hv_device(dev); 213 214 return 0; 215 } 216 217 static 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 224 static 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 230 MODULE_ALIAS(PS3_MODULE_ALIAS_OHCI); 231 232 static 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 }; 240