diff options
Diffstat (limited to 'drivers/usb/host/fhci-tds.c')
-rw-r--r-- | drivers/usb/host/fhci-tds.c | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c new file mode 100644 index 000000000000..b40332290319 --- /dev/null +++ b/drivers/usb/host/fhci-tds.c | |||
@@ -0,0 +1,626 @@ | |||
1 | /* | ||
2 | * Freescale QUICC Engine USB Host Controller Driver | ||
3 | * | ||
4 | * Copyright (c) Freescale Semicondutor, Inc. 2006. | ||
5 | * Shlomi Gridish <gridish@freescale.com> | ||
6 | * Jerry Huang <Chang-Ming.Huang@freescale.com> | ||
7 | * Copyright (c) Logic Product Development, Inc. 2007 | ||
8 | * Peter Barada <peterb@logicpd.com> | ||
9 | * Copyright (c) MontaVista Software, Inc. 2008. | ||
10 | * Anton Vorontsov <avorontsov@ru.mvista.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/list.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/usb.h> | ||
24 | #include "../core/hcd.h" | ||
25 | #include "fhci.h" | ||
26 | |||
27 | #define DUMMY_BD_BUFFER 0xdeadbeef | ||
28 | #define DUMMY2_BD_BUFFER 0xbaadf00d | ||
29 | |||
30 | /* Transaction Descriptors bits */ | ||
31 | #define TD_R 0x8000 /* ready bit */ | ||
32 | #define TD_W 0x2000 /* wrap bit */ | ||
33 | #define TD_I 0x1000 /* interrupt on completion */ | ||
34 | #define TD_L 0x0800 /* last */ | ||
35 | #define TD_TC 0x0400 /* transmit CRC */ | ||
36 | #define TD_CNF 0x0200 /* CNF - Must be always 1 */ | ||
37 | #define TD_LSP 0x0100 /* Low-speed transaction */ | ||
38 | #define TD_PID 0x00c0 /* packet id */ | ||
39 | #define TD_RXER 0x0020 /* Rx error or not */ | ||
40 | |||
41 | #define TD_NAK 0x0010 /* No ack. */ | ||
42 | #define TD_STAL 0x0008 /* Stall recieved */ | ||
43 | #define TD_TO 0x0004 /* time out */ | ||
44 | #define TD_UN 0x0002 /* underrun */ | ||
45 | #define TD_NO 0x0010 /* Rx Non Octet Aligned Packet */ | ||
46 | #define TD_AB 0x0008 /* Frame Aborted */ | ||
47 | #define TD_CR 0x0004 /* CRC Error */ | ||
48 | #define TD_OV 0x0002 /* Overrun */ | ||
49 | #define TD_BOV 0x0001 /* Buffer Overrun */ | ||
50 | |||
51 | #define TD_ERRORS (TD_NAK | TD_STAL | TD_TO | TD_UN | \ | ||
52 | TD_NO | TD_AB | TD_CR | TD_OV | TD_BOV) | ||
53 | |||
54 | #define TD_PID_DATA0 0x0080 /* Data 0 toggle */ | ||
55 | #define TD_PID_DATA1 0x00c0 /* Data 1 toggle */ | ||
56 | #define TD_PID_TOGGLE 0x00c0 /* Data 0/1 toggle mask */ | ||
57 | |||
58 | #define TD_TOK_SETUP 0x0000 | ||
59 | #define TD_TOK_OUT 0x4000 | ||
60 | #define TD_TOK_IN 0x8000 | ||
61 | #define TD_ISO 0x1000 | ||
62 | #define TD_ENDP 0x0780 | ||
63 | #define TD_ADDR 0x007f | ||
64 | |||
65 | #define TD_ENDP_SHIFT 7 | ||
66 | |||
67 | struct usb_td { | ||
68 | __be16 status; | ||
69 | __be16 length; | ||
70 | __be32 buf_ptr; | ||
71 | __be16 extra; | ||
72 | __be16 reserved; | ||
73 | }; | ||
74 | |||
75 | static struct usb_td __iomem *next_bd(struct usb_td __iomem *base, | ||
76 | struct usb_td __iomem *td, | ||
77 | u16 status) | ||
78 | { | ||
79 | if (status & TD_W) | ||
80 | return base; | ||
81 | else | ||
82 | return ++td; | ||
83 | } | ||
84 | |||
85 | void fhci_push_dummy_bd(struct endpoint *ep) | ||
86 | { | ||
87 | if (ep->already_pushed_dummy_bd == false) { | ||
88 | u16 td_status = in_be16(&ep->empty_td->status); | ||
89 | |||
90 | out_be32(&ep->empty_td->buf_ptr, DUMMY_BD_BUFFER); | ||
91 | /* get the next TD in the ring */ | ||
92 | ep->empty_td = next_bd(ep->td_base, ep->empty_td, td_status); | ||
93 | ep->already_pushed_dummy_bd = true; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | /* destroy an USB endpoint */ | ||
98 | void fhci_ep0_free(struct fhci_usb *usb) | ||
99 | { | ||
100 | struct endpoint *ep; | ||
101 | int size; | ||
102 | |||
103 | ep = usb->ep0; | ||
104 | if (ep) { | ||
105 | if (ep->td_base) | ||
106 | cpm_muram_free(cpm_muram_offset(ep->td_base)); | ||
107 | |||
108 | if (ep->conf_frame_Q) { | ||
109 | size = cq_howmany(ep->conf_frame_Q); | ||
110 | for (; size; size--) { | ||
111 | struct packet *pkt = cq_get(ep->conf_frame_Q); | ||
112 | |||
113 | kfree(pkt); | ||
114 | } | ||
115 | cq_delete(ep->conf_frame_Q); | ||
116 | } | ||
117 | |||
118 | if (ep->empty_frame_Q) { | ||
119 | size = cq_howmany(ep->empty_frame_Q); | ||
120 | for (; size; size--) { | ||
121 | struct packet *pkt = cq_get(ep->empty_frame_Q); | ||
122 | |||
123 | kfree(pkt); | ||
124 | } | ||
125 | cq_delete(ep->empty_frame_Q); | ||
126 | } | ||
127 | |||
128 | if (ep->dummy_packets_Q) { | ||
129 | size = cq_howmany(ep->dummy_packets_Q); | ||
130 | for (; size; size--) { | ||
131 | u8 *buff = cq_get(ep->dummy_packets_Q); | ||
132 | |||
133 | kfree(buff); | ||
134 | } | ||
135 | cq_delete(ep->dummy_packets_Q); | ||
136 | } | ||
137 | |||
138 | kfree(ep); | ||
139 | usb->ep0 = NULL; | ||
140 | } | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * create the endpoint structure | ||
145 | * | ||
146 | * arguments: | ||
147 | * usb A pointer to the data structure of the USB | ||
148 | * data_mem The data memory partition(BUS) | ||
149 | * ring_len TD ring length | ||
150 | */ | ||
151 | u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem, | ||
152 | u32 ring_len) | ||
153 | { | ||
154 | struct endpoint *ep; | ||
155 | struct usb_td __iomem *td; | ||
156 | unsigned long ep_offset; | ||
157 | char *err_for = "enpoint PRAM"; | ||
158 | int ep_mem_size; | ||
159 | u32 i; | ||
160 | |||
161 | /* we need at least 3 TDs in the ring */ | ||
162 | if (!(ring_len > 2)) { | ||
163 | fhci_err(usb->fhci, "illegal TD ring length parameters\n"); | ||
164 | return -EINVAL; | ||
165 | } | ||
166 | |||
167 | ep = kzalloc(sizeof(*ep), GFP_KERNEL); | ||
168 | if (!ep) | ||
169 | return -ENOMEM; | ||
170 | |||
171 | ep_mem_size = ring_len * sizeof(*td) + sizeof(struct fhci_ep_pram); | ||
172 | ep_offset = cpm_muram_alloc(ep_mem_size, 32); | ||
173 | if (IS_ERR_VALUE(ep_offset)) | ||
174 | goto err; | ||
175 | ep->td_base = cpm_muram_addr(ep_offset); | ||
176 | |||
177 | /* zero all queue pointers */ | ||
178 | ep->conf_frame_Q = cq_new(ring_len + 2); | ||
179 | ep->empty_frame_Q = cq_new(ring_len + 2); | ||
180 | ep->dummy_packets_Q = cq_new(ring_len + 2); | ||
181 | if (!ep->conf_frame_Q || !ep->empty_frame_Q || !ep->dummy_packets_Q) { | ||
182 | err_for = "frame_queues"; | ||
183 | goto err; | ||
184 | } | ||
185 | |||
186 | for (i = 0; i < (ring_len + 1); i++) { | ||
187 | struct packet *pkt; | ||
188 | u8 *buff; | ||
189 | |||
190 | pkt = kmalloc(sizeof(*pkt), GFP_KERNEL); | ||
191 | if (!pkt) { | ||
192 | err_for = "frame"; | ||
193 | goto err; | ||
194 | } | ||
195 | |||
196 | buff = kmalloc(1028 * sizeof(*buff), GFP_KERNEL); | ||
197 | if (!buff) { | ||
198 | kfree(pkt); | ||
199 | err_for = "buffer"; | ||
200 | goto err; | ||
201 | } | ||
202 | cq_put(ep->empty_frame_Q, pkt); | ||
203 | cq_put(ep->dummy_packets_Q, buff); | ||
204 | } | ||
205 | |||
206 | /* we put the endpoint parameter RAM right behind the TD ring */ | ||
207 | ep->ep_pram_ptr = (void __iomem *)ep->td_base + sizeof(*td) * ring_len; | ||
208 | |||
209 | ep->conf_td = ep->td_base; | ||
210 | ep->empty_td = ep->td_base; | ||
211 | |||
212 | ep->already_pushed_dummy_bd = false; | ||
213 | |||
214 | /* initialize tds */ | ||
215 | td = ep->td_base; | ||
216 | for (i = 0; i < ring_len; i++) { | ||
217 | out_be32(&td->buf_ptr, 0); | ||
218 | out_be16(&td->status, 0); | ||
219 | out_be16(&td->length, 0); | ||
220 | out_be16(&td->extra, 0); | ||
221 | td++; | ||
222 | } | ||
223 | td--; | ||
224 | out_be16(&td->status, TD_W); /* for last TD set Wrap bit */ | ||
225 | out_be16(&td->length, 0); | ||
226 | |||
227 | /* endpoint structure has been created */ | ||
228 | usb->ep0 = ep; | ||
229 | |||
230 | return 0; | ||
231 | err: | ||
232 | fhci_ep0_free(usb); | ||
233 | kfree(ep); | ||
234 | fhci_err(usb->fhci, "no memory for the %s\n", err_for); | ||
235 | return -ENOMEM; | ||
236 | } | ||
237 | |||
238 | /* | ||
239 | * initialize the endpoint register according to the given parameters | ||
240 | * | ||
241 | * artuments: | ||
242 | * usb A pointer to the data strucutre of the USB | ||
243 | * ep A pointer to the endpoint structre | ||
244 | * data_mem The data memory partition(BUS) | ||
245 | */ | ||
246 | void fhci_init_ep_registers(struct fhci_usb *usb, struct endpoint *ep, | ||
247 | enum fhci_mem_alloc data_mem) | ||
248 | { | ||
249 | u8 rt; | ||
250 | |||
251 | /* set the endpoint registers according to the endpoint */ | ||
252 | out_be16(&usb->fhci->regs->usb_ep[0], | ||
253 | USB_TRANS_CTR | USB_EP_MF | USB_EP_RTE); | ||
254 | out_be16(&usb->fhci->pram->ep_ptr[0], | ||
255 | cpm_muram_offset(ep->ep_pram_ptr)); | ||
256 | |||
257 | rt = (BUS_MODE_BO_BE | BUS_MODE_GBL); | ||
258 | #ifdef MULTI_DATA_BUS | ||
259 | if (data_mem == MEM_SECONDARY) | ||
260 | rt |= BUS_MODE_DTB; | ||
261 | #endif | ||
262 | out_8(&ep->ep_pram_ptr->rx_func_code, rt); | ||
263 | out_8(&ep->ep_pram_ptr->tx_func_code, rt); | ||
264 | out_be16(&ep->ep_pram_ptr->rx_buff_len, 1028); | ||
265 | out_be16(&ep->ep_pram_ptr->rx_base, 0); | ||
266 | out_be16(&ep->ep_pram_ptr->tx_base, cpm_muram_offset(ep->td_base)); | ||
267 | out_be16(&ep->ep_pram_ptr->rx_bd_ptr, 0); | ||
268 | out_be16(&ep->ep_pram_ptr->tx_bd_ptr, cpm_muram_offset(ep->td_base)); | ||
269 | out_be32(&ep->ep_pram_ptr->tx_state, 0); | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * Collect the submitted frames and inform the application about them | ||
274 | * It is also prepearing the TDs for new frames. If the Tx interrupts | ||
275 | * are diabled, the application should call that routine to get | ||
276 | * confirmation about the submitted frames. Otherwise, the routine is | ||
277 | * called frome the interrupt service routine during the Tx interrupt. | ||
278 | * In that case the application is informed by calling the application | ||
279 | * specific 'fhci_transaction_confirm' routine | ||
280 | */ | ||
281 | static void fhci_td_transaction_confirm(struct fhci_usb *usb) | ||
282 | { | ||
283 | struct endpoint *ep = usb->ep0; | ||
284 | struct packet *pkt; | ||
285 | struct usb_td __iomem *td; | ||
286 | u16 extra_data; | ||
287 | u16 td_status; | ||
288 | u16 td_length; | ||
289 | u32 buf; | ||
290 | |||
291 | /* | ||
292 | * collect transmitted BDs from the chip. The routine clears all BDs | ||
293 | * with R bit = 0 and the pointer to data buffer is not NULL, that is | ||
294 | * BDs which point to the transmitted data buffer | ||
295 | */ | ||
296 | while (1) { | ||
297 | td = ep->conf_td; | ||
298 | td_status = in_be16(&td->status); | ||
299 | td_length = in_be16(&td->length); | ||
300 | buf = in_be32(&td->buf_ptr); | ||
301 | extra_data = in_be16(&td->extra); | ||
302 | |||
303 | /* check if the TD is empty */ | ||
304 | if (!(!(td_status & TD_R) && ((td_status & ~TD_W) || buf))) | ||
305 | break; | ||
306 | /* check if it is a dummy buffer */ | ||
307 | else if ((buf == DUMMY_BD_BUFFER) && !(td_status & ~TD_W)) | ||
308 | break; | ||
309 | |||
310 | /* mark TD as empty */ | ||
311 | clrbits16(&td->status, ~TD_W); | ||
312 | out_be16(&td->length, 0); | ||
313 | out_be32(&td->buf_ptr, 0); | ||
314 | out_be16(&td->extra, 0); | ||
315 | /* advance the TD pointer */ | ||
316 | ep->conf_td = next_bd(ep->td_base, ep->conf_td, td_status); | ||
317 | |||
318 | /* check if it is a dummy buffer(type2) */ | ||
319 | if ((buf == DUMMY2_BD_BUFFER) && !(td_status & ~TD_W)) | ||
320 | continue; | ||
321 | |||
322 | pkt = cq_get(ep->conf_frame_Q); | ||
323 | if (!pkt) | ||
324 | fhci_err(usb->fhci, "no frame to confirm\n"); | ||
325 | |||
326 | if (td_status & TD_ERRORS) { | ||
327 | if (td_status & TD_RXER) { | ||
328 | if (td_status & TD_CR) | ||
329 | pkt->status = USB_TD_RX_ER_CRC; | ||
330 | else if (td_status & TD_AB) | ||
331 | pkt->status = USB_TD_RX_ER_BITSTUFF; | ||
332 | else if (td_status & TD_OV) | ||
333 | pkt->status = USB_TD_RX_ER_OVERUN; | ||
334 | else if (td_status & TD_BOV) | ||
335 | pkt->status = USB_TD_RX_DATA_OVERUN; | ||
336 | else if (td_status & TD_NO) | ||
337 | pkt->status = USB_TD_RX_ER_NONOCT; | ||
338 | else | ||
339 | fhci_err(usb->fhci, "illegal error " | ||
340 | "occured\n"); | ||
341 | } else if (td_status & TD_NAK) | ||
342 | pkt->status = USB_TD_TX_ER_NAK; | ||
343 | else if (td_status & TD_TO) | ||
344 | pkt->status = USB_TD_TX_ER_TIMEOUT; | ||
345 | else if (td_status & TD_UN) | ||
346 | pkt->status = USB_TD_TX_ER_UNDERUN; | ||
347 | else if (td_status & TD_STAL) | ||
348 | pkt->status = USB_TD_TX_ER_STALL; | ||
349 | else | ||
350 | fhci_err(usb->fhci, "illegal error occured\n"); | ||
351 | } else if ((extra_data & TD_TOK_IN) && | ||
352 | pkt->len > td_length - CRC_SIZE) { | ||
353 | pkt->status = USB_TD_RX_DATA_UNDERUN; | ||
354 | } | ||
355 | |||
356 | if (extra_data & TD_TOK_IN) | ||
357 | pkt->len = td_length - CRC_SIZE; | ||
358 | else if (pkt->info & PKT_ZLP) | ||
359 | pkt->len = 0; | ||
360 | else | ||
361 | pkt->len = td_length; | ||
362 | |||
363 | fhci_transaction_confirm(usb, pkt); | ||
364 | } | ||
365 | } | ||
366 | |||
367 | /* | ||
368 | * Submitting a data frame to a specified endpoint of a USB device | ||
369 | * The frame is put in the driver's transmit queue for this endpoint | ||
370 | * | ||
371 | * Arguments: | ||
372 | * usb A pointer to the USB structure | ||
373 | * pkt A pointer to the user frame structure | ||
374 | * trans_type Transaction tyep - IN,OUT or SETUP | ||
375 | * dest_addr Device address - 0~127 | ||
376 | * dest_ep Endpoint number of the device - 0~16 | ||
377 | * trans_mode Pipe type - ISO,Interrupt,bulk or control | ||
378 | * dest_speed USB speed - Low speed or FULL speed | ||
379 | * data_toggle Data sequence toggle - 0 or 1 | ||
380 | */ | ||
381 | u32 fhci_host_transaction(struct fhci_usb *usb, | ||
382 | struct packet *pkt, | ||
383 | enum fhci_ta_type trans_type, | ||
384 | u8 dest_addr, | ||
385 | u8 dest_ep, | ||
386 | enum fhci_tf_mode trans_mode, | ||
387 | enum fhci_speed dest_speed, u8 data_toggle) | ||
388 | { | ||
389 | struct endpoint *ep = usb->ep0; | ||
390 | struct usb_td __iomem *td; | ||
391 | u16 extra_data; | ||
392 | u16 td_status; | ||
393 | |||
394 | fhci_usb_disable_interrupt(usb); | ||
395 | /* start from the next BD that should be filled */ | ||
396 | td = ep->empty_td; | ||
397 | td_status = in_be16(&td->status); | ||
398 | |||
399 | if (td_status & TD_R && in_be16(&td->length)) { | ||
400 | /* if the TD is not free */ | ||
401 | fhci_usb_enable_interrupt(usb); | ||
402 | return -1; | ||
403 | } | ||
404 | |||
405 | /* get the next TD in the ring */ | ||
406 | ep->empty_td = next_bd(ep->td_base, ep->empty_td, td_status); | ||
407 | fhci_usb_enable_interrupt(usb); | ||
408 | pkt->priv_data = td; | ||
409 | out_be32(&td->buf_ptr, virt_to_phys(pkt->data)); | ||
410 | /* sets up transaction parameters - addr,endp,dir,and type */ | ||
411 | extra_data = (dest_ep << TD_ENDP_SHIFT) | dest_addr; | ||
412 | switch (trans_type) { | ||
413 | case FHCI_TA_IN: | ||
414 | extra_data |= TD_TOK_IN; | ||
415 | break; | ||
416 | case FHCI_TA_OUT: | ||
417 | extra_data |= TD_TOK_OUT; | ||
418 | break; | ||
419 | case FHCI_TA_SETUP: | ||
420 | extra_data |= TD_TOK_SETUP; | ||
421 | break; | ||
422 | } | ||
423 | if (trans_mode == FHCI_TF_ISO) | ||
424 | extra_data |= TD_ISO; | ||
425 | out_be16(&td->extra, extra_data); | ||
426 | |||
427 | /* sets up the buffer descriptor */ | ||
428 | td_status = ((td_status & TD_W) | TD_R | TD_L | TD_I | TD_CNF); | ||
429 | if (!(pkt->info & PKT_NO_CRC)) | ||
430 | td_status |= TD_TC; | ||
431 | |||
432 | switch (trans_type) { | ||
433 | case FHCI_TA_IN: | ||
434 | if (data_toggle) | ||
435 | pkt->info |= PKT_PID_DATA1; | ||
436 | else | ||
437 | pkt->info |= PKT_PID_DATA0; | ||
438 | break; | ||
439 | default: | ||
440 | if (data_toggle) { | ||
441 | td_status |= TD_PID_DATA1; | ||
442 | pkt->info |= PKT_PID_DATA1; | ||
443 | } else { | ||
444 | td_status |= TD_PID_DATA0; | ||
445 | pkt->info |= PKT_PID_DATA0; | ||
446 | } | ||
447 | break; | ||
448 | } | ||
449 | |||
450 | if ((dest_speed == FHCI_LOW_SPEED) && | ||
451 | (usb->port_status == FHCI_PORT_FULL)) | ||
452 | td_status |= TD_LSP; | ||
453 | |||
454 | out_be16(&td->status, td_status); | ||
455 | |||
456 | /* set up buffer length */ | ||
457 | if (trans_type == FHCI_TA_IN) | ||
458 | out_be16(&td->length, pkt->len + CRC_SIZE); | ||
459 | else | ||
460 | out_be16(&td->length, pkt->len); | ||
461 | |||
462 | /* put the frame to the confirmation queue */ | ||
463 | cq_put(ep->conf_frame_Q, pkt); | ||
464 | |||
465 | if (cq_howmany(ep->conf_frame_Q) == 1) | ||
466 | out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO); | ||
467 | |||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | /* Reset the Tx BD ring */ | ||
472 | void fhci_flush_bds(struct fhci_usb *usb) | ||
473 | { | ||
474 | u16 extra_data; | ||
475 | u16 td_status; | ||
476 | u32 buf; | ||
477 | struct usb_td __iomem *td; | ||
478 | struct endpoint *ep = usb->ep0; | ||
479 | |||
480 | td = ep->td_base; | ||
481 | while (1) { | ||
482 | td_status = in_be16(&td->status); | ||
483 | buf = in_be32(&td->buf_ptr); | ||
484 | extra_data = in_be16(&td->extra); | ||
485 | |||
486 | /* if the TD is not empty - we'll confirm it as Timeout */ | ||
487 | if (td_status & TD_R) | ||
488 | out_be16(&td->status, (td_status & ~TD_R) | TD_TO); | ||
489 | /* if this TD is dummy - let's skip this TD */ | ||
490 | else if (in_be32(&td->buf_ptr) == DUMMY_BD_BUFFER) | ||
491 | out_be32(&td->buf_ptr, DUMMY2_BD_BUFFER); | ||
492 | /* if this is the last TD - break */ | ||
493 | if (td_status & TD_W) | ||
494 | break; | ||
495 | |||
496 | td++; | ||
497 | } | ||
498 | |||
499 | fhci_td_transaction_confirm(usb); | ||
500 | |||
501 | td = ep->td_base; | ||
502 | do { | ||
503 | out_be16(&td->status, 0); | ||
504 | out_be16(&td->length, 0); | ||
505 | out_be32(&td->buf_ptr, 0); | ||
506 | out_be16(&td->extra, 0); | ||
507 | td++; | ||
508 | } while (!(in_be16(&td->status) & TD_W)); | ||
509 | out_be16(&td->status, TD_W); /* for last TD set Wrap bit */ | ||
510 | out_be16(&td->length, 0); | ||
511 | out_be32(&td->buf_ptr, 0); | ||
512 | out_be16(&td->extra, 0); | ||
513 | |||
514 | out_be16(&ep->ep_pram_ptr->tx_bd_ptr, | ||
515 | in_be16(&ep->ep_pram_ptr->tx_base)); | ||
516 | out_be32(&ep->ep_pram_ptr->tx_state, 0); | ||
517 | out_be16(&ep->ep_pram_ptr->tx_cnt, 0); | ||
518 | ep->empty_td = ep->td_base; | ||
519 | ep->conf_td = ep->td_base; | ||
520 | } | ||
521 | |||
522 | /* | ||
523 | * Flush all transmitted packets from TDs in the actual frame. | ||
524 | * This routine is called when something wrong with the controller and | ||
525 | * we want to get rid of the actual frame and start again next frame | ||
526 | */ | ||
527 | void fhci_flush_actual_frame(struct fhci_usb *usb) | ||
528 | { | ||
529 | u8 mode; | ||
530 | u16 tb_ptr; | ||
531 | u16 extra_data; | ||
532 | u16 td_status; | ||
533 | u32 buf_ptr; | ||
534 | struct usb_td __iomem *td; | ||
535 | struct endpoint *ep = usb->ep0; | ||
536 | |||
537 | /* disable the USB controller */ | ||
538 | mode = in_8(&usb->fhci->regs->usb_mod); | ||
539 | out_8(&usb->fhci->regs->usb_mod, mode & ~USB_MODE_EN); | ||
540 | |||
541 | tb_ptr = in_be16(&ep->ep_pram_ptr->tx_bd_ptr); | ||
542 | td = cpm_muram_addr(tb_ptr); | ||
543 | td_status = in_be16(&td->status); | ||
544 | buf_ptr = in_be32(&td->buf_ptr); | ||
545 | extra_data = in_be16(&td->extra); | ||
546 | do { | ||
547 | if (td_status & TD_R) { | ||
548 | out_be16(&td->status, (td_status & ~TD_R) | TD_TO); | ||
549 | } else { | ||
550 | out_be32(&td->buf_ptr, 0); | ||
551 | ep->already_pushed_dummy_bd = false; | ||
552 | break; | ||
553 | } | ||
554 | |||
555 | /* advance the TD pointer */ | ||
556 | td = next_bd(ep->td_base, td, td_status); | ||
557 | td_status = in_be16(&td->status); | ||
558 | buf_ptr = in_be32(&td->buf_ptr); | ||
559 | extra_data = in_be16(&td->extra); | ||
560 | } while ((td_status & TD_R) || buf_ptr); | ||
561 | |||
562 | fhci_td_transaction_confirm(usb); | ||
563 | |||
564 | out_be16(&ep->ep_pram_ptr->tx_bd_ptr, | ||
565 | in_be16(&ep->ep_pram_ptr->tx_base)); | ||
566 | out_be32(&ep->ep_pram_ptr->tx_state, 0); | ||
567 | out_be16(&ep->ep_pram_ptr->tx_cnt, 0); | ||
568 | ep->empty_td = ep->td_base; | ||
569 | ep->conf_td = ep->td_base; | ||
570 | |||
571 | usb->actual_frame->frame_status = FRAME_TIMER_END_TRANSMISSION; | ||
572 | |||
573 | /* reset the event register */ | ||
574 | out_be16(&usb->fhci->regs->usb_event, 0xffff); | ||
575 | /* enable the USB controller */ | ||
576 | out_8(&usb->fhci->regs->usb_mod, mode | USB_MODE_EN); | ||
577 | } | ||
578 | |||
579 | /* handles Tx confirm and Tx error interrupt */ | ||
580 | void fhci_tx_conf_interrupt(struct fhci_usb *usb) | ||
581 | { | ||
582 | fhci_td_transaction_confirm(usb); | ||
583 | |||
584 | /* | ||
585 | * Schedule another transaction to this frame only if we have | ||
586 | * already confirmed all transaction in the frame. | ||
587 | */ | ||
588 | if (((fhci_get_sof_timer_count(usb) < usb->max_frame_usage) || | ||
589 | (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION)) && | ||
590 | (list_empty(&usb->actual_frame->tds_list))) | ||
591 | fhci_schedule_transactions(usb); | ||
592 | } | ||
593 | |||
594 | void fhci_host_transmit_actual_frame(struct fhci_usb *usb) | ||
595 | { | ||
596 | u16 tb_ptr; | ||
597 | u16 td_status; | ||
598 | struct usb_td __iomem *td; | ||
599 | struct endpoint *ep = usb->ep0; | ||
600 | |||
601 | tb_ptr = in_be16(&ep->ep_pram_ptr->tx_bd_ptr); | ||
602 | td = cpm_muram_addr(tb_ptr); | ||
603 | |||
604 | if (in_be32(&td->buf_ptr) == DUMMY_BD_BUFFER) { | ||
605 | struct usb_td __iomem *old_td = td; | ||
606 | |||
607 | ep->already_pushed_dummy_bd = false; | ||
608 | td_status = in_be16(&td->status); | ||
609 | /* gets the next TD in the ring */ | ||
610 | td = next_bd(ep->td_base, td, td_status); | ||
611 | tb_ptr = cpm_muram_offset(td); | ||
612 | out_be16(&ep->ep_pram_ptr->tx_bd_ptr, tb_ptr); | ||
613 | |||
614 | /* start transmit only if we have something in the TDs */ | ||
615 | if (in_be16(&td->status) & TD_R) | ||
616 | out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO); | ||
617 | |||
618 | if (in_be32(&ep->conf_td->buf_ptr) == DUMMY_BD_BUFFER) { | ||
619 | out_be32(&old_td->buf_ptr, 0); | ||
620 | ep->conf_td = next_bd(ep->td_base, ep->conf_td, | ||
621 | td_status); | ||
622 | } else { | ||
623 | out_be32(&old_td->buf_ptr, DUMMY2_BD_BUFFER); | ||
624 | } | ||
625 | } | ||
626 | } | ||