]>
Commit | Line | Data |
---|---|---|
fd0f2f37 YS |
1 | /* |
2 | * R8A66597 HCD (Host Controller Driver) for u-boot | |
3 | * | |
4 | * Copyright (C) 2008 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> | |
5 | * | |
e62b5266 | 6 | * SPDX-License-Identifier: GPL-2.0 |
fd0f2f37 YS |
7 | */ |
8 | ||
9 | #include <common.h> | |
24b852a7 | 10 | #include <console.h> |
fd0f2f37 YS |
11 | #include <usb.h> |
12 | #include <asm/io.h> | |
243fd642 | 13 | #include <linux/iopoll.h> |
fd0f2f37 YS |
14 | |
15 | #include "r8a66597.h" | |
16 | ||
fd0f2f37 YS |
17 | #ifdef R8A66597_DEBUG |
18 | #define R8A66597_DPRINT printf | |
19 | #else | |
20 | #define R8A66597_DPRINT(...) | |
21 | #endif | |
22 | ||
fd0f2f37 YS |
23 | static struct r8a66597 gr8a66597; |
24 | ||
60ece6d8 | 25 | static void get_hub_data(struct usb_device *dev, u16 *hub_devnum, u16 *hubport) |
fd0f2f37 | 26 | { |
60ece6d8 YS |
27 | int i; |
28 | ||
29 | *hub_devnum = 0; | |
30 | *hubport = 0; | |
31 | ||
32 | /* check a device connected to root_hub */ | |
33 | if ((dev->parent && dev->parent->devnum == 1) || | |
34 | (dev->devnum == 1)) | |
35 | return; | |
36 | ||
37 | for (i = 0; i < USB_MAXCHILDREN; i++) { | |
38 | if (dev->parent->children[i] == dev) { | |
39 | *hub_devnum = (u8)dev->parent->devnum; | |
40 | *hubport = i; | |
41 | return; | |
42 | } | |
43 | } | |
44 | ||
45 | printf("get_hub_data error.\n"); | |
46 | } | |
47 | ||
48 | static void set_devadd(struct r8a66597 *r8a66597, u8 r8a66597_address, | |
49 | struct usb_device *dev, int port) | |
50 | { | |
51 | u16 val, usbspd, upphub, hubport; | |
fd0f2f37 YS |
52 | unsigned long devadd_reg = get_devadd_addr(r8a66597_address); |
53 | ||
60ece6d8 YS |
54 | get_hub_data(dev, &upphub, &hubport); |
55 | usbspd = r8a66597->speed; | |
fd0f2f37 YS |
56 | val = (upphub << 11) | (hubport << 8) | (usbspd << 6) | (port & 0x0001); |
57 | r8a66597_write(r8a66597, val, devadd_reg); | |
58 | } | |
59 | ||
60 | static int r8a66597_clock_enable(struct r8a66597 *r8a66597) | |
61 | { | |
62 | u16 tmp; | |
63 | int i = 0; | |
64 | ||
65 | #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) | |
66 | do { | |
67 | r8a66597_write(r8a66597, SCKE, SYSCFG0); | |
68 | tmp = r8a66597_read(r8a66597, SYSCFG0); | |
69 | if (i++ > 1000) { | |
70 | printf("register access fail.\n"); | |
71 | return -1; | |
72 | } | |
73 | } while ((tmp & SCKE) != SCKE); | |
74 | r8a66597_write(r8a66597, 0x04, 0x02); | |
75 | #else | |
76 | do { | |
77 | r8a66597_write(r8a66597, USBE, SYSCFG0); | |
78 | tmp = r8a66597_read(r8a66597, SYSCFG0); | |
79 | if (i++ > 1000) { | |
80 | printf("register access fail.\n"); | |
81 | return -1; | |
82 | } | |
83 | } while ((tmp & USBE) != USBE); | |
84 | r8a66597_bclr(r8a66597, USBE, SYSCFG0); | |
11f46789 | 85 | #if !defined(CONFIG_RZA_USB) |
9d034208 | 86 | r8a66597_mdfy(r8a66597, CONFIG_R8A66597_XTAL, XTAL, SYSCFG0); |
fd0f2f37 YS |
87 | |
88 | i = 0; | |
89 | r8a66597_bset(r8a66597, XCKE, SYSCFG0); | |
90 | do { | |
91 | udelay(1000); | |
92 | tmp = r8a66597_read(r8a66597, SYSCFG0); | |
93 | if (i++ > 500) { | |
94 | printf("register access fail.\n"); | |
95 | return -1; | |
96 | } | |
97 | } while ((tmp & SCKE) != SCKE); | |
11f46789 CB |
98 | #else |
99 | /* | |
100 | * RZ/A Only: | |
101 | * Bits XTAL(UCKSEL) and UPLLE in SYSCFG0 for USB0 controls both USB0 | |
102 | * and USB1, so we must always set the USB0 register | |
103 | */ | |
104 | #if (CONFIG_R8A66597_XTAL == 1) | |
105 | setbits(le16, R8A66597_BASE0, XTAL); | |
106 | #endif | |
107 | mdelay(1); | |
108 | setbits(le16, R8A66597_BASE0, UPLLE); | |
109 | mdelay(1); | |
110 | r8a66597_bset(r8a66597, SUSPM, SUSPMODE0); | |
111 | #endif /* CONFIG_RZA_USB */ | |
fd0f2f37 YS |
112 | #endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */ |
113 | ||
114 | return 0; | |
115 | } | |
116 | ||
117 | static void r8a66597_clock_disable(struct r8a66597 *r8a66597) | |
118 | { | |
11f46789 | 119 | #if !defined(CONFIG_RZA_USB) |
fd0f2f37 YS |
120 | r8a66597_bclr(r8a66597, SCKE, SYSCFG0); |
121 | udelay(1); | |
122 | #if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597) | |
123 | r8a66597_bclr(r8a66597, PLLC, SYSCFG0); | |
124 | r8a66597_bclr(r8a66597, XCKE, SYSCFG0); | |
125 | r8a66597_bclr(r8a66597, USBE, SYSCFG0); | |
126 | #endif | |
11f46789 CB |
127 | #else |
128 | r8a66597_bclr(r8a66597, SUSPM, SUSPMODE0); | |
129 | ||
130 | clrbits(le16, R8A66597_BASE0, UPLLE); | |
131 | mdelay(1); | |
132 | r8a66597_bclr(r8a66597, USBE, SYSCFG0); | |
133 | mdelay(1); | |
134 | ||
135 | #endif | |
fd0f2f37 YS |
136 | } |
137 | ||
138 | static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port) | |
139 | { | |
140 | u16 val; | |
141 | ||
142 | val = port ? DRPD : DCFM | DRPD; | |
143 | r8a66597_bset(r8a66597, val, get_syscfg_reg(port)); | |
144 | r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port)); | |
145 | ||
11f46789 | 146 | #if !defined(CONFIG_RZA_USB) |
fd0f2f37 | 147 | r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, get_dmacfg_reg(port)); |
11f46789 | 148 | #endif |
fd0f2f37 YS |
149 | } |
150 | ||
151 | static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port) | |
152 | { | |
153 | u16 val, tmp; | |
154 | ||
155 | r8a66597_write(r8a66597, 0, get_intenb_reg(port)); | |
156 | r8a66597_write(r8a66597, 0, get_intsts_reg(port)); | |
157 | ||
158 | r8a66597_port_power(r8a66597, port, 0); | |
159 | ||
160 | do { | |
161 | tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS; | |
162 | udelay(640); | |
163 | } while (tmp == EDGESTS); | |
164 | ||
165 | val = port ? DRPD : DCFM | DRPD; | |
166 | r8a66597_bclr(r8a66597, val, get_syscfg_reg(port)); | |
167 | r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port)); | |
168 | } | |
169 | ||
170 | static int enable_controller(struct r8a66597 *r8a66597) | |
171 | { | |
172 | int ret, port; | |
173 | ||
174 | ret = r8a66597_clock_enable(r8a66597); | |
175 | if (ret < 0) | |
176 | return ret; | |
177 | ||
11f46789 | 178 | #if !defined(CONFIG_RZA_USB) |
9d034208 | 179 | r8a66597_bset(r8a66597, CONFIG_R8A66597_LDRV & LDRV, PINCFG); |
11f46789 | 180 | #endif |
fd0f2f37 YS |
181 | r8a66597_bset(r8a66597, USBE, SYSCFG0); |
182 | ||
183 | r8a66597_bset(r8a66597, INTL, SOFCFG); | |
184 | r8a66597_write(r8a66597, 0, INTENB0); | |
8ecdce72 | 185 | for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) |
186 | r8a66597_write(r8a66597, 0, get_intenb_reg(port)); | |
fd0f2f37 | 187 | |
9d034208 NI |
188 | r8a66597_bset(r8a66597, CONFIG_R8A66597_ENDIAN & BIGEND, CFIFOSEL); |
189 | r8a66597_bset(r8a66597, CONFIG_R8A66597_ENDIAN & BIGEND, D0FIFOSEL); | |
190 | r8a66597_bset(r8a66597, CONFIG_R8A66597_ENDIAN & BIGEND, D1FIFOSEL); | |
fd0f2f37 YS |
191 | r8a66597_bset(r8a66597, TRNENSEL, SOFCFG); |
192 | ||
193 | for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) | |
194 | r8a66597_enable_port(r8a66597, port); | |
195 | ||
196 | return 0; | |
197 | } | |
198 | ||
199 | static void disable_controller(struct r8a66597 *r8a66597) | |
200 | { | |
201 | int i; | |
202 | ||
203 | if (!(r8a66597_read(r8a66597, SYSCFG0) & USBE)) | |
204 | return; | |
205 | ||
206 | r8a66597_write(r8a66597, 0, INTENB0); | |
207 | r8a66597_write(r8a66597, 0, INTSTS0); | |
208 | ||
209 | r8a66597_write(r8a66597, 0, D0FIFOSEL); | |
210 | r8a66597_write(r8a66597, 0, D1FIFOSEL); | |
211 | r8a66597_write(r8a66597, 0, DCPCFG); | |
212 | r8a66597_write(r8a66597, 0x40, DCPMAXP); | |
213 | r8a66597_write(r8a66597, 0, DCPCTR); | |
214 | ||
215 | for (i = 0; i <= 10; i++) | |
216 | r8a66597_write(r8a66597, 0, get_devadd_addr(i)); | |
217 | for (i = 1; i <= 5; i++) { | |
218 | r8a66597_write(r8a66597, 0, get_pipetre_addr(i)); | |
219 | r8a66597_write(r8a66597, 0, get_pipetrn_addr(i)); | |
220 | } | |
221 | for (i = 1; i < R8A66597_MAX_NUM_PIPE; i++) { | |
222 | r8a66597_write(r8a66597, 0, get_pipectr_addr(i)); | |
223 | r8a66597_write(r8a66597, i, PIPESEL); | |
224 | r8a66597_write(r8a66597, 0, PIPECFG); | |
225 | r8a66597_write(r8a66597, 0, PIPEBUF); | |
226 | r8a66597_write(r8a66597, 0, PIPEMAXP); | |
227 | r8a66597_write(r8a66597, 0, PIPEPERI); | |
228 | } | |
229 | ||
230 | for (i = 0; i < R8A66597_MAX_ROOT_HUB; i++) | |
231 | r8a66597_disable_port(r8a66597, i); | |
232 | ||
233 | r8a66597_clock_disable(r8a66597); | |
234 | } | |
235 | ||
236 | static void r8a66597_reg_wait(struct r8a66597 *r8a66597, unsigned long reg, | |
237 | u16 mask, u16 loop) | |
238 | { | |
239 | u16 tmp; | |
240 | int i = 0; | |
241 | ||
242 | do { | |
243 | tmp = r8a66597_read(r8a66597, reg); | |
244 | if (i++ > 1000000) { | |
245 | printf("register%lx, loop %x is timeout\n", reg, loop); | |
246 | break; | |
247 | } | |
248 | } while ((tmp & mask) != loop); | |
249 | } | |
250 | ||
251 | static void pipe_buffer_setting(struct r8a66597 *r8a66597, | |
252 | struct usb_device *dev, unsigned long pipe) | |
253 | { | |
254 | u16 val = 0; | |
255 | u16 pipenum, bufnum, maxpacket; | |
256 | ||
257 | if (usb_pipein(pipe)) { | |
258 | pipenum = BULK_IN_PIPENUM; | |
259 | bufnum = BULK_IN_BUFNUM; | |
260 | maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)]; | |
261 | } else { | |
262 | pipenum = BULK_OUT_PIPENUM; | |
263 | bufnum = BULK_OUT_BUFNUM; | |
264 | maxpacket = dev->epmaxpacketout[usb_pipeendpoint(pipe)]; | |
265 | } | |
266 | ||
267 | if (r8a66597->pipe_config & (1 << pipenum)) | |
268 | return; | |
269 | r8a66597->pipe_config |= (1 << pipenum); | |
270 | ||
271 | r8a66597_bset(r8a66597, ACLRM, get_pipectr_addr(pipenum)); | |
272 | r8a66597_bclr(r8a66597, ACLRM, get_pipectr_addr(pipenum)); | |
273 | r8a66597_write(r8a66597, pipenum, PIPESEL); | |
274 | ||
275 | /* FIXME: This driver support bulk transfer only. */ | |
276 | if (!usb_pipein(pipe)) | |
277 | val |= R8A66597_DIR; | |
278 | else | |
279 | val |= R8A66597_SHTNAK; | |
280 | val |= R8A66597_BULK | R8A66597_DBLB | usb_pipeendpoint(pipe); | |
281 | r8a66597_write(r8a66597, val, PIPECFG); | |
282 | ||
283 | r8a66597_write(r8a66597, (8 << 10) | bufnum, PIPEBUF); | |
284 | r8a66597_write(r8a66597, make_devsel(usb_pipedevice(pipe)) | | |
285 | maxpacket, PIPEMAXP); | |
286 | r8a66597_write(r8a66597, 0, PIPEPERI); | |
287 | r8a66597_write(r8a66597, SQCLR, get_pipectr_addr(pipenum)); | |
288 | } | |
289 | ||
290 | static int send_setup_packet(struct r8a66597 *r8a66597, struct usb_device *dev, | |
291 | struct devrequest *setup) | |
292 | { | |
293 | int i; | |
294 | unsigned short *p = (unsigned short *)setup; | |
295 | unsigned long setup_addr = USBREQ; | |
296 | u16 intsts1; | |
297 | int timeout = 3000; | |
11f46789 CB |
298 | #if defined(CONFIG_RZA_USB) |
299 | u16 dcpctr; | |
11f46789 | 300 | #endif |
fd0f2f37 YS |
301 | u16 devsel = setup->request == USB_REQ_SET_ADDRESS ? 0 : dev->devnum; |
302 | ||
303 | r8a66597_write(r8a66597, make_devsel(devsel) | | |
304 | (8 << dev->maxpacketsize), DCPMAXP); | |
305 | r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1); | |
306 | ||
11f46789 CB |
307 | #if defined(CONFIG_RZA_USB) |
308 | dcpctr = r8a66597_read(r8a66597, DCPCTR); | |
309 | if ((dcpctr & PID) == PID_BUF) { | |
243fd642 CB |
310 | if (readw_poll_timeout(r8a66597->reg + DCPCTR, dcpctr, |
311 | dcpctr & BSTS, 1000) < 0) { | |
312 | printf("DCPCTR BSTS timeout!\n"); | |
313 | return -ETIMEDOUT; | |
11f46789 CB |
314 | } |
315 | } | |
316 | #endif | |
317 | ||
fd0f2f37 YS |
318 | for (i = 0; i < 4; i++) { |
319 | r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr); | |
320 | setup_addr += 2; | |
321 | } | |
322 | r8a66597_write(r8a66597, ~0x0001, BRDYSTS); | |
323 | r8a66597_write(r8a66597, SUREQ, DCPCTR); | |
324 | ||
325 | while (1) { | |
326 | intsts1 = r8a66597_read(r8a66597, INTSTS1); | |
327 | if (intsts1 & SACK) | |
328 | break; | |
329 | if (intsts1 & SIGN) { | |
330 | printf("setup packet send error\n"); | |
331 | return -1; | |
332 | } | |
333 | if (timeout-- < 0) { | |
334 | printf("setup packet timeout\n"); | |
335 | return -1; | |
336 | } | |
337 | udelay(500); | |
338 | } | |
339 | ||
340 | return 0; | |
341 | } | |
342 | ||
343 | static int send_bulk_packet(struct r8a66597 *r8a66597, struct usb_device *dev, | |
344 | unsigned long pipe, void *buffer, int transfer_len) | |
345 | { | |
346 | u16 tmp, bufsize; | |
347 | u16 *buf; | |
348 | size_t size; | |
349 | ||
350 | R8A66597_DPRINT("%s\n", __func__); | |
351 | ||
352 | r8a66597_mdfy(r8a66597, MBW | BULK_OUT_PIPENUM, | |
353 | MBW | CURPIPE, CFIFOSEL); | |
354 | r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, BULK_OUT_PIPENUM); | |
355 | tmp = r8a66597_read(r8a66597, CFIFOCTR); | |
356 | if ((tmp & FRDY) == 0) { | |
357 | printf("%s FRDY is not set (%x)\n", __func__, tmp); | |
358 | return -1; | |
359 | } | |
360 | ||
361 | /* prepare parameters */ | |
362 | bufsize = dev->epmaxpacketout[usb_pipeendpoint(pipe)]; | |
363 | buf = (u16 *)(buffer + dev->act_len); | |
364 | size = min((int)bufsize, transfer_len - dev->act_len); | |
365 | ||
366 | /* write fifo */ | |
367 | r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS); | |
368 | if (buffer) { | |
369 | r8a66597_write_fifo(r8a66597, CFIFO, buf, size); | |
370 | r8a66597_write(r8a66597, BVAL, CFIFOCTR); | |
371 | } | |
372 | ||
373 | /* update parameters */ | |
374 | dev->act_len += size; | |
375 | ||
376 | r8a66597_mdfy(r8a66597, PID_BUF, PID, | |
377 | get_pipectr_addr(BULK_OUT_PIPENUM)); | |
378 | ||
379 | while (!(r8a66597_read(r8a66597, BEMPSTS) & (1 << BULK_OUT_PIPENUM))) | |
380 | if (ctrlc()) | |
381 | return -1; | |
382 | r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS); | |
383 | ||
384 | if (dev->act_len >= transfer_len) | |
385 | r8a66597_mdfy(r8a66597, PID_NAK, PID, | |
386 | get_pipectr_addr(BULK_OUT_PIPENUM)); | |
387 | ||
388 | return 0; | |
389 | } | |
390 | ||
391 | static int receive_bulk_packet(struct r8a66597 *r8a66597, | |
392 | struct usb_device *dev, | |
393 | unsigned long pipe, | |
394 | void *buffer, int transfer_len) | |
395 | { | |
396 | u16 tmp; | |
397 | u16 *buf; | |
398 | const u16 pipenum = BULK_IN_PIPENUM; | |
399 | int rcv_len; | |
400 | int maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)]; | |
401 | ||
402 | R8A66597_DPRINT("%s\n", __func__); | |
403 | ||
404 | /* prepare */ | |
405 | if (dev->act_len == 0) { | |
406 | r8a66597_mdfy(r8a66597, PID_NAK, PID, | |
407 | get_pipectr_addr(pipenum)); | |
408 | r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS); | |
409 | ||
410 | r8a66597_write(r8a66597, TRCLR, get_pipetre_addr(pipenum)); | |
411 | r8a66597_write(r8a66597, | |
412 | (transfer_len + maxpacket - 1) / maxpacket, | |
413 | get_pipetrn_addr(pipenum)); | |
414 | r8a66597_bset(r8a66597, TRENB, get_pipetre_addr(pipenum)); | |
415 | ||
416 | r8a66597_mdfy(r8a66597, PID_BUF, PID, | |
417 | get_pipectr_addr(pipenum)); | |
418 | } | |
419 | ||
420 | r8a66597_mdfy(r8a66597, MBW | pipenum, MBW | CURPIPE, CFIFOSEL); | |
421 | r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum); | |
422 | ||
423 | while (!(r8a66597_read(r8a66597, BRDYSTS) & (1 << pipenum))) | |
424 | if (ctrlc()) | |
425 | return -1; | |
426 | r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS); | |
427 | ||
428 | tmp = r8a66597_read(r8a66597, CFIFOCTR); | |
429 | if ((tmp & FRDY) == 0) { | |
430 | printf("%s FRDY is not set. (%x)\n", __func__, tmp); | |
431 | return -1; | |
432 | } | |
433 | ||
434 | buf = (u16 *)(buffer + dev->act_len); | |
435 | rcv_len = tmp & DTLN; | |
436 | dev->act_len += rcv_len; | |
437 | ||
438 | if (buffer) { | |
439 | if (rcv_len == 0) | |
440 | r8a66597_write(r8a66597, BCLR, CFIFOCTR); | |
441 | else | |
442 | r8a66597_read_fifo(r8a66597, CFIFO, buf, rcv_len); | |
443 | } | |
444 | ||
445 | return 0; | |
446 | } | |
447 | ||
448 | static int receive_control_packet(struct r8a66597 *r8a66597, | |
449 | struct usb_device *dev, | |
450 | void *buffer, int transfer_len) | |
451 | { | |
452 | u16 tmp; | |
453 | int rcv_len; | |
454 | ||
455 | /* FIXME: limit transfer size : 64byte or less */ | |
456 | ||
457 | r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG); | |
458 | r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL); | |
459 | r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); | |
460 | r8a66597_bset(r8a66597, SQSET, DCPCTR); | |
461 | r8a66597_write(r8a66597, BCLR, CFIFOCTR); | |
462 | r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR); | |
463 | ||
464 | while (!(r8a66597_read(r8a66597, BRDYSTS) & 0x0001)) | |
465 | if (ctrlc()) | |
466 | return -1; | |
467 | r8a66597_write(r8a66597, ~0x0001, BRDYSTS); | |
468 | ||
469 | r8a66597_mdfy(r8a66597, MBW, MBW | CURPIPE, CFIFOSEL); | |
470 | r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); | |
471 | ||
472 | tmp = r8a66597_read(r8a66597, CFIFOCTR); | |
473 | if ((tmp & FRDY) == 0) { | |
474 | printf("%s FRDY is not set. (%x)\n", __func__, tmp); | |
475 | return -1; | |
476 | } | |
477 | ||
478 | rcv_len = tmp & DTLN; | |
479 | dev->act_len += rcv_len; | |
480 | ||
481 | r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR); | |
482 | ||
483 | if (buffer) { | |
484 | if (rcv_len == 0) | |
485 | r8a66597_write(r8a66597, BCLR, DCPCTR); | |
486 | else | |
487 | r8a66597_read_fifo(r8a66597, CFIFO, buffer, rcv_len); | |
488 | } | |
489 | ||
490 | return 0; | |
491 | } | |
492 | ||
493 | static int send_status_packet(struct r8a66597 *r8a66597, | |
494 | unsigned long pipe) | |
495 | { | |
496 | r8a66597_bset(r8a66597, SQSET, DCPCTR); | |
497 | r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR); | |
498 | ||
499 | if (usb_pipein(pipe)) { | |
500 | r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG); | |
501 | r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL); | |
502 | r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); | |
503 | r8a66597_write(r8a66597, ~BEMP0, BEMPSTS); | |
504 | r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR); | |
505 | } else { | |
506 | r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG); | |
507 | r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL); | |
508 | r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); | |
509 | r8a66597_write(r8a66597, BCLR, CFIFOCTR); | |
510 | } | |
511 | r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR); | |
512 | ||
513 | while (!(r8a66597_read(r8a66597, BEMPSTS) & 0x0001)) | |
514 | if (ctrlc()) | |
515 | return -1; | |
516 | ||
517 | return 0; | |
518 | } | |
519 | ||
520 | static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port) | |
521 | { | |
522 | int count = R8A66597_MAX_SAMPLING; | |
523 | unsigned short syssts, old_syssts; | |
524 | ||
525 | R8A66597_DPRINT("%s\n", __func__); | |
526 | ||
527 | old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST); | |
528 | while (count > 0) { | |
5b84dd67 | 529 | mdelay(R8A66597_RH_POLL_TIME); |
fd0f2f37 YS |
530 | |
531 | syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST); | |
532 | if (syssts == old_syssts) { | |
533 | count--; | |
534 | } else { | |
535 | count = R8A66597_MAX_SAMPLING; | |
536 | old_syssts = syssts; | |
537 | } | |
538 | } | |
539 | } | |
540 | ||
541 | static void r8a66597_bus_reset(struct r8a66597 *r8a66597, int port) | |
542 | { | |
5b84dd67 | 543 | mdelay(10); |
fd0f2f37 | 544 | r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT, get_dvstctr_reg(port)); |
5b84dd67 | 545 | mdelay(50); |
fd0f2f37 | 546 | r8a66597_mdfy(r8a66597, UACT, USBRST | UACT, get_dvstctr_reg(port)); |
5b84dd67 | 547 | mdelay(50); |
fd0f2f37 YS |
548 | } |
549 | ||
550 | static int check_usb_device_connecting(struct r8a66597 *r8a66597) | |
551 | { | |
552 | int timeout = 10000; /* 100usec * 10000 = 1sec */ | |
553 | int i; | |
554 | ||
555 | for (i = 0; i < 5; i++) { | |
556 | /* check a usb cable connect */ | |
557 | while (!(r8a66597_read(r8a66597, INTSTS1) & ATTCH)) { | |
558 | if (timeout-- < 0) { | |
559 | printf("%s timeout.\n", __func__); | |
560 | return -1; | |
561 | } | |
562 | udelay(100); | |
563 | } | |
564 | ||
565 | /* check a data line */ | |
566 | r8a66597_check_syssts(r8a66597, 0); | |
567 | ||
568 | r8a66597_bus_reset(r8a66597, 0); | |
569 | r8a66597->speed = get_rh_usb_speed(r8a66597, 0); | |
570 | ||
571 | if (!(r8a66597_read(r8a66597, INTSTS1) & DTCH)) { | |
572 | r8a66597->port_change = USB_PORT_STAT_C_CONNECTION; | |
573 | r8a66597->port_status = USB_PORT_STAT_CONNECTION | | |
574 | USB_PORT_STAT_ENABLE; | |
575 | return 0; /* success */ | |
576 | } | |
577 | ||
578 | R8A66597_DPRINT("USB device has detached. retry = %d\n", i); | |
579 | r8a66597_write(r8a66597, ~DTCH, INTSTS1); | |
580 | } | |
581 | ||
582 | return -1; /* fail */ | |
583 | } | |
584 | ||
fd0f2f37 YS |
585 | /*-------------------------------------------------------------------------* |
586 | * Virtual Root Hub | |
587 | *-------------------------------------------------------------------------*/ | |
588 | ||
eb838e7d | 589 | #include <usbroothubdes.h> |
fd0f2f37 YS |
590 | |
591 | static int r8a66597_submit_rh_msg(struct usb_device *dev, unsigned long pipe, | |
592 | void *buffer, int transfer_len, struct devrequest *cmd) | |
593 | { | |
594 | struct r8a66597 *r8a66597 = &gr8a66597; | |
595 | int leni = transfer_len; | |
596 | int len = 0; | |
597 | int stat = 0; | |
598 | __u16 bmRType_bReq; | |
599 | __u16 wValue; | |
fd0f2f37 YS |
600 | __u16 wLength; |
601 | unsigned char data[32]; | |
602 | ||
603 | R8A66597_DPRINT("%s\n", __func__); | |
604 | ||
9dbc3667 | 605 | if (usb_pipeint(pipe)) { |
fd0f2f37 YS |
606 | printf("Root-Hub submit IRQ: NOT implemented"); |
607 | return 0; | |
608 | } | |
609 | ||
610 | bmRType_bReq = cmd->requesttype | (cmd->request << 8); | |
611 | wValue = cpu_to_le16 (cmd->value); | |
fd0f2f37 YS |
612 | wLength = cpu_to_le16 (cmd->length); |
613 | ||
614 | switch (bmRType_bReq) { | |
615 | case RH_GET_STATUS: | |
616 | *(__u16 *)buffer = cpu_to_le16(1); | |
617 | len = 2; | |
618 | break; | |
619 | case RH_GET_STATUS | RH_INTERFACE: | |
620 | *(__u16 *)buffer = cpu_to_le16(0); | |
621 | len = 2; | |
622 | break; | |
623 | case RH_GET_STATUS | RH_ENDPOINT: | |
624 | *(__u16 *)buffer = cpu_to_le16(0); | |
625 | len = 2; | |
626 | break; | |
627 | case RH_GET_STATUS | RH_CLASS: | |
628 | *(__u32 *)buffer = cpu_to_le32(0); | |
629 | len = 4; | |
630 | break; | |
631 | case RH_GET_STATUS | RH_OTHER | RH_CLASS: | |
632 | *(__u32 *)buffer = cpu_to_le32(r8a66597->port_status | | |
633 | (r8a66597->port_change << 16)); | |
634 | len = 4; | |
635 | break; | |
636 | case RH_CLEAR_FEATURE | RH_ENDPOINT: | |
637 | case RH_CLEAR_FEATURE | RH_CLASS: | |
638 | break; | |
639 | ||
640 | case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: | |
641 | switch (wValue) { | |
642 | case RH_C_PORT_CONNECTION: | |
643 | r8a66597->port_change &= ~USB_PORT_STAT_C_CONNECTION; | |
644 | break; | |
645 | } | |
646 | break; | |
647 | ||
648 | case RH_SET_FEATURE | RH_OTHER | RH_CLASS: | |
649 | switch (wValue) { | |
650 | case (RH_PORT_SUSPEND): | |
651 | break; | |
652 | case (RH_PORT_RESET): | |
653 | r8a66597_bus_reset(r8a66597, 0); | |
654 | break; | |
655 | case (RH_PORT_POWER): | |
656 | break; | |
657 | case (RH_PORT_ENABLE): | |
658 | break; | |
659 | } | |
660 | break; | |
661 | case RH_SET_ADDRESS: | |
662 | gr8a66597.rh_devnum = wValue; | |
663 | break; | |
664 | case RH_GET_DESCRIPTOR: | |
665 | switch ((wValue & 0xff00) >> 8) { | |
666 | case (0x01): /* device descriptor */ | |
667 | len = min_t(unsigned int, | |
668 | leni, | |
669 | min_t(unsigned int, | |
670 | sizeof(root_hub_dev_des), | |
671 | wLength)); | |
672 | memcpy(buffer, root_hub_dev_des, len); | |
673 | break; | |
674 | case (0x02): /* configuration descriptor */ | |
675 | len = min_t(unsigned int, | |
676 | leni, | |
677 | min_t(unsigned int, | |
678 | sizeof(root_hub_config_des), | |
679 | wLength)); | |
680 | memcpy(buffer, root_hub_config_des, len); | |
681 | break; | |
682 | case (0x03): /* string descriptors */ | |
683 | if (wValue == 0x0300) { | |
684 | len = min_t(unsigned int, | |
685 | leni, | |
686 | min_t(unsigned int, | |
687 | sizeof(root_hub_str_index0), | |
688 | wLength)); | |
689 | memcpy(buffer, root_hub_str_index0, len); | |
690 | } | |
691 | if (wValue == 0x0301) { | |
692 | len = min_t(unsigned int, | |
693 | leni, | |
694 | min_t(unsigned int, | |
695 | sizeof(root_hub_str_index1), | |
696 | wLength)); | |
697 | memcpy(buffer, root_hub_str_index1, len); | |
698 | } | |
699 | break; | |
700 | default: | |
701 | stat = USB_ST_STALLED; | |
702 | } | |
703 | break; | |
704 | ||
705 | case RH_GET_DESCRIPTOR | RH_CLASS: | |
706 | { | |
707 | __u32 temp = 0x00000001; | |
708 | ||
709 | data[0] = 9; /* min length; */ | |
710 | data[1] = 0x29; | |
711 | data[2] = temp & RH_A_NDP; | |
712 | data[3] = 0; | |
713 | if (temp & RH_A_PSM) | |
714 | data[3] |= 0x1; | |
715 | if (temp & RH_A_NOCP) | |
716 | data[3] |= 0x10; | |
717 | else if (temp & RH_A_OCPM) | |
718 | data[3] |= 0x8; | |
719 | ||
720 | /* corresponds to data[4-7] */ | |
721 | data[5] = (temp & RH_A_POTPGT) >> 24; | |
722 | data[7] = temp & RH_B_DR; | |
723 | if (data[2] < 7) { | |
724 | data[8] = 0xff; | |
725 | } else { | |
726 | data[0] += 2; | |
727 | data[8] = (temp & RH_B_DR) >> 8; | |
728 | data[10] = data[9] = 0xff; | |
729 | } | |
730 | ||
731 | len = min_t(unsigned int, leni, | |
732 | min_t(unsigned int, data[0], wLength)); | |
733 | memcpy(buffer, data, len); | |
734 | break; | |
735 | } | |
736 | ||
737 | case RH_GET_CONFIGURATION: | |
738 | *(__u8 *) buffer = 0x01; | |
739 | len = 1; | |
740 | break; | |
741 | case RH_SET_CONFIGURATION: | |
742 | break; | |
743 | default: | |
e58c41e2 | 744 | R8A66597_DPRINT("unsupported root hub command"); |
fd0f2f37 YS |
745 | stat = USB_ST_STALLED; |
746 | } | |
747 | ||
5b84dd67 | 748 | mdelay(1); |
fd0f2f37 YS |
749 | |
750 | len = min_t(int, len, leni); | |
751 | ||
752 | dev->act_len = len; | |
753 | dev->status = stat; | |
754 | ||
755 | return stat; | |
756 | } | |
757 | ||
758 | int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, | |
759 | int transfer_len) | |
760 | { | |
761 | struct r8a66597 *r8a66597 = &gr8a66597; | |
762 | int ret = 0; | |
763 | ||
764 | R8A66597_DPRINT("%s\n", __func__); | |
765 | R8A66597_DPRINT("pipe = %08x, buffer = %p, len = %d, devnum = %d\n", | |
766 | pipe, buffer, transfer_len, dev->devnum); | |
767 | ||
60ece6d8 | 768 | set_devadd(r8a66597, dev->devnum, dev, 0); |
fd0f2f37 YS |
769 | |
770 | pipe_buffer_setting(r8a66597, dev, pipe); | |
771 | ||
772 | dev->act_len = 0; | |
773 | while (dev->act_len < transfer_len && ret == 0) { | |
774 | if (ctrlc()) | |
775 | return -1; | |
776 | ||
777 | if (usb_pipein(pipe)) | |
778 | ret = receive_bulk_packet(r8a66597, dev, pipe, buffer, | |
779 | transfer_len); | |
780 | else | |
781 | ret = send_bulk_packet(r8a66597, dev, pipe, buffer, | |
782 | transfer_len); | |
783 | } | |
784 | ||
785 | if (ret == 0) | |
786 | dev->status = 0; | |
787 | ||
788 | return ret; | |
789 | } | |
790 | ||
791 | int submit_control_msg(struct usb_device *dev, unsigned long pipe, | |
792 | void *buffer, int transfer_len, struct devrequest *setup) | |
793 | { | |
794 | struct r8a66597 *r8a66597 = &gr8a66597; | |
795 | u16 r8a66597_address = setup->request == USB_REQ_SET_ADDRESS ? | |
796 | 0 : dev->devnum; | |
797 | ||
798 | R8A66597_DPRINT("%s\n", __func__); | |
799 | if (usb_pipedevice(pipe) == r8a66597->rh_devnum) | |
800 | return r8a66597_submit_rh_msg(dev, pipe, buffer, transfer_len, | |
801 | setup); | |
802 | ||
803 | R8A66597_DPRINT("%s: setup\n", __func__); | |
60ece6d8 | 804 | set_devadd(r8a66597, r8a66597_address, dev, 0); |
fd0f2f37 YS |
805 | |
806 | if (send_setup_packet(r8a66597, dev, setup) < 0) { | |
807 | printf("setup packet send error\n"); | |
808 | return -1; | |
809 | } | |
810 | ||
60ece6d8 | 811 | dev->act_len = 0; |
fd0f2f37 YS |
812 | if (usb_pipein(pipe)) |
813 | if (receive_control_packet(r8a66597, dev, buffer, | |
814 | transfer_len) < 0) | |
815 | return -1; | |
816 | ||
817 | if (send_status_packet(r8a66597, pipe) < 0) | |
818 | return -1; | |
819 | ||
820 | dev->status = 0; | |
821 | ||
822 | return 0; | |
823 | } | |
824 | ||
825 | int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, | |
826 | int transfer_len, int interval) | |
827 | { | |
828 | /* no implement */ | |
829 | R8A66597_DPRINT("%s\n", __func__); | |
830 | return 0; | |
831 | } | |
832 | ||
06d513ec | 833 | int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) |
fd0f2f37 YS |
834 | { |
835 | struct r8a66597 *r8a66597 = &gr8a66597; | |
836 | ||
837 | R8A66597_DPRINT("%s\n", __func__); | |
838 | ||
198c5f99 | 839 | memset(r8a66597, 0, sizeof(*r8a66597)); |
fd0f2f37 YS |
840 | r8a66597->reg = CONFIG_R8A66597_BASE_ADDR; |
841 | ||
842 | disable_controller(r8a66597); | |
5b84dd67 | 843 | mdelay(100); |
fd0f2f37 YS |
844 | |
845 | enable_controller(r8a66597); | |
846 | r8a66597_port_power(r8a66597, 0 , 1); | |
847 | ||
848 | /* check usb device */ | |
849 | check_usb_device_connecting(r8a66597); | |
850 | ||
5b84dd67 | 851 | mdelay(50); |
fd0f2f37 YS |
852 | |
853 | return 0; | |
854 | } | |
855 | ||
c7e3b2b5 | 856 | int usb_lowlevel_stop(int index) |
fd0f2f37 YS |
857 | { |
858 | disable_controller(&gr8a66597); | |
859 | ||
860 | return 0; | |
861 | } |