[U-Boot] Cache issue on armv7
Kever Yang
kever.yang at rock-chips.com
Thu Mar 30 10:27:05 UTC 2017
I believe the cache API has some problem on armv7, at least
invalidate_dcache_range()
does not work as expected.
I get one issue on rk3288 dwc2 host driver:
- connect U-Disk and run 'usb start';
- write gpt table to it with 'gpt write usb 0 $partitions'
- check the partition table with 'part list usb 0'
It always get fail to find the gpt table event after RESET.
I do some debugging and found that the first package read by USB which
is MBR
always not correct for CPU while the USB bus/cable transfer the correct
data, the CPU
get the data just the same as there is no usb data transfer.
Here is the source code of dwc2 transfer, it has the correct cache
invalidate and
flush operation.
drivers/usb/host/dwc2.c
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;
}
I can fix this issue by a work around patch like this:
either add a flush or a invalidate cache before start usb transfer can
make the data correct.
+++ b/drivers/usb/host/dwc2.c
@@ -824,7 +824,10 @@ static int transfer_chunk(struct dwc2_hc_regs
*hc_regs, void *aligned_buffer,
(unsigned long)aligned_buffer +
roundup(xfer_len, ARCH_DMA_MINALIGN));
}
-
+ if (in && 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);
That's it, any one met problem like me?
Thanks,
- Kever
More information about the U-Boot
mailing list