[U-Boot] [RFC PATCH] usb: dwc2: handle bcm2835 phys->virt address translations

Stephen Warren swarren at wwwdotorg.org
Fri Mar 13 07:13:09 CET 2015


BCM2835 bus addresses use the top 2 bits to determine whether peripherals
use or bypass the GPU L1 and L2 cache. BCM2835-ARM-Peripherals.pdf states
that:

0: L1 & L2 cached
4: L2 cache coherent (non allocaing)
8: L2 cached only
c: Direct uncached.

That document also states that "Software accessing RAM using the DMA
engines must use bus addresses (base at 0xc0000000). However, this appears
to be incorrect since it does not work in practice on the bcm2835
(although it does on bcm2836). "usb start" causes some EABI function to
call raise(8), presumably due to corrupted USB IN data (the converse is
true on bcm2836; a value of 4 causes signals). However, I haven't
investigated the cause.

A value of 4 matches what the RPI Foundation's kernel; see the definition
of _REAL_BUS_OFFSET in arch/arm/mach-bcm2708/include/mach/memory.h. With
the code updated to implement a phys->bus translation by setting the top
two bits of DWC2 DMA addresses to 4, USB keyboard support appears stable.

A similar change is made for bcm2836 (RPi 2). I can't justify this value
since it doesn't match the RPi Foundation kernel. However, it does appear
to work for the built-in USB Ethernet at least.

Ideally, the bcm2835 SoC support would provide some common function for
any DMA-capable driver to call to perform the phys->bus translation,
rather than placing ifdefs in each driver file. However, I can't find
such a standard function in U-Boot.

I'm not sure if e.g. SDHCI needs this change too? It appears to work fine
without...

Cc: Eric Anholt <eric at anholt.net>
Cc: Gordon Hollingworth <gordon at holliweb.co.uk>
Signed-off-by: Stephen Warren <swarren at wwwdotorg.org>
---
(For those CC'd: note that this is a patch for U-Boot)

 drivers/usb/host/dwc2.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
index e370d29ffc8e..f647461eabbb 100644
--- a/drivers/usb/host/dwc2.c
+++ b/drivers/usb/host/dwc2.c
@@ -752,6 +752,7 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in,
 	uint32_t xfer_len;
 	uint32_t num_packets;
 	int stop_transfer = 0;
+	uint32_t dma_addr;
 
 	debug("%s: msg: pipe %lx pid %d in %d len %d\n", __func__, pipe, *pid,
 	      in, len);
@@ -792,7 +793,26 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in,
 		if (!in)
 			memcpy(aligned_buffer, (char *)buffer + done, len);
 
-		writel((uint32_t)aligned_buffer, &hc_regs->hcdma);
+		dma_addr = (uint32_t)aligned_buffer;
+#if defined(CONFIG_BCM2836)
+		/*
+		 * BCM2836 bus addresses use the top 2 bits to determine
+		 * whether peripherals use or bypass the GPU L1 and L2 cache.
+		 * While this doesn't match the value the RPi Foundation
+		 * kernel uses, it does work in practice for U-Boot.
+		 */
+		dma_addr |= 0xc0000000;
+#elif defined(CONFIG_BCM2835)
+		/*
+		 * BCM2835 bus addresses use the top 2 bits to determine
+		 * whether peripherals use or bypass the GPU L1 and L2 cache.
+		 * This phys->virt mapping matches what the RPI Foundation's
+		 * kernel does; see the definition of _REAL_BUS_OFFSET in
+		 * arch/arm/mach-bcm2708/include/mach/memory.h.
+		 */
+		dma_addr |= 0x40000000;
+#endif
+		writel(dma_addr, &hc_regs->hcdma);
 
 		/* Set host channel enable after all other setup is complete. */
 		clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
-- 
1.9.1



More information about the U-Boot mailing list