Blame view

drivers/usb/host/ohci-ps3.c 6.32 KB
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /*
   *  PS3 OHCI Host Controller driver
   *
   *  Copyright (C) 2006 Sony Computer Entertainment Inc.
   *  Copyright 2006 Sony Corp.
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation; version 2 of the License.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program; if not, write to the Free Software
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
7a4eb7fd5   Geoff Levand   USB: PS3: USB sys...
20
  #include <asm/firmware.h>
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  #include <asm/ps3.h>
  
  static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
  {
  	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
  
  	ohci->flags |= OHCI_QUIRK_BE_MMIO;
  	ohci_hcd_init(ohci);
  	return ohci_init(ohci);
  }
  
  static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd)
  {
  	int result;
  	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
  
  	/* Handle root hub init quirk in spider south bridge. */
  	/* Also set PwrOn2PwrGood to 0x7f (254ms). */
  
  	ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM,
  		&ohci->regs->roothub.a);
  	ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b);
  
  	result = ohci_run(ohci);
  
  	if (result < 0) {
  		err("can't start %s", hcd->self.bus_name);
  		ohci_stop(hcd);
  	}
  
  	return result;
  }
  
  static const struct hc_driver ps3_ohci_hc_driver = {
  	.description		= hcd_name,
  	.product_desc		= "PS3 OHCI Host Controller",
  	.hcd_priv_size		= sizeof(struct ohci_hcd),
  	.irq			= ohci_irq,
  	.flags			= HCD_MEMORY | HCD_USB11,
  	.reset			= ps3_ohci_hc_reset,
  	.start			= ps3_ohci_hc_start,
  	.stop			= ohci_stop,
  	.shutdown		= ohci_shutdown,
  	.urb_enqueue		= ohci_urb_enqueue,
  	.urb_dequeue		= ohci_urb_dequeue,
  	.endpoint_disable	= ohci_endpoint_disable,
  	.get_frame_number	= ohci_get_frame,
  	.hub_status_data	= ohci_hub_status_data,
  	.hub_control		= ohci_hub_control,
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
70
71
72
73
74
75
  	.start_port_reset	= ohci_start_port_reset,
  #if defined(CONFIG_PM)
  	.bus_suspend 		= ohci_bus_suspend,
  	.bus_resume 		= ohci_bus_resume,
  #endif
  };
313485175   Geert Uytterhoeven   usb/ps3: Add miss...
76
  static int __devinit ps3_ohci_probe(struct ps3_system_bus_device *dev)
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
77
78
79
80
  {
  	int result;
  	struct usb_hcd *hcd;
  	unsigned int virq;
284901a90   Yang Hongyang   dma-mapping: repl...
81
  	static u64 dummy_mask = DMA_BIT_MASK(32);
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
82
83
84
85
86
  
  	if (usb_disabled()) {
  		result = -ENODEV;
  		goto fail_start;
  	}
7a4eb7fd5   Geoff Levand   USB: PS3: USB sys...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  	result = ps3_open_hv_device(dev);
  
  	if (result) {
  		dev_dbg(&dev->core, "%s:%d: ps3_open_hv_device failed: %s
  ",
  			__func__, __LINE__, ps3_result(result));
  		result = -EPERM;
  		goto fail_open;
  	}
  
  	result = ps3_dma_region_create(dev->d_region);
  
  	if (result) {
  		dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: "
  			"(%d)
  ", __func__, __LINE__, result);
  		BUG_ON("check region type");
  		goto fail_dma_region;
  	}
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
106
107
108
109
110
111
112
  	result = ps3_mmio_region_create(dev->m_region);
  
  	if (result) {
  		dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed
  ",
  			__func__, __LINE__);
  		result = -EPERM;
7a4eb7fd5   Geoff Levand   USB: PS3: USB sys...
113
  		goto fail_mmio_region;
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
114
115
116
117
118
  	}
  
  	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh
  ", __func__,
  		__LINE__, dev->m_region->lpar_addr);
dc4f60c25   Geoff Levand   [POWERPC] PS3: In...
119
  	result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
120
121
122
123
124
125
126
127
  
  	if (result) {
  		dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.
  ",
  			__func__, __LINE__, virq);
  		result = -EPERM;
  		goto fail_irq;
  	}
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
128
  	dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
7071a3ce0   Kay Sievers   USB: usb dev_name...
129
  	hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev_name(&dev->core));
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
130
131
132
133
134
135
136
137
138
139
140
  
  	if (!hcd) {
  		dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed
  ", __func__,
  			__LINE__);
  		result = -ENOMEM;
  		goto fail_create_hcd;
  	}
  
  	hcd->rsrc_start = dev->m_region->lpar_addr;
  	hcd->rsrc_len = dev->m_region->len;
7a4eb7fd5   Geoff Levand   USB: PS3: USB sys...
141
142
143
144
145
  
  	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name))
  		dev_dbg(&dev->core, "%s:%d: request_mem_region failed
  ",
  			__func__, __LINE__);
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  	hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
  
  	if (!hcd->regs) {
  		dev_dbg(&dev->core, "%s:%d: ioremap failed
  ", __func__,
  			__LINE__);
  		result = -EPERM;
  		goto fail_ioremap;
  	}
  
  	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh
  ", __func__, __LINE__,
  		(unsigned long)hcd->rsrc_start);
  	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len   %lxh
  ", __func__, __LINE__,
  		(unsigned long)hcd->rsrc_len);
  	dev_dbg(&dev->core, "%s:%d: hcd->regs       %lxh
  ", __func__, __LINE__,
  		(unsigned long)hcd->regs);
  	dev_dbg(&dev->core, "%s:%d: virq            %lu
  ", __func__, __LINE__,
  		(unsigned long)virq);
03fa68c24   Geert Uytterhoeven   ps3: shorten ps3_...
168
  	ps3_system_bus_set_drvdata(dev, hcd);
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
  
  	result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
  
  	if (result) {
  		dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)
  ",
  			__func__, __LINE__, result);
  		goto fail_add_hcd;
  	}
  
  	return result;
  
  fail_add_hcd:
  	iounmap(hcd->regs);
  fail_ioremap:
7a4eb7fd5   Geoff Levand   USB: PS3: USB sys...
184
  	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
185
186
  	usb_put_hcd(hcd);
  fail_create_hcd:
dc4f60c25   Geoff Levand   [POWERPC] PS3: In...
187
  	ps3_io_irq_destroy(virq);
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
188
189
  fail_irq:
  	ps3_free_mmio_region(dev->m_region);
7a4eb7fd5   Geoff Levand   USB: PS3: USB sys...
190
191
192
193
194
  fail_mmio_region:
  	ps3_dma_region_free(dev->d_region);
  fail_dma_region:
  	ps3_close_hv_device(dev);
  fail_open:
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
195
196
197
  fail_start:
  	return result;
  }
ddcb01ff9   Geoff Levand   USB: Fix PS3 USB ...
198
  static int ps3_ohci_remove(struct ps3_system_bus_device *dev)
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
199
  {
7a4eb7fd5   Geoff Levand   USB: PS3: USB sys...
200
  	unsigned int tmp;
03fa68c24   Geert Uytterhoeven   ps3: shorten ps3_...
201
  	struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
202

7a4eb7fd5   Geoff Levand   USB: PS3: USB sys...
203
204
205
206
207
208
209
210
  	BUG_ON(!hcd);
  
  	dev_dbg(&dev->core, "%s:%d: regs %p
  ", __func__, __LINE__, hcd->regs);
  	dev_dbg(&dev->core, "%s:%d: irq %u
  ", __func__, __LINE__, hcd->irq);
  
  	tmp = hcd->irq;
ddcb01ff9   Geoff Levand   USB: Fix PS3 USB ...
211
  	ohci_shutdown(hcd);
7a4eb7fd5   Geoff Levand   USB: PS3: USB sys...
212
  	usb_remove_hcd(hcd);
03fa68c24   Geert Uytterhoeven   ps3: shorten ps3_...
213
  	ps3_system_bus_set_drvdata(dev, NULL);
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
214

7a4eb7fd5   Geoff Levand   USB: PS3: USB sys...
215
216
217
218
219
220
221
222
223
224
225
  	BUG_ON(!hcd->regs);
  	iounmap(hcd->regs);
  
  	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
  	usb_put_hcd(hcd);
  
  	ps3_io_irq_destroy(tmp);
  	ps3_free_mmio_region(dev->m_region);
  
  	ps3_dma_region_free(dev->d_region);
  	ps3_close_hv_device(dev);
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
226
227
  	return 0;
  }
313485175   Geert Uytterhoeven   usb/ps3: Add miss...
228
  static int __init ps3_ohci_driver_register(struct ps3_system_bus_driver *drv)
7a4eb7fd5   Geoff Levand   USB: PS3: USB sys...
229
230
231
232
233
234
235
236
237
238
239
240
241
  {
  	return firmware_has_feature(FW_FEATURE_PS3_LV1)
  		? ps3_system_bus_driver_register(drv)
  		: 0;
  }
  
  static void ps3_ohci_driver_unregister(struct ps3_system_bus_driver *drv)
  {
  	if (firmware_has_feature(FW_FEATURE_PS3_LV1))
  		ps3_system_bus_driver_unregister(drv);
  }
  
  MODULE_ALIAS(PS3_MODULE_ALIAS_OHCI);
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
242

7a4eb7fd5   Geoff Levand   USB: PS3: USB sys...
243
244
245
  static struct ps3_system_bus_driver ps3_ohci_driver = {
  	.core.name = "ps3-ohci-driver",
  	.core.owner = THIS_MODULE,
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
246
  	.match_id = PS3_MATCH_ID_OHCI,
7a4eb7fd5   Geoff Levand   USB: PS3: USB sys...
247
248
249
  	.probe = ps3_ohci_probe,
  	.remove = ps3_ohci_remove,
  	.shutdown = ps3_ohci_remove,
6a6c957eb   Geoff Levand   USB: ps3 ohci bus...
250
  };