diff options
-rw-r--r-- | arch/powerpc/Kconfig | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 25 | ||||
-rw-r--r-- | drivers/usb/host/ehci-ps3.c | 193 |
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 | } |
951 | module_exit(ehci_hcd_cleanup); | 974 | module_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 | |||
23 | static 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 | |||
54 | static 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 | ||
78 | static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg( | ||
79 | const struct device *_dev, const char *fmt, ...) {return 0;} | ||
80 | #endif | ||
81 | |||
82 | |||
83 | static 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 | |||
160 | fail_add_hcd: | ||
161 | iounmap(hcd->regs); | ||
162 | fail_ioremap: | ||
163 | usb_put_hcd(hcd); | ||
164 | fail_create_hcd: | ||
165 | ps3_free_io_irq(virq); | ||
166 | fail_irq: | ||
167 | ps3_free_mmio_region(dev->m_region); | ||
168 | fail_mmio: | ||
169 | fail_start: | ||
170 | return result; | ||
171 | } | ||
172 | |||
173 | static 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 | |||
184 | MODULE_ALIAS("ps3-ehci"); | ||
185 | |||
186 | static 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 | }; | ||