forked from mirrors/linux
		
	usb: dwc2: gadget: DDMA transfer start and complete
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>
This commit is contained in:
		
							parent
							
								
									e02f9aa611
								
							
						
					
					
						commit
						aa3e8bc813
					
				
					 1 changed files with 82 additions and 12 deletions
				
			
		| 
						 | 
					@ -760,6 +760,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
 | 
				
			||||||
	unsigned length;
 | 
						unsigned length;
 | 
				
			||||||
	unsigned packets;
 | 
						unsigned packets;
 | 
				
			||||||
	unsigned maxreq;
 | 
						unsigned maxreq;
 | 
				
			||||||
 | 
						unsigned int dma_reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (index != 0) {
 | 
						if (index != 0) {
 | 
				
			||||||
		if (hs_ep->req && !continuing) {
 | 
							if (hs_ep->req && !continuing) {
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
						epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
 | 
				
			||||||
	epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index);
 | 
						epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -849,22 +851,51 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
 | 
				
			||||||
	/* store the request as the current one we're doing */
 | 
						/* store the request as the current one we're doing */
 | 
				
			||||||
	hs_ep->req = hs_req;
 | 
						hs_ep->req = hs_req;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* write size / packets */
 | 
						if (using_desc_dma(hsotg)) {
 | 
				
			||||||
	dwc2_writel(epsize, hsotg->regs + epsize_reg);
 | 
							u32 offset = 0;
 | 
				
			||||||
 | 
							u32 mps = hs_ep->ep.maxpacket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (using_dma(hsotg) && !continuing) {
 | 
							/* Adjust length: EP0 - MPS, other OUT EPs - multiple of MPS */
 | 
				
			||||||
		unsigned int dma_reg;
 | 
							if (!dir_in) {
 | 
				
			||||||
 | 
								if (!index)
 | 
				
			||||||
 | 
									length = mps;
 | 
				
			||||||
 | 
								else if (length % mps)
 | 
				
			||||||
 | 
									length += (mps - (length % mps));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * write DMA address to control register, buffer already
 | 
							 * If more data to send, adjust DMA for EP0 out data stage.
 | 
				
			||||||
		 * synced by dwc2_hsotg_ep_queue().
 | 
							 * 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index);
 | 
							/* Fill DDMA chain entries */
 | 
				
			||||||
		dwc2_writel(ureq->dma, hsotg->regs + dma_reg);
 | 
							dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq->dma + offset,
 | 
				
			||||||
 | 
											     length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n",
 | 
							/* write descriptor chain address to control register */
 | 
				
			||||||
			__func__, &ureq->dma, dma_reg);
 | 
							dwc2_writel(hs_ep->desc_list_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().
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								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) {
 | 
						if (hs_ep->isochronous && hs_ep->interval == 1) {
 | 
				
			||||||
| 
						 | 
					@ -1863,6 +1894,36 @@ static void dwc2_hsotg_change_ep_iso_parity(struct dwc2_hsotg *hsotg,
 | 
				
			||||||
	dwc2_writel(ctrl, hsotg->regs + epctl_reg);
 | 
						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
 | 
					 * dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO
 | 
				
			||||||
 * @hsotg: The device instance
 | 
					 * @hsotg: The device instance
 | 
				
			||||||
| 
						 | 
					@ -1893,6 +1954,9 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (using_desc_dma(hsotg))
 | 
				
			||||||
 | 
							size_left = dwc2_gadget_get_xfersize_ddma(hs_ep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (using_dma(hsotg)) {
 | 
						if (using_dma(hsotg)) {
 | 
				
			||||||
		unsigned size_done;
 | 
							unsigned size_done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
						 * past the end of the buffer (DMA transfers are always 32bit
 | 
				
			||||||
	 * aligned).
 | 
						 * aligned).
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
						if (using_desc_dma(hsotg)) {
 | 
				
			||||||
	size_left = DXEPTSIZ_XFERSIZE_GET(epsize);
 | 
							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->size_loaded - size_left;
 | 
				
			||||||
	size_done += hs_ep->last_load;
 | 
						size_done += hs_ep->last_load;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue