diff options
author | Neil Zhang <zhangwm@marvell.com> | 2011-12-15 06:26:39 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2011-12-19 03:02:24 -0500 |
commit | 91d959d8e5fa52def4bdbb184c57427c29ce7602 (patch) | |
tree | 59820869d59aeb0aab4f7d48651e5ef28fb3fbd9 | |
parent | 86bb702813010a0870c45d7f080669450a95be8d (diff) |
usb: gadget: mv_udc: rewrite queue_dtd according to spec
Rewrite function queue_dtd according to ChipIdea's reference manual.
Remove all unnecessary logic, it will enhance the performance.
Signed-off-by: Neil Zhang <zhangwm@marvell.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | drivers/usb/gadget/mv_udc_core.c | 139 |
1 files changed, 38 insertions, 101 deletions
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 635ee47dd4e..0ad321d94f2 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c | |||
@@ -276,11 +276,12 @@ static void done(struct mv_ep *ep, struct mv_req *req, int status) | |||
276 | 276 | ||
277 | static int queue_dtd(struct mv_ep *ep, struct mv_req *req) | 277 | static int queue_dtd(struct mv_ep *ep, struct mv_req *req) |
278 | { | 278 | { |
279 | u32 tmp, epstatus, bit_pos, direction; | ||
280 | struct mv_udc *udc; | 279 | struct mv_udc *udc; |
281 | struct mv_dqh *dqh; | 280 | struct mv_dqh *dqh; |
281 | u32 bit_pos, direction; | ||
282 | u32 usbcmd, epstatus; | ||
282 | unsigned int loops; | 283 | unsigned int loops; |
283 | int readsafe, retval = 0; | 284 | int retval = 0; |
284 | 285 | ||
285 | udc = ep->udc; | 286 | udc = ep->udc; |
286 | direction = ep_dir(ep); | 287 | direction = ep_dir(ep); |
@@ -293,30 +294,18 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req) | |||
293 | lastreq = list_entry(ep->queue.prev, struct mv_req, queue); | 294 | lastreq = list_entry(ep->queue.prev, struct mv_req, queue); |
294 | lastreq->tail->dtd_next = | 295 | lastreq->tail->dtd_next = |
295 | req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK; | 296 | req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK; |
296 | if (readl(&udc->op_regs->epprime) & bit_pos) { | 297 | |
297 | loops = LOOPS(PRIME_TIMEOUT); | 298 | wmb(); |
298 | while (readl(&udc->op_regs->epprime) & bit_pos) { | 299 | |
299 | if (loops == 0) { | 300 | if (readl(&udc->op_regs->epprime) & bit_pos) |
300 | retval = -ETIME; | 301 | goto done; |
301 | goto done; | 302 | |
302 | } | ||
303 | udelay(LOOPS_USEC); | ||
304 | loops--; | ||
305 | } | ||
306 | if (readl(&udc->op_regs->epstatus) & bit_pos) | ||
307 | goto done; | ||
308 | } | ||
309 | readsafe = 0; | ||
310 | loops = LOOPS(READSAFE_TIMEOUT); | 303 | loops = LOOPS(READSAFE_TIMEOUT); |
311 | while (readsafe == 0) { | 304 | while (1) { |
312 | if (loops == 0) { | ||
313 | retval = -ETIME; | ||
314 | goto done; | ||
315 | } | ||
316 | /* start with setting the semaphores */ | 305 | /* start with setting the semaphores */ |
317 | tmp = readl(&udc->op_regs->usbcmd); | 306 | usbcmd = readl(&udc->op_regs->usbcmd); |
318 | tmp |= USBCMD_ATDTW_TRIPWIRE_SET; | 307 | usbcmd |= USBCMD_ATDTW_TRIPWIRE_SET; |
319 | writel(tmp, &udc->op_regs->usbcmd); | 308 | writel(usbcmd, &udc->op_regs->usbcmd); |
320 | 309 | ||
321 | /* read the endpoint status */ | 310 | /* read the endpoint status */ |
322 | epstatus = readl(&udc->op_regs->epstatus) & bit_pos; | 311 | epstatus = readl(&udc->op_regs->epstatus) & bit_pos; |
@@ -329,98 +318,46 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req) | |||
329 | * primed. | 318 | * primed. |
330 | */ | 319 | */ |
331 | if (readl(&udc->op_regs->usbcmd) | 320 | if (readl(&udc->op_regs->usbcmd) |
332 | & USBCMD_ATDTW_TRIPWIRE_SET) { | 321 | & USBCMD_ATDTW_TRIPWIRE_SET) |
333 | readsafe = 1; | 322 | break; |
334 | } | 323 | |
335 | loops--; | 324 | loops--; |
325 | if (loops == 0) { | ||
326 | dev_err(&udc->dev->dev, | ||
327 | "Timeout for ATDTW_TRIPWIRE...\n"); | ||
328 | retval = -ETIME; | ||
329 | goto done; | ||
330 | } | ||
336 | udelay(LOOPS_USEC); | 331 | udelay(LOOPS_USEC); |
337 | } | 332 | } |
338 | 333 | ||
339 | /* Clear the semaphore */ | 334 | /* Clear the semaphore */ |
340 | tmp = readl(&udc->op_regs->usbcmd); | 335 | usbcmd = readl(&udc->op_regs->usbcmd); |
341 | tmp &= USBCMD_ATDTW_TRIPWIRE_CLEAR; | 336 | usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR; |
342 | writel(tmp, &udc->op_regs->usbcmd); | 337 | writel(usbcmd, &udc->op_regs->usbcmd); |
343 | |||
344 | /* If endpoint is not active, we activate it now. */ | ||
345 | if (!epstatus) { | ||
346 | if (direction == EP_DIR_IN) { | ||
347 | struct mv_dtd *curr_dtd = dma_to_virt( | ||
348 | &udc->dev->dev, dqh->curr_dtd_ptr); | ||
349 | |||
350 | loops = LOOPS(DTD_TIMEOUT); | ||
351 | while (curr_dtd->size_ioc_sts | ||
352 | & DTD_STATUS_ACTIVE) { | ||
353 | if (loops == 0) { | ||
354 | retval = -ETIME; | ||
355 | goto done; | ||
356 | } | ||
357 | loops--; | ||
358 | udelay(LOOPS_USEC); | ||
359 | } | ||
360 | } | ||
361 | /* No other transfers on the queue */ | ||
362 | 338 | ||
363 | /* Write dQH next pointer and terminate bit to 0 */ | 339 | if (epstatus) |
364 | dqh->next_dtd_ptr = req->head->td_dma | 340 | goto done; |
341 | } | ||
342 | |||
343 | /* Write dQH next pointer and terminate bit to 0 */ | ||
344 | dqh->next_dtd_ptr = req->head->td_dma | ||
365 | & EP_QUEUE_HEAD_NEXT_POINTER_MASK; | 345 | & EP_QUEUE_HEAD_NEXT_POINTER_MASK; |
366 | dqh->size_ioc_int_sts = 0; | ||
367 | 346 | ||
368 | /* | 347 | /* clear active and halt bit, in case set from a previous error */ |
369 | * Ensure that updates to the QH will | 348 | dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED); |
370 | * occur before priming. | ||
371 | */ | ||
372 | wmb(); | ||
373 | 349 | ||
374 | /* Prime the Endpoint */ | 350 | /* Ensure that updates to the QH will occure before priming. */ |
375 | writel(bit_pos, &udc->op_regs->epprime); | 351 | wmb(); |
376 | } | ||
377 | } else { | ||
378 | /* Write dQH next pointer and terminate bit to 0 */ | ||
379 | dqh->next_dtd_ptr = req->head->td_dma | ||
380 | & EP_QUEUE_HEAD_NEXT_POINTER_MASK; | ||
381 | dqh->size_ioc_int_sts = 0; | ||
382 | |||
383 | /* Ensure that updates to the QH will occur before priming. */ | ||
384 | wmb(); | ||
385 | 352 | ||
386 | /* Prime the Endpoint */ | 353 | /* Prime the Endpoint */ |
387 | writel(bit_pos, &udc->op_regs->epprime); | 354 | writel(bit_pos, &udc->op_regs->epprime); |
388 | 355 | ||
389 | if (direction == EP_DIR_IN) { | ||
390 | /* FIXME add status check after prime the IN ep */ | ||
391 | int prime_again; | ||
392 | u32 curr_dtd_ptr = dqh->curr_dtd_ptr; | ||
393 | |||
394 | loops = LOOPS(DTD_TIMEOUT); | ||
395 | prime_again = 0; | ||
396 | while ((curr_dtd_ptr != req->head->td_dma)) { | ||
397 | curr_dtd_ptr = dqh->curr_dtd_ptr; | ||
398 | if (loops == 0) { | ||
399 | dev_err(&udc->dev->dev, | ||
400 | "failed to prime %s\n", | ||
401 | ep->name); | ||
402 | retval = -ETIME; | ||
403 | goto done; | ||
404 | } | ||
405 | loops--; | ||
406 | udelay(LOOPS_USEC); | ||
407 | |||
408 | if (loops == (LOOPS(DTD_TIMEOUT) >> 2)) { | ||
409 | if (prime_again) | ||
410 | goto done; | ||
411 | dev_info(&udc->dev->dev, | ||
412 | "prime again\n"); | ||
413 | writel(bit_pos, | ||
414 | &udc->op_regs->epprime); | ||
415 | prime_again = 1; | ||
416 | } | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | done: | 356 | done: |
421 | return retval; | 357 | return retval; |
422 | } | 358 | } |
423 | 359 | ||
360 | |||
424 | static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length, | 361 | static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length, |
425 | dma_addr_t *dma, int *is_last) | 362 | dma_addr_t *dma, int *is_last) |
426 | { | 363 | { |