Commit | Line | Data |
---|---|---|
5fd54ace | 1 | // SPDX-License-Identifier: GPL-2.0+ |
236dd4d1 AV |
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> | |
236dd4d1 AV |
12 | */ |
13 | ||
14 | #include <linux/kernel.h> | |
15 | #include <linux/types.h> | |
16 | #include <linux/errno.h> | |
5a0e3ad6 | 17 | #include <linux/slab.h> |
236dd4d1 AV |
18 | #include <linux/list.h> |
19 | #include <linux/io.h> | |
20 | #include <linux/usb.h> | |
27729aad | 21 | #include <linux/usb/hcd.h> |
236dd4d1 AV |
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. */ | |
25985edc | 39 | #define TD_STAL 0x0008 /* Stall received */ |
236dd4d1 AV |
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 extra; | |
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 | { | |
2d80b52e | 84 | if (!ep->already_pushed_dummy_bd) { |
236dd4d1 AV |
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(ep->td_base, ep->empty_td, 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(cpm_muram_offset(ep->td_base)); | |
104 | ||
4c743d0a | 105 | if (kfifo_initialized(&ep->conf_frame_Q)) { |
45465487 | 106 | size = cq_howmany(&ep->conf_frame_Q); |
236dd4d1 | 107 | for (; size; size--) { |
45465487 | 108 | struct packet *pkt = cq_get(&ep->conf_frame_Q); |
236dd4d1 AV |
109 | |
110 | kfree(pkt); | |
111 | } | |
45465487 | 112 | cq_delete(&ep->conf_frame_Q); |
236dd4d1 AV |
113 | } |
114 | ||
4c743d0a | 115 | if (kfifo_initialized(&ep->empty_frame_Q)) { |
45465487 | 116 | size = cq_howmany(&ep->empty_frame_Q); |
236dd4d1 | 117 | for (; size; size--) { |
45465487 | 118 | struct packet *pkt = cq_get(&ep->empty_frame_Q); |
236dd4d1 AV |
119 | |
120 | kfree(pkt); | |
121 | } | |
45465487 | 122 | cq_delete(&ep->empty_frame_Q); |
236dd4d1 AV |
123 | } |
124 | ||
4c743d0a | 125 | if (kfifo_initialized(&ep->dummy_packets_Q)) { |
45465487 | 126 | size = cq_howmany(&ep->dummy_packets_Q); |
236dd4d1 | 127 | for (; size; size--) { |
45465487 | 128 | u8 *buff = cq_get(&ep->dummy_packets_Q); |
236dd4d1 AV |
129 | |
130 | kfree(buff); | |
131 | } | |
45465487 | 132 | cq_delete(&ep->dummy_packets_Q); |
236dd4d1 AV |
133 | } |
134 | ||
135 | kfree(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; | |
1c1301dd | 154 | char *err_for = "endpoint PRAM"; |
236dd4d1 AV |
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(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(ep_mem_size, 32); | |
170 | if (IS_ERR_VALUE(ep_offset)) | |
171 | goto err; | |
172 | ep->td_base = cpm_muram_addr(ep_offset); | |
173 | ||
174 | /* zero all queue pointers */ | |
45465487 SS |
175 | if (cq_new(&ep->conf_frame_Q, ring_len + 2) || |
176 | cq_new(&ep->empty_frame_Q, ring_len + 2) || | |
177 | cq_new(&ep->dummy_packets_Q, ring_len + 2)) { | |
236dd4d1 AV |
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(sizeof(*pkt), GFP_KERNEL); | |
187 | if (!pkt) { | |
188 | err_for = "frame"; | |
189 | goto err; | |
190 | } | |
191 | ||
6da2ec56 | 192 | buff = kmalloc_array(1028, sizeof(*buff), GFP_KERNEL); |
236dd4d1 AV |
193 | if (!buff) { |
194 | kfree(pkt); | |
195 | err_for = "buffer"; | |
196 | goto err; | |
197 | } | |
45465487 SS |
198 | cq_put(&ep->empty_frame_Q, pkt); |
199 | cq_put(&ep->dummy_packets_Q, buff); | |
236dd4d1 AV |
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(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 */ | |
cf61fdb9 | 248 | out_be16(&usb->fhci->regs->usb_usep[0], |
236dd4d1 AV |
249 | USB_TRANS_CTR | USB_EP_MF | USB_EP_RTE); |
250 | out_be16(&usb->fhci->pram->ep_ptr[0], | |
251 | cpm_muram_offset(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(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(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 | |
48e34d0f JM |
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 | |
236dd4d1 | 272 | * confirmation about the submitted frames. Otherwise, the routine is |
25985edc | 273 | * called from the interrupt service routine during the Tx interrupt. |
236dd4d1 AV |
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 extra_data; | |
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(ep->td_base, ep->conf_td, 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 | ||
45465487 | 318 | pkt = cq_get(&ep->conf_frame_Q); |
236dd4d1 AV |
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 " | |
25985edc | 336 | "occurred\n"); |
236dd4d1 AV |
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 | |
25985edc | 346 | fhci_err(usb->fhci, "illegal error occurred\n"); |
236dd4d1 AV |
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 extra_data; | |
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(ep->td_base, ep->empty_td, td_status); | |
403 | fhci_usb_enable_interrupt(usb); | |
404 | pkt->priv_data = td; | |
405 | out_be32(&td->buf_ptr, virt_to_phys(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 */ | |
45465487 | 459 | cq_put(&ep->conf_frame_Q, pkt); |
236dd4d1 | 460 | |
45465487 | 461 | if (cq_howmany(&ep->conf_frame_Q) == 1) |
cf61fdb9 | 462 | out_8(&usb->fhci->regs->usb_uscom, USB_CMD_STR_FIFO); |
236dd4d1 AV |
463 | |
464 | return 0; | |
465 | } | |
466 | ||
467 | /* Reset the Tx BD ring */ | |
468 | void fhci_flush_bds(struct fhci_usb *usb) | |
469 | { | |
470 | u16 extra_data; | |
471 | u16 td_status; | |
472 | u32 buf; | |
473 | struct usb_td __iomem *td; | |
474 | struct endpoint *ep = usb->ep0; | |
475 | ||
476 | td = ep->td_base; | |
477 | while (1) { | |
478 | td_status = in_be16(&td->status); | |
479 | buf = in_be32(&td->buf_ptr); | |
480 | extra_data = in_be16(&td->extra); | |
481 | ||
482 | /* if the TD is not empty - we'll confirm it as Timeout */ | |
483 | if (td_status & TD_R) | |
484 | out_be16(&td->status, (td_status & ~TD_R) | TD_TO); | |
485 | /* if this TD is dummy - let's skip this TD */ | |
486 | else if (in_be32(&td->buf_ptr) == DUMMY_BD_BUFFER) | |
487 | out_be32(&td->buf_ptr, DUMMY2_BD_BUFFER); | |
488 | /* if this is the last TD - break */ | |
489 | if (td_status & TD_W) | |
490 | break; | |
491 | ||
492 | td++; | |
493 | } | |
494 | ||
495 | fhci_td_transaction_confirm(usb); | |
496 | ||
497 | td = ep->td_base; | |
498 | do { | |
499 | out_be16(&td->status, 0); | |
500 | out_be16(&td->length, 0); | |
501 | out_be32(&td->buf_ptr, 0); | |
502 | out_be16(&td->extra, 0); | |
503 | td++; | |
504 | } while (!(in_be16(&td->status) & TD_W)); | |
505 | out_be16(&td->status, TD_W); /* for last TD set Wrap bit */ | |
506 | out_be16(&td->length, 0); | |
507 | out_be32(&td->buf_ptr, 0); | |
508 | out_be16(&td->extra, 0); | |
509 | ||
510 | out_be16(&ep->ep_pram_ptr->tx_bd_ptr, | |
511 | in_be16(&ep->ep_pram_ptr->tx_base)); | |
512 | out_be32(&ep->ep_pram_ptr->tx_state, 0); | |
513 | out_be16(&ep->ep_pram_ptr->tx_cnt, 0); | |
514 | ep->empty_td = ep->td_base; | |
515 | ep->conf_td = ep->td_base; | |
516 | } | |
517 | ||
518 | /* | |
519 | * Flush all transmitted packets from TDs in the actual frame. | |
520 | * This routine is called when something wrong with the controller and | |
521 | * we want to get rid of the actual frame and start again next frame | |
522 | */ | |
523 | void fhci_flush_actual_frame(struct fhci_usb *usb) | |
524 | { | |
525 | u8 mode; | |
526 | u16 tb_ptr; | |
527 | u16 extra_data; | |
528 | u16 td_status; | |
529 | u32 buf_ptr; | |
530 | struct usb_td __iomem *td; | |
531 | struct endpoint *ep = usb->ep0; | |
532 | ||
533 | /* disable the USB controller */ | |
cf61fdb9 GMF |
534 | mode = in_8(&usb->fhci->regs->usb_usmod); |
535 | out_8(&usb->fhci->regs->usb_usmod, mode & ~USB_MODE_EN); | |
236dd4d1 AV |
536 | |
537 | tb_ptr = in_be16(&ep->ep_pram_ptr->tx_bd_ptr); | |
538 | td = cpm_muram_addr(tb_ptr); | |
539 | td_status = in_be16(&td->status); | |
540 | buf_ptr = in_be32(&td->buf_ptr); | |
541 | extra_data = in_be16(&td->extra); | |
542 | do { | |
543 | if (td_status & TD_R) { | |
544 | out_be16(&td->status, (td_status & ~TD_R) | TD_TO); | |
545 | } else { | |
546 | out_be32(&td->buf_ptr, 0); | |
547 | ep->already_pushed_dummy_bd = false; | |
548 | break; | |
549 | } | |
550 | ||
551 | /* advance the TD pointer */ | |
552 | td = next_bd(ep->td_base, td, td_status); | |
553 | td_status = in_be16(&td->status); | |
554 | buf_ptr = in_be32(&td->buf_ptr); | |
555 | extra_data = in_be16(&td->extra); | |
556 | } while ((td_status & TD_R) || buf_ptr); | |
557 | ||
558 | fhci_td_transaction_confirm(usb); | |
559 | ||
560 | out_be16(&ep->ep_pram_ptr->tx_bd_ptr, | |
561 | in_be16(&ep->ep_pram_ptr->tx_base)); | |
562 | out_be32(&ep->ep_pram_ptr->tx_state, 0); | |
563 | out_be16(&ep->ep_pram_ptr->tx_cnt, 0); | |
564 | ep->empty_td = ep->td_base; | |
565 | ep->conf_td = ep->td_base; | |
566 | ||
567 | usb->actual_frame->frame_status = FRAME_TIMER_END_TRANSMISSION; | |
568 | ||
569 | /* reset the event register */ | |
cf61fdb9 | 570 | out_be16(&usb->fhci->regs->usb_usber, 0xffff); |
236dd4d1 | 571 | /* enable the USB controller */ |
cf61fdb9 | 572 | out_8(&usb->fhci->regs->usb_usmod, mode | USB_MODE_EN); |
236dd4d1 AV |
573 | } |
574 | ||
575 | /* handles Tx confirm and Tx error interrupt */ | |
576 | void fhci_tx_conf_interrupt(struct fhci_usb *usb) | |
577 | { | |
578 | fhci_td_transaction_confirm(usb); | |
579 | ||
580 | /* | |
581 | * Schedule another transaction to this frame only if we have | |
582 | * already confirmed all transaction in the frame. | |
583 | */ | |
584 | if (((fhci_get_sof_timer_count(usb) < usb->max_frame_usage) || | |
585 | (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION)) && | |
586 | (list_empty(&usb->actual_frame->tds_list))) | |
587 | fhci_schedule_transactions(usb); | |
588 | } | |
589 | ||
590 | void fhci_host_transmit_actual_frame(struct fhci_usb *usb) | |
591 | { | |
592 | u16 tb_ptr; | |
593 | u16 td_status; | |
594 | struct usb_td __iomem *td; | |
595 | struct endpoint *ep = usb->ep0; | |
596 | ||
597 | tb_ptr = in_be16(&ep->ep_pram_ptr->tx_bd_ptr); | |
598 | td = cpm_muram_addr(tb_ptr); | |
599 | ||
600 | if (in_be32(&td->buf_ptr) == DUMMY_BD_BUFFER) { | |
601 | struct usb_td __iomem *old_td = td; | |
602 | ||
603 | ep->already_pushed_dummy_bd = false; | |
604 | td_status = in_be16(&td->status); | |
605 | /* gets the next TD in the ring */ | |
606 | td = next_bd(ep->td_base, td, td_status); | |
607 | tb_ptr = cpm_muram_offset(td); | |
608 | out_be16(&ep->ep_pram_ptr->tx_bd_ptr, tb_ptr); | |
609 | ||
610 | /* start transmit only if we have something in the TDs */ | |
611 | if (in_be16(&td->status) & TD_R) | |
cf61fdb9 | 612 | out_8(&usb->fhci->regs->usb_uscom, USB_CMD_STR_FIFO); |
236dd4d1 AV |
613 | |
614 | if (in_be32(&ep->conf_td->buf_ptr) == DUMMY_BD_BUFFER) { | |
615 | out_be32(&old_td->buf_ptr, 0); | |
616 | ep->conf_td = next_bd(ep->td_base, ep->conf_td, | |
617 | td_status); | |
618 | } else { | |
619 | out_be32(&old_td->buf_ptr, DUMMY2_BD_BUFFER); | |
620 | } | |
621 | } | |
622 | } |