forked from Minki/linux
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>
This commit is contained in:
parent
86bb702813
commit
91d959d8e5
@ -276,11 +276,12 @@ static void done(struct mv_ep *ep, struct mv_req *req, int status)
|
|||||||
|
|
||||||
static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
|
static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
|
||||||
{
|
{
|
||||||
u32 tmp, epstatus, bit_pos, direction;
|
|
||||||
struct mv_udc *udc;
|
struct mv_udc *udc;
|
||||||
struct mv_dqh *dqh;
|
struct mv_dqh *dqh;
|
||||||
|
u32 bit_pos, direction;
|
||||||
|
u32 usbcmd, epstatus;
|
||||||
unsigned int loops;
|
unsigned int loops;
|
||||||
int readsafe, retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
udc = ep->udc;
|
udc = ep->udc;
|
||||||
direction = ep_dir(ep);
|
direction = ep_dir(ep);
|
||||||
@ -293,30 +294,18 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
|
|||||||
lastreq = list_entry(ep->queue.prev, struct mv_req, queue);
|
lastreq = list_entry(ep->queue.prev, struct mv_req, queue);
|
||||||
lastreq->tail->dtd_next =
|
lastreq->tail->dtd_next =
|
||||||
req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
|
req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
|
||||||
if (readl(&udc->op_regs->epprime) & bit_pos) {
|
|
||||||
loops = LOOPS(PRIME_TIMEOUT);
|
wmb();
|
||||||
while (readl(&udc->op_regs->epprime) & bit_pos) {
|
|
||||||
if (loops == 0) {
|
if (readl(&udc->op_regs->epprime) & bit_pos)
|
||||||
retval = -ETIME;
|
goto done;
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
udelay(LOOPS_USEC);
|
|
||||||
loops--;
|
|
||||||
}
|
|
||||||
if (readl(&udc->op_regs->epstatus) & bit_pos)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
readsafe = 0;
|
|
||||||
loops = LOOPS(READSAFE_TIMEOUT);
|
loops = LOOPS(READSAFE_TIMEOUT);
|
||||||
while (readsafe == 0) {
|
while (1) {
|
||||||
if (loops == 0) {
|
|
||||||
retval = -ETIME;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* start with setting the semaphores */
|
/* start with setting the semaphores */
|
||||||
tmp = readl(&udc->op_regs->usbcmd);
|
usbcmd = readl(&udc->op_regs->usbcmd);
|
||||||
tmp |= USBCMD_ATDTW_TRIPWIRE_SET;
|
usbcmd |= USBCMD_ATDTW_TRIPWIRE_SET;
|
||||||
writel(tmp, &udc->op_regs->usbcmd);
|
writel(usbcmd, &udc->op_regs->usbcmd);
|
||||||
|
|
||||||
/* read the endpoint status */
|
/* read the endpoint status */
|
||||||
epstatus = readl(&udc->op_regs->epstatus) & bit_pos;
|
epstatus = readl(&udc->op_regs->epstatus) & bit_pos;
|
||||||
@ -329,98 +318,46 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
|
|||||||
* primed.
|
* primed.
|
||||||
*/
|
*/
|
||||||
if (readl(&udc->op_regs->usbcmd)
|
if (readl(&udc->op_regs->usbcmd)
|
||||||
& USBCMD_ATDTW_TRIPWIRE_SET) {
|
& USBCMD_ATDTW_TRIPWIRE_SET)
|
||||||
readsafe = 1;
|
break;
|
||||||
}
|
|
||||||
loops--;
|
loops--;
|
||||||
|
if (loops == 0) {
|
||||||
|
dev_err(&udc->dev->dev,
|
||||||
|
"Timeout for ATDTW_TRIPWIRE...\n");
|
||||||
|
retval = -ETIME;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
udelay(LOOPS_USEC);
|
udelay(LOOPS_USEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the semaphore */
|
/* Clear the semaphore */
|
||||||
tmp = readl(&udc->op_regs->usbcmd);
|
usbcmd = readl(&udc->op_regs->usbcmd);
|
||||||
tmp &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
|
usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
|
||||||
writel(tmp, &udc->op_regs->usbcmd);
|
writel(usbcmd, &udc->op_regs->usbcmd);
|
||||||
|
|
||||||
/* If endpoint is not active, we activate it now. */
|
if (epstatus)
|
||||||
if (!epstatus) {
|
goto done;
|
||||||
if (direction == EP_DIR_IN) {
|
|
||||||
struct mv_dtd *curr_dtd = dma_to_virt(
|
|
||||||
&udc->dev->dev, dqh->curr_dtd_ptr);
|
|
||||||
|
|
||||||
loops = LOOPS(DTD_TIMEOUT);
|
|
||||||
while (curr_dtd->size_ioc_sts
|
|
||||||
& DTD_STATUS_ACTIVE) {
|
|
||||||
if (loops == 0) {
|
|
||||||
retval = -ETIME;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
loops--;
|
|
||||||
udelay(LOOPS_USEC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* No other transfers on the queue */
|
|
||||||
|
|
||||||
/* Write dQH next pointer and terminate bit to 0 */
|
|
||||||
dqh->next_dtd_ptr = req->head->td_dma
|
|
||||||
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
|
|
||||||
dqh->size_ioc_int_sts = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ensure that updates to the QH will
|
|
||||||
* occur before priming.
|
|
||||||
*/
|
|
||||||
wmb();
|
|
||||||
|
|
||||||
/* Prime the Endpoint */
|
|
||||||
writel(bit_pos, &udc->op_regs->epprime);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Write dQH next pointer and terminate bit to 0 */
|
|
||||||
dqh->next_dtd_ptr = req->head->td_dma
|
|
||||||
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
|
|
||||||
dqh->size_ioc_int_sts = 0;
|
|
||||||
|
|
||||||
/* Ensure that updates to the QH will occur before priming. */
|
|
||||||
wmb();
|
|
||||||
|
|
||||||
/* Prime the Endpoint */
|
|
||||||
writel(bit_pos, &udc->op_regs->epprime);
|
|
||||||
|
|
||||||
if (direction == EP_DIR_IN) {
|
|
||||||
/* FIXME add status check after prime the IN ep */
|
|
||||||
int prime_again;
|
|
||||||
u32 curr_dtd_ptr = dqh->curr_dtd_ptr;
|
|
||||||
|
|
||||||
loops = LOOPS(DTD_TIMEOUT);
|
|
||||||
prime_again = 0;
|
|
||||||
while ((curr_dtd_ptr != req->head->td_dma)) {
|
|
||||||
curr_dtd_ptr = dqh->curr_dtd_ptr;
|
|
||||||
if (loops == 0) {
|
|
||||||
dev_err(&udc->dev->dev,
|
|
||||||
"failed to prime %s\n",
|
|
||||||
ep->name);
|
|
||||||
retval = -ETIME;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
loops--;
|
|
||||||
udelay(LOOPS_USEC);
|
|
||||||
|
|
||||||
if (loops == (LOOPS(DTD_TIMEOUT) >> 2)) {
|
|
||||||
if (prime_again)
|
|
||||||
goto done;
|
|
||||||
dev_info(&udc->dev->dev,
|
|
||||||
"prime again\n");
|
|
||||||
writel(bit_pos,
|
|
||||||
&udc->op_regs->epprime);
|
|
||||||
prime_again = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Write dQH next pointer and terminate bit to 0 */
|
||||||
|
dqh->next_dtd_ptr = req->head->td_dma
|
||||||
|
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
|
||||||
|
|
||||||
|
/* clear active and halt bit, in case set from a previous error */
|
||||||
|
dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
|
||||||
|
|
||||||
|
/* Ensure that updates to the QH will occure before priming. */
|
||||||
|
wmb();
|
||||||
|
|
||||||
|
/* Prime the Endpoint */
|
||||||
|
writel(bit_pos, &udc->op_regs->epprime);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
|
static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
|
||||||
dma_addr_t *dma, int *is_last)
|
dma_addr_t *dma, int *is_last)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user