+static int transfer_chunk(struct dwc2_hc_regs *hc_regs, void *aligned_buffer,
+ u8 *pid, int in, void *buffer, int num_packets,
+ int xfer_len, int *actual_len, int odd_frame)
+{
+ 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 |
+ DWC2_HCCHAR_ODDFRM,
+ (1 << DWC2_HCCHAR_MULTICNT_OFFSET) |
+ (odd_frame << DWC2_HCCHAR_ODDFRM_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;
+}
+