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