Commit daed3059 authored by Stefan Brüns's avatar Stefan Brüns Committed by Marek Vasut
Browse files

usb: dwc2: split transfer core from outer loop



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: default avatarStefan Brüns <stefan.bruens@rwth-aachen.de>
parent 03460cdc
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment