diff mbox

[U-Boot,3/6] usb: dwc2: split transfer core from outer loop

Message ID 1453000196-4752-4-git-send-email-stefan.bruens@rwth-aachen.de
State Accepted
Commit daed305941eb7ff30039af8142c2392bd5c3ad91
Delegated to: Marek Vasut
Headers show

Commit Message

Stefan Brüns Jan. 17, 2016, 3:09 a.m. UTC
Split the movement of data between CPU and Host Controller from the
status handling and tracking of transfer progress.
This will also simplify adding of SPLIT transaction support.

Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
---
 drivers/usb/host/dwc2.c | 112 +++++++++++++++++++++++++++---------------------
 1 file changed, 64 insertions(+), 48 deletions(-)
diff mbox

Patch

diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
index ad097cb..0e710d9 100644
--- a/drivers/usb/host/dwc2.c
+++ b/drivers/usb/host/dwc2.c
@@ -426,9 +426,6 @@  static void dwc_otg_hc_init(struct dwc2_core_regs *regs, uint8_t hc_num,
 	if (dev->speed == USB_SPEED_LOW)
 		hcchar |= DWC2_HCCHAR_LSPDDEV;
 
-	/* Clear old interrupt conditions for this host channel. */
-	writel(0x3fff, &hc_regs->hcint);
-
 	/*
 	 * Program the HCCHARn register with the endpoint characteristics
 	 * for the current transfer.
@@ -729,9 +726,8 @@  static int dwc_otg_submit_rh_msg(struct dwc2_priv *priv, struct usb_device *dev,
 	return stat;
 }
 
-int wait_for_chhltd(struct dwc2_core_regs *regs, uint32_t *sub, int *toggle)
+int wait_for_chhltd(struct dwc2_hc_regs *hc_regs, uint32_t *sub, int *toggle)
 {
-	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
 	int ret;
 	uint32_t hcint, hctsiz;
 
@@ -765,6 +761,58 @@  static int dwc2_eptype[] = {
 	DWC2_HCCHAR_EPTYPE_BULK,
 };
 
+static int transfer_chunk(struct dwc2_hc_regs *hc_regs, void *aligned_buffer,
+			  int *pid, int in, void *buffer, int num_packets,
+			  int xfer_len, int *actual_len)
+{
+	int ret = 0;
+	uint32_t sub;
+
+	debug("%s: chunk: pid %d xfer_len %u pkts %u\n", __func__,
+	      *pid, xfer_len, num_packets);
+
+	writel((xfer_len << DWC2_HCTSIZ_XFERSIZE_OFFSET) |
+	       (num_packets << DWC2_HCTSIZ_PKTCNT_OFFSET) |
+	       (*pid << DWC2_HCTSIZ_PID_OFFSET),
+	       &hc_regs->hctsiz);
+
+	if (!in && xfer_len) {
+		memcpy(aligned_buffer, buffer, xfer_len);
+
+		flush_dcache_range((unsigned long)aligned_buffer,
+				   (unsigned long)aligned_buffer +
+				   roundup(xfer_len, ARCH_DMA_MINALIGN));
+	}
+
+	writel(phys_to_bus((unsigned long)aligned_buffer), &hc_regs->hcdma);
+
+	/* Clear old interrupt conditions for this host channel. */
+	writel(0x3fff, &hc_regs->hcint);
+
+	/* Set host channel enable after all other setup is complete. */
+	clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
+			DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS,
+			(1 << DWC2_HCCHAR_MULTICNT_OFFSET) |
+			DWC2_HCCHAR_CHEN);
+
+	ret = wait_for_chhltd(hc_regs, &sub, pid);
+	if (ret < 0)
+		return ret;
+
+	if (in) {
+		xfer_len -= sub;
+
+		invalidate_dcache_range((unsigned long)aligned_buffer,
+					(unsigned long)aligned_buffer +
+					roundup(xfer_len, ARCH_DMA_MINALIGN));
+
+		memcpy(buffer, aligned_buffer, xfer_len);
+	}
+	*actual_len = xfer_len;
+
+	return ret;
+}
+
 int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev,
 	      unsigned long pipe, int *pid, int in, void *buffer, int len)
 {
@@ -776,7 +824,6 @@  int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev,
 	int eptype = dwc2_eptype[usb_pipetype(pipe)];
 	int done = 0;
 	int ret = 0;
-	uint32_t sub;
 	uint32_t xfer_len;
 	uint32_t num_packets;
 	int stop_transfer = 0;
@@ -795,11 +842,12 @@  int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev,
 	num_packets = max_xfer_len / max;
 	max_xfer_len = num_packets * max;
 
-	do {
-		/* Initialize channel */
-		dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, dev, devnum, ep, in,
-				eptype, max);
+	/* Initialize channel */
+	dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, dev, devnum, ep, in,
+			eptype, max);
 
+	do {
+		int actual_len = 0;
 		xfer_len = len - done;
 
 		if (xfer_len > max_xfer_len)
@@ -809,49 +857,17 @@  int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev,
 		else
 			num_packets = 1;
 
-		debug("%s: chunk: pid %d xfer_len %u pkts %u\n", __func__,
-		      *pid, xfer_len, num_packets);
+		ret = transfer_chunk(hc_regs, priv->aligned_buffer, pid,
+				     in, (char *)buffer + done, num_packets,
+				     xfer_len, &actual_len);
 
-		writel((xfer_len << DWC2_HCTSIZ_XFERSIZE_OFFSET) |
-		       (num_packets << DWC2_HCTSIZ_PKTCNT_OFFSET) |
-		       (*pid << DWC2_HCTSIZ_PID_OFFSET),
-		       &hc_regs->hctsiz);
-
-		if (!in && xfer_len) {
-			memcpy(priv->aligned_buffer, (char *)buffer + done,
-			       xfer_len);
-
-			flush_dcache_range((unsigned long)priv->aligned_buffer,
-				(unsigned long)((void *)priv->aligned_buffer +
-				roundup(xfer_len, ARCH_DMA_MINALIGN)));
-		}
-
-		writel(phys_to_bus((unsigned long)priv->aligned_buffer),
-		       &hc_regs->hcdma);
-
-		/* Set host channel enable after all other setup is complete. */
-		clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
-				DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS,
-				(1 << DWC2_HCCHAR_MULTICNT_OFFSET) |
-				DWC2_HCCHAR_CHEN);
-
-		ret = wait_for_chhltd(regs, &sub, pid);
 		if (ret)
 			break;
 
-		if (in) {
-			xfer_len -= sub;
-
-			invalidate_dcache_range((unsigned long)priv->aligned_buffer,
-				(unsigned long)((void *)priv->aligned_buffer +
-				roundup(xfer_len, ARCH_DMA_MINALIGN)));
-
-			memcpy(buffer + done, priv->aligned_buffer, xfer_len);
-			if (sub)
-				stop_transfer = 1;
-		}
+		if (actual_len < xfer_len)
+			stop_transfer = 1;
 
-		done += xfer_len;
+		done += actual_len;
 
 	} while ((done < len) && !stop_transfer);