Skip to content

Commit

Permalink
usb: dwc2: gadget: DDMA transfer start and complete
Browse files Browse the repository at this point in the history
Update transfer starting dwc2_hsotg_start_req() routine with call of
function dwc2_gadget_config_nonisoc_xfer_ddma() to fill descriptor
chain.

Add call of dwc2_gadget_get_xfersize_ddma() in
dwc2_hsotg_handle_outdone() and dwc2_hsotg_complete_in() interrupt
handlers for DDMA mode to get information on transferred data from
descriptors instead of DXEPTSIZ.

Signed-off-by: Vahram Aharonyan <vahrama@synopsys.com>
Signed-off-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
  • Loading branch information
Vahram Aharonyan authored and Felipe Balbi committed Nov 18, 2016
1 parent e02f9aa commit aa3e8bc
Showing 1 changed file with 83 additions and 13 deletions.
96 changes: 83 additions & 13 deletions drivers/usb/dwc2/gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
unsigned length;
unsigned packets;
unsigned maxreq;
unsigned int dma_reg;

if (index != 0) {
if (hs_ep->req && !continuing) {
Expand All @@ -774,6 +775,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
}
}

dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index);
epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index);

Expand Down Expand Up @@ -849,22 +851,51 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
/* store the request as the current one we're doing */
hs_ep->req = hs_req;

/* write size / packets */
dwc2_writel(epsize, hsotg->regs + epsize_reg);

if (using_dma(hsotg) && !continuing) {
unsigned int dma_reg;
if (using_desc_dma(hsotg)) {
u32 offset = 0;
u32 mps = hs_ep->ep.maxpacket;

/* Adjust length: EP0 - MPS, other OUT EPs - multiple of MPS */
if (!dir_in) {
if (!index)
length = mps;
else if (length % mps)
length += (mps - (length % mps));
}

/*
* write DMA address to control register, buffer already
* synced by dwc2_hsotg_ep_queue().
* If more data to send, adjust DMA for EP0 out data stage.
* ureq->dma stays unchanged, hence increment it by already
* passed passed data count before starting new transaction.
*/
if (!index && hsotg->ep0_state == DWC2_EP0_DATA_OUT &&
continuing)
offset = ureq->actual;

/* Fill DDMA chain entries */
dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq->dma + offset,
length);

/* write descriptor chain address to control register */
dwc2_writel(hs_ep->desc_list_dma, hsotg->regs + dma_reg);

dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index);
dwc2_writel(ureq->dma, hsotg->regs + dma_reg);
dev_dbg(hsotg->dev, "%s: %08x pad => 0x%08x\n",
__func__, (u32)hs_ep->desc_list_dma, dma_reg);
} else {
/* write size / packets */
dwc2_writel(epsize, hsotg->regs + epsize_reg);

if (using_dma(hsotg) && !continuing) {
/*
* write DMA address to control register, buffer
* already synced by dwc2_hsotg_ep_queue().
*/

dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n",
__func__, &ureq->dma, dma_reg);
dwc2_writel(ureq->dma, hsotg->regs + dma_reg);

dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n",
__func__, &ureq->dma, dma_reg);
}
}

if (hs_ep->isochronous && hs_ep->interval == 1) {
Expand Down Expand Up @@ -1863,6 +1894,36 @@ static void dwc2_hsotg_change_ep_iso_parity(struct dwc2_hsotg *hsotg,
dwc2_writel(ctrl, hsotg->regs + epctl_reg);
}

/*
* dwc2_gadget_get_xfersize_ddma - get transferred bytes amount from desc
* @hs_ep - The endpoint on which transfer went
*
* Iterate over endpoints descriptor chain and get info on bytes remained
* in DMA descriptors after transfer has completed. Used for non isoc EPs.
*/
static unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep)
{
struct dwc2_hsotg *hsotg = hs_ep->parent;
unsigned int bytes_rem = 0;
struct dwc2_dma_desc *desc = hs_ep->desc_list;
int i;
u32 status;

if (!desc)
return -EINVAL;

for (i = 0; i < hs_ep->desc_count; ++i) {
status = desc->status;
bytes_rem += status & DEV_DMA_NBYTES_MASK;

if (status & DEV_DMA_STS_MASK)
dev_err(hsotg->dev, "descriptor %d closed with %x\n",
i, status & DEV_DMA_STS_MASK);
}

return bytes_rem;
}

/**
* dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO
* @hsotg: The device instance
Expand Down Expand Up @@ -1893,6 +1954,9 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum)
return;
}

if (using_desc_dma(hsotg))
size_left = dwc2_gadget_get_xfersize_ddma(hs_ep);

if (using_dma(hsotg)) {
unsigned size_done;

Expand Down Expand Up @@ -2224,8 +2288,14 @@ static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg,
* past the end of the buffer (DMA transfers are always 32bit
* aligned).
*/

size_left = DXEPTSIZ_XFERSIZE_GET(epsize);
if (using_desc_dma(hsotg)) {
size_left = dwc2_gadget_get_xfersize_ddma(hs_ep);
if (size_left < 0)
dev_err(hsotg->dev, "error parsing DDMA results %d\n",
size_left);
} else {
size_left = DXEPTSIZ_XFERSIZE_GET(epsize);
}

size_done = hs_ep->size_loaded - size_left;
size_done += hs_ep->last_load;
Expand Down

0 comments on commit aa3e8bc

Please sign in to comment.