[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