diff options
| author | Geoff Levand <geoffrey.levand@am.sony.com> | 2007-01-15 23:12:10 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-07 18:44:37 -0500 |
| commit | 6a6c957eba20814456bc4bffbd4ec42406f9eb02 (patch) | |
| tree | 21e215b745658c6ff49b833da59c84327c9793d2 | |
| parent | de44743b033942731f6b898c2d389f7ee5ac890b (diff) | |
USB: ps3 ohci bus glue
USB OHCI driver bus glue for the PS3 game console.
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -rw-r--r-- | arch/powerpc/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-hcd.c | 21 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-ps3.c | 196 |
3 files changed, 219 insertions, 1 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index c393e1540071..c1e01b22addc 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
| @@ -529,6 +529,9 @@ config PPC_PS3 | |||
| 529 | bool "Sony PS3 (incomplete)" | 529 | bool "Sony PS3 (incomplete)" |
| 530 | depends on PPC_MULTIPLATFORM && PPC64 | 530 | depends on PPC_MULTIPLATFORM && PPC64 |
| 531 | select PPC_CELL | 531 | select PPC_CELL |
| 532 | select USB_ARCH_HAS_OHCI | ||
| 533 | select USB_OHCI_LITTLE_ENDIAN | ||
| 534 | select USB_OHCI_BIG_ENDIAN_MMIO | ||
| 532 | select USB_ARCH_HAS_EHCI | 535 | select USB_ARCH_HAS_EHCI |
| 533 | select USB_EHCI_BIG_ENDIAN_MMIO | 536 | select USB_EHCI_BIG_ENDIAN_MMIO |
| 534 | help | 537 | help |
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 2c4a6299e4c6..fa6a7ceaa0db 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
| @@ -919,10 +919,16 @@ MODULE_LICENSE ("GPL"); | |||
| 919 | #define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver | 919 | #define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver |
| 920 | #endif | 920 | #endif |
| 921 | 921 | ||
| 922 | #ifdef CONFIG_PPC_PS3 | ||
| 923 | #include "ohci-ps3.c" | ||
| 924 | #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_driver | ||
| 925 | #endif | ||
| 926 | |||
| 922 | #if !defined(PCI_DRIVER) && \ | 927 | #if !defined(PCI_DRIVER) && \ |
| 923 | !defined(PLATFORM_DRIVER) && \ | 928 | !defined(PLATFORM_DRIVER) && \ |
| 924 | !defined(OF_PLATFORM_DRIVER) && \ | 929 | !defined(OF_PLATFORM_DRIVER) && \ |
| 925 | !defined(SA1111_DRIVER) | 930 | !defined(SA1111_DRIVER) && \ |
| 931 | !defined(PS3_SYSTEM_BUS_DRIVER) | ||
| 926 | #error "missing bus glue for ohci-hcd" | 932 | #error "missing bus glue for ohci-hcd" |
| 927 | #endif | 933 | #endif |
| 928 | 934 | ||
| @@ -937,6 +943,12 @@ static int __init ohci_hcd_mod_init(void) | |||
| 937 | pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, | 943 | pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, |
| 938 | sizeof (struct ed), sizeof (struct td)); | 944 | sizeof (struct ed), sizeof (struct td)); |
| 939 | 945 | ||
| 946 | #ifdef PS3_SYSTEM_BUS_DRIVER | ||
| 947 | retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER); | ||
| 948 | if (retval < 0) | ||
| 949 | goto error_ps3; | ||
| 950 | #endif | ||
| 951 | |||
| 940 | #ifdef PLATFORM_DRIVER | 952 | #ifdef PLATFORM_DRIVER |
| 941 | retval = platform_driver_register(&PLATFORM_DRIVER); | 953 | retval = platform_driver_register(&PLATFORM_DRIVER); |
| 942 | if (retval < 0) | 954 | if (retval < 0) |
| @@ -979,6 +991,10 @@ static int __init ohci_hcd_mod_init(void) | |||
| 979 | platform_driver_unregister(&PLATFORM_DRIVER); | 991 | platform_driver_unregister(&PLATFORM_DRIVER); |
| 980 | error_platform: | 992 | error_platform: |
| 981 | #endif | 993 | #endif |
| 994 | #ifdef PS3_SYSTEM_BUS_DRIVER | ||
| 995 | ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); | ||
| 996 | error_ps3: | ||
| 997 | #endif | ||
| 982 | return retval; | 998 | return retval; |
| 983 | } | 999 | } |
| 984 | module_init(ohci_hcd_mod_init); | 1000 | module_init(ohci_hcd_mod_init); |
| @@ -997,6 +1013,9 @@ static void __exit ohci_hcd_mod_exit(void) | |||
| 997 | #ifdef PLATFORM_DRIVER | 1013 | #ifdef PLATFORM_DRIVER |
| 998 | platform_driver_unregister(&PLATFORM_DRIVER); | 1014 | platform_driver_unregister(&PLATFORM_DRIVER); |
| 999 | #endif | 1015 | #endif |
| 1016 | #ifdef PS3_SYSTEM_BUS_DRIVER | ||
| 1017 | ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); | ||
| 1018 | #endif | ||
| 1000 | } | 1019 | } |
| 1001 | module_exit(ohci_hcd_mod_exit); | 1020 | module_exit(ohci_hcd_mod_exit); |
| 1002 | 1021 | ||
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c new file mode 100644 index 000000000000..69d948b4a701 --- /dev/null +++ b/drivers/usb/host/ohci-ps3.c | |||
| @@ -0,0 +1,196 @@ | |||
| 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/ps3.h> | ||
| 22 | |||
| 23 | static int ps3_ohci_hc_reset(struct usb_hcd *hcd) | ||
| 24 | { | ||
| 25 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | ||
| 26 | |||
| 27 | ohci->flags |= OHCI_QUIRK_BE_MMIO; | ||
| 28 | ohci_hcd_init(ohci); | ||
| 29 | return ohci_init(ohci); | ||
| 30 | } | ||
| 31 | |||
| 32 | static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd) | ||
| 33 | { | ||
| 34 | int result; | ||
| 35 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | ||
| 36 | |||
| 37 | /* Handle root hub init quirk in spider south bridge. */ | ||
| 38 | /* Also set PwrOn2PwrGood to 0x7f (254ms). */ | ||
| 39 | |||
| 40 | ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM, | ||
| 41 | &ohci->regs->roothub.a); | ||
| 42 | ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b); | ||
| 43 | |||
| 44 | result = ohci_run(ohci); | ||
| 45 | |||
| 46 | if (result < 0) { | ||
| 47 | err("can't start %s", hcd->self.bus_name); | ||
| 48 | ohci_stop(hcd); | ||
| 49 | } | ||
| 50 | |||
| 51 | return result; | ||
| 52 | } | ||
| 53 | |||
| 54 | static const struct hc_driver ps3_ohci_hc_driver = { | ||
| 55 | .description = hcd_name, | ||
| 56 | .product_desc = "PS3 OHCI Host Controller", | ||
| 57 | .hcd_priv_size = sizeof(struct ohci_hcd), | ||
| 58 | .irq = ohci_irq, | ||
| 59 | .flags = HCD_MEMORY | HCD_USB11, | ||
| 60 | .reset = ps3_ohci_hc_reset, | ||
| 61 | .start = ps3_ohci_hc_start, | ||
| 62 | .stop = ohci_stop, | ||
| 63 | .shutdown = ohci_shutdown, | ||
| 64 | .urb_enqueue = ohci_urb_enqueue, | ||
| 65 | .urb_dequeue = ohci_urb_dequeue, | ||
| 66 | .endpoint_disable = ohci_endpoint_disable, | ||
| 67 | .get_frame_number = ohci_get_frame, | ||
| 68 | .hub_status_data = ohci_hub_status_data, | ||
| 69 | .hub_control = ohci_hub_control, | ||
| 70 | .hub_irq_enable = ohci_rhsc_enable, | ||
| 71 | .start_port_reset = ohci_start_port_reset, | ||
| 72 | #if defined(CONFIG_PM) | ||
| 73 | .bus_suspend = ohci_bus_suspend, | ||
| 74 | .bus_resume = ohci_bus_resume, | ||
| 75 | #endif | ||
| 76 | }; | ||
| 77 | |||
| 78 | /* redefine dev_dbg to do a syntax check */ | ||
| 79 | |||
| 80 | #if !defined(DEBUG) | ||
| 81 | #undef dev_dbg | ||
| 82 | static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg( | ||
| 83 | const struct device *_dev, const char *fmt, ...) {return 0;} | ||
| 84 | #endif | ||
| 85 | |||
| 86 | static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev) | ||
| 87 | { | ||
| 88 | int result; | ||
| 89 | struct usb_hcd *hcd; | ||
| 90 | unsigned int virq; | ||
| 91 | static u64 dummy_mask = DMA_32BIT_MASK; | ||
| 92 | |||
| 93 | if (usb_disabled()) { | ||
| 94 | result = -ENODEV; | ||
| 95 | goto fail_start; | ||
| 96 | } | ||
| 97 | |||
| 98 | result = ps3_mmio_region_create(dev->m_region); | ||
| 99 | |||
| 100 | if (result) { | ||
| 101 | dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n", | ||
| 102 | __func__, __LINE__); | ||
| 103 | result = -EPERM; | ||
| 104 | goto fail_mmio; | ||
| 105 | } | ||
| 106 | |||
| 107 | dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, | ||
| 108 | __LINE__, dev->m_region->lpar_addr); | ||
| 109 | |||
| 110 | result = ps3_alloc_io_irq(dev->interrupt_id, &virq); | ||
| 111 | |||
| 112 | if (result) { | ||
| 113 | dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", | ||
| 114 | __func__, __LINE__, virq); | ||
| 115 | result = -EPERM; | ||
| 116 | goto fail_irq; | ||
| 117 | } | ||
| 118 | |||
| 119 | dev->core.power.power_state = PMSG_ON; | ||
| 120 | dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ | ||
| 121 | |||
| 122 | hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id); | ||
| 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 | hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len); | ||
| 134 | |||
| 135 | if (!hcd->regs) { | ||
| 136 | dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__, | ||
| 137 | __LINE__); | ||
| 138 | result = -EPERM; | ||
| 139 | goto fail_ioremap; | ||
| 140 | } | ||
| 141 | |||
| 142 | dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__, | ||
| 143 | (unsigned long)hcd->rsrc_start); | ||
| 144 | dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__, | ||
| 145 | (unsigned long)hcd->rsrc_len); | ||
| 146 | dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__, | ||
| 147 | (unsigned long)hcd->regs); | ||
| 148 | dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, | ||
| 149 | (unsigned long)virq); | ||
| 150 | |||
| 151 | ps3_system_bus_set_driver_data(dev, hcd); | ||
| 152 | |||
| 153 | result = usb_add_hcd(hcd, virq, IRQF_DISABLED); | ||
| 154 | |||
| 155 | if (result) { | ||
| 156 | dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n", | ||
| 157 | __func__, __LINE__, result); | ||
| 158 | goto fail_add_hcd; | ||
| 159 | } | ||
| 160 | |||
| 161 | return result; | ||
| 162 | |||
| 163 | fail_add_hcd: | ||
| 164 | iounmap(hcd->regs); | ||
| 165 | fail_ioremap: | ||
| 166 | usb_put_hcd(hcd); | ||
| 167 | fail_create_hcd: | ||
| 168 | ps3_free_io_irq(virq); | ||
| 169 | fail_irq: | ||
| 170 | ps3_free_mmio_region(dev->m_region); | ||
| 171 | fail_mmio: | ||
| 172 | fail_start: | ||
| 173 | return result; | ||
| 174 | } | ||
| 175 | |||
| 176 | static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev) | ||
| 177 | { | ||
| 178 | struct usb_hcd *hcd = | ||
| 179 | (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); | ||
| 180 | |||
| 181 | usb_put_hcd(hcd); | ||
| 182 | ps3_system_bus_set_driver_data(dev, NULL); | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | MODULE_ALIAS("ps3-ohci"); | ||
| 188 | |||
| 189 | static struct ps3_system_bus_driver ps3_ohci_sb_driver = { | ||
| 190 | .match_id = PS3_MATCH_ID_OHCI, | ||
| 191 | .core = { | ||
| 192 | .name = "ps3-ohci-driver", | ||
| 193 | }, | ||
| 194 | .probe = ps3_ohci_sb_probe, | ||
| 195 | .remove = ps3_ohci_sb_remove, | ||
| 196 | }; | ||
