aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--drivers/usb/host/ehci-hcd.c25
-rw-r--r--drivers/usb/host/ehci-ps3.c193
3 files changed, 219 insertions, 1 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index d6abe495c6b0..c393e1540071 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -529,6 +529,8 @@ 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_EHCI
533 select USB_EHCI_BIG_ENDIAN_MMIO
532 help 534 help
533 This option enables support for the Sony PS3 game console 535 This option enables support for the Sony PS3 game console
534 and other platforms using the PS3 hypervisor. 536 and other platforms using the PS3 hypervisor.
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 03d567e4d00a..9ec896218feb 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -907,7 +907,13 @@ MODULE_LICENSE ("GPL");
907#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver 907#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
908#endif 908#endif
909 909
910#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) 910#ifdef CONFIG_PPC_PS3
911#include "ehci-ps3.c"
912#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_sb_driver
913#endif
914
915#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
916 !defined(PS3_SYSTEM_BUS_DRIVER)
911#error "missing bus glue for ehci-hcd" 917#error "missing bus glue for ehci-hcd"
912#endif 918#endif
913 919
@@ -932,6 +938,20 @@ static int __init ehci_hcd_init(void)
932#ifdef PLATFORM_DRIVER 938#ifdef PLATFORM_DRIVER
933 platform_driver_unregister(&PLATFORM_DRIVER); 939 platform_driver_unregister(&PLATFORM_DRIVER);
934#endif 940#endif
941 return retval;
942 }
943#endif
944
945#ifdef PS3_SYSTEM_BUS_DRIVER
946 retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
947 if (retval < 0) {
948#ifdef PLATFORM_DRIVER
949 platform_driver_unregister(&PLATFORM_DRIVER);
950#endif
951#ifdef PCI_DRIVER
952 pci_unregister_driver(&PCI_DRIVER);
953#endif
954 return retval;
935 } 955 }
936#endif 956#endif
937 957
@@ -947,6 +967,9 @@ static void __exit ehci_hcd_cleanup(void)
947#ifdef PCI_DRIVER 967#ifdef PCI_DRIVER
948 pci_unregister_driver(&PCI_DRIVER); 968 pci_unregister_driver(&PCI_DRIVER);
949#endif 969#endif
970#ifdef PS3_SYSTEM_BUS_DRIVER
971 ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
972#endif
950} 973}
951module_exit(ehci_hcd_cleanup); 974module_exit(ehci_hcd_cleanup);
952 975
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
new file mode 100644
index 000000000000..371f194a9d39
--- /dev/null
+++ b/drivers/usb/host/ehci-ps3.c
@@ -0,0 +1,193 @@
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/ps3.h>
22
23static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
24{
25 int result;
26 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
27
28 ehci->big_endian_mmio = 1;
29
30 ehci->caps = hcd->regs;
31 ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
32 &ehci->caps->hc_capbase));
33
34 dbg_hcs_params(ehci, "reset");
35 dbg_hcc_params(ehci, "reset");
36
37 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
38
39 result = ehci_halt(ehci);
40
41 if (result)
42 return result;
43
44 result = ehci_init(hcd);
45
46 if (result)
47 return result;
48
49 ehci_port_power(ehci, 0);
50
51 return result;
52}
53
54static const struct hc_driver ps3_ehci_hc_driver = {
55 .description = hcd_name,
56 .product_desc = "PS3 EHCI Host Controller",
57 .hcd_priv_size = sizeof(struct ehci_hcd),
58 .irq = ehci_irq,
59 .flags = HCD_MEMORY | HCD_USB2,
60 .reset = ps3_ehci_hc_reset,
61 .start = ehci_run,
62 .stop = ehci_stop,
63 .shutdown = ehci_shutdown,
64 .urb_enqueue = ehci_urb_enqueue,
65 .urb_dequeue = ehci_urb_dequeue,
66 .endpoint_disable = ehci_endpoint_disable,
67 .get_frame_number = ehci_get_frame,
68 .hub_status_data = ehci_hub_status_data,
69 .hub_control = ehci_hub_control,
70#if defined(CONFIG_PM)
71 .bus_suspend = ehci_bus_suspend,
72 .bus_resume = ehci_bus_resume,
73#endif
74};
75
76#if !defined(DEBUG)
77#undef dev_dbg
78static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
79 const struct device *_dev, const char *fmt, ...) {return 0;}
80#endif
81
82
83static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
84{
85 int result;
86 struct usb_hcd *hcd;
87 unsigned int virq;
88 static u64 dummy_mask = DMA_32BIT_MASK;
89
90 if (usb_disabled()) {
91 result = -ENODEV;
92 goto fail_start;
93 }
94
95 result = ps3_mmio_region_create(dev->m_region);
96
97 if (result) {
98 dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
99 __func__, __LINE__);
100 result = -EPERM;
101 goto fail_mmio;
102 }
103
104 dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
105 __LINE__, dev->m_region->lpar_addr);
106
107 result = ps3_alloc_io_irq(dev->interrupt_id, &virq);
108
109 if (result) {
110 dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
111 __func__, __LINE__, virq);
112 result = -EPERM;
113 goto fail_irq;
114 }
115
116 dev->core.power.power_state = PMSG_ON;
117 dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
118
119 hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id);
120
121 if (!hcd) {
122 dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
123 __LINE__);
124 result = -ENOMEM;
125 goto fail_create_hcd;
126 }
127
128 hcd->rsrc_start = dev->m_region->lpar_addr;
129 hcd->rsrc_len = dev->m_region->len;
130 hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
131
132 if (!hcd->regs) {
133 dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
134 __LINE__);
135 result = -EPERM;
136 goto fail_ioremap;
137 }
138
139 dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
140 (unsigned long)hcd->rsrc_start);
141 dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__,
142 (unsigned long)hcd->rsrc_len);
143 dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__,
144 (unsigned long)hcd->regs);
145 dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
146 (unsigned long)virq);
147
148 ps3_system_bus_set_driver_data(dev, hcd);
149
150 result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
151
152 if (result) {
153 dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
154 __func__, __LINE__, result);
155 goto fail_add_hcd;
156 }
157
158 return result;
159
160fail_add_hcd:
161 iounmap(hcd->regs);
162fail_ioremap:
163 usb_put_hcd(hcd);
164fail_create_hcd:
165 ps3_free_io_irq(virq);
166fail_irq:
167 ps3_free_mmio_region(dev->m_region);
168fail_mmio:
169fail_start:
170 return result;
171}
172
173static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
174{
175 struct usb_hcd *hcd =
176 (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
177
178 usb_put_hcd(hcd);
179 ps3_system_bus_set_driver_data(dev, NULL);
180
181 return 0;
182}
183
184MODULE_ALIAS("ps3-ehci");
185
186static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
187 .match_id = PS3_MATCH_ID_EHCI,
188 .core = {
189 .name = "ps3-ehci-driver",
190 },
191 .probe = ps3_ehci_sb_probe,
192 .remove = ps3_ehci_sb_remove,
193};