diff --git a/ChangeLog b/ChangeLog
index b32319cc3d03386fc12f9e3b674729bf6e91a14b..544508425492ba1d86aaaa18c998a2747bf83213 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5330,7 +5330,7 @@
 	* arch/arm/src/sama5/sam_dmac.c:  Finally after many bugfixes (the
 	  last being caching issues), the SAMA5 DMA support has been
 	  verified (with SPI) (2013-8-9).
-	* arch/arm/src/sama5/sam_memories.c and .h:  Central logic for
+	* arch/arm/src/sama5/sam_memories.c and .h:  Centralize logic for
 	  conversions between physical and virtual addresses (2013-8-9).
 	* arch/arm/src/sama5/sam_hsmci.c and sam34/sam_hsmci.c:  Correct a
 	  race condition in the SAMA5 HSCMI driver:  The tranfer done
@@ -5404,3 +5404,7 @@
 	  passes information associated with the RHport implicitly.  The klugey,
 	  procedural alternative was to add the function address to every
 	  interface method (which I started to do but backed above) (2013-8-13).
+	* arch/arm/src/sama5/sam_memories.c and .h:  Extended logic so do
+	  conversions from physical to virtual addresses (2013-8-14).
+	* arch/arm/src/sama5/sam_ohci.c:  Add D cache contols and conversion
+	  between physical and virtual address (2013-8-14).
diff --git a/arch/arm/src/sama5/Kconfig b/arch/arm/src/sama5/Kconfig
index 10bf8b69d90eb6cde5f6c8a6d766fa7c49bab8b5..085d2090ad65998539b5c5c046aa657bd67f71b4 100644
--- a/arch/arm/src/sama5/Kconfig
+++ b/arch/arm/src/sama5/Kconfig
@@ -348,15 +348,15 @@ config SAMA5_OHCI
 if SAMA5_OHCI
 config SAMA5_OHCI_NEDS
 	int "Number of endpoint descriptors"
-	default 2
+	default 6
 
 config SAMA5_OHCI_NTDS
 	int "Number of transfer descriptors"
-	default 3
+	default 9
 
 config SAMA5_OHCI_TDBUFFERS
 	int "Number of transfer descriptor buffers"
-	default 2
+	default 6
 
 config SAMA5_OHCI_TDBUFSIZE
 	int "Size of one transfer descriptor buffer"
diff --git a/arch/arm/src/sama5/sam_memories.c b/arch/arm/src/sama5/sam_memories.c
index 3a723f9960c325b7e7e79702ab079d1e2ac7f8d4..9167a432393152d623b14193e0095d4ce08f067d 100644
--- a/arch/arm/src/sama5/sam_memories.c
+++ b/arch/arm/src/sama5/sam_memories.c
@@ -58,19 +58,19 @@
  * Name: peripha_physregaddr
  *
  * Description:
- *   Give the virtual address of a peripheral A register, return the
+ *   Given the virtual address of a peripheral A register, return the
  *   physical address of the register
  *
  ****************************************************************************/
 
-static inline uintptr_t peripha_physregaddr(uintptr_t vregaddr)
+static inline uintptr_t peripha_physregaddr(uintptr_t virtregaddr)
 {
 #if SAM_PERIPHA_PSECTION != SAM_PERIPHA_VSECTION
   /* Get the offset into the virtual memory region section containing the
    * register
    */
 
-  uintptr_t sectoffset = vregaddr - SAM_PERIPHA_VSECTION;
+  uintptr_t sectoffset = virtregaddr - SAM_PERIPHA_VSECTION;
 
   /* Add that offset to the physical base address of the memory region */
 
@@ -79,7 +79,7 @@ static inline uintptr_t peripha_physregaddr(uintptr_t vregaddr)
 #else
   /* 1-to-1 mapping */
 
-  return vregaddr;
+  return virtregaddr;
 
 #endif
 }
@@ -88,19 +88,19 @@ static inline uintptr_t peripha_physregaddr(uintptr_t vregaddr)
  * Name: periphb_physregaddr
  *
  * Description:
- *   Give the virtual address of a peripheral B register, return the
+ *   Given the virtual address of a peripheral B register, return the
  *   physical address of the register
  *
  ****************************************************************************/
 
-static inline uintptr_t periphb_physregaddr(uintptr_t vregaddr)
+static inline uintptr_t periphb_physregaddr(uintptr_t virtregaddr)
 {
 #if SAM_PERIPHB_PSECTION != SAM_PERIPHB_VSECTION
   /* Get the offset into the virtual memory region section containing the
    * register
    */
 
-  uintptr_t sectoffset = vregaddr - SAM_PERIPHB_VSECTION;
+  uintptr_t sectoffset = virtregaddr - SAM_PERIPHB_VSECTION;
 
   /* Add that offset to the physical base address of the memory region */
 
@@ -109,7 +109,7 @@ static inline uintptr_t periphb_physregaddr(uintptr_t vregaddr)
 #else
   /* 1-to-1 mapping */
 
-  return vregaddr;
+  return virtregaddr;
 
 #endif
 }
@@ -118,19 +118,19 @@ static inline uintptr_t periphb_physregaddr(uintptr_t vregaddr)
  * Name: sysc_physregaddr
  *
  * Description:
- *   Give the virtual address of a system controller register, return the
+ *   Given the virtual address of a system controller register, return the
  *   physical address of the register
  *
  ****************************************************************************/
 
-static inline uintptr_t sysc_physregaddr(uintptr_t vregaddr)
+static inline uintptr_t sysc_physregaddr(uintptr_t virtregaddr)
 {
 #if SAM_SYSC_PSECTION != SAM_SYSC_VSECTION
   /* Get the offset into the virtual memory region section containing the
    * register
    */
 
-  uintptr_t sectoffset = vregaddr - SAM_SYSC_VSECTION;
+  uintptr_t sectoffset = virtregaddr - SAM_SYSC_VSECTION;
 
   /* Add that offset to the physical base address of the memory region */
 
@@ -139,7 +139,7 @@ static inline uintptr_t sysc_physregaddr(uintptr_t vregaddr)
 #else
   /* 1-to-1 mapping */
 
-  return vregaddr;
+  return virtregaddr;
 
 #endif
 }
@@ -148,19 +148,19 @@ static inline uintptr_t sysc_physregaddr(uintptr_t vregaddr)
  * Name: isram_physramaddr
  *
  * Description:
- *   Give the virtual address of an internal SRAM memory location, return the
+ *   Given the virtual address of an internal SRAM memory location, return the
  *   physical address of that location
  *
  ****************************************************************************/
 
-static inline uintptr_t isram_physramaddr(uintptr_t vregaddr)
+static inline uintptr_t isram_physramaddr(uintptr_t virtramaddr)
 {
 #if SAM_ISRAM_PSECTION != SAM_ISRAM_VSECTION
   /* Get the offset into the virtual memory region section containing the
    * RAM memory location.
    */
 
-  uintptr_t sectoffset = vregaddr - SAM_ISRAM_VSECTION;
+  uintptr_t sectoffset = virtramaddr - SAM_ISRAM_VSECTION;
 
   /* Add that offset to the physical base address of the memory region */
 
@@ -169,7 +169,7 @@ static inline uintptr_t isram_physramaddr(uintptr_t vregaddr)
 #else
   /* 1-to-1 mapping */
 
-  return vregaddr;
+  return virtramaddr;
 
 #endif
 }
@@ -178,20 +178,20 @@ static inline uintptr_t isram_physramaddr(uintptr_t vregaddr)
  * Name: sdram_physramaddr
  *
  * Description:
- *   Give the virtual address of an external SDRAM memory location, return
+ *   Given the virtual address of an external SDRAM memory location, return
  *   the physical address of that location
  *
  ****************************************************************************/
 
 #ifdef CONFIG_SAMA5_DDRCS
-static inline uintptr_t sdram_physramaddr(uintptr_t vregaddr)
+static inline uintptr_t sdram_physramaddr(uintptr_t virtramaddr)
 {
 #if SAM_DDRCS_PSECTION != SAM_DDRCS_VSECTION
   /* Get the offset into the virtual memory region section containing the
    * RAM memory location.
    */
 
-  uintptr_t sectoffset = vregaddr - SAM_DDRCS_VSECTION;
+  uintptr_t sectoffset = virtramaddr - SAM_DDRCS_VSECTION;
 
   /* Add that offset to the physical base address of the memory region */
 
@@ -200,7 +200,7 @@ static inline uintptr_t sdram_physramaddr(uintptr_t vregaddr)
 #else
   /* 1-to-1 mapping */
 
-  return vregaddr;
+  return virtramaddr;
 
 #endif
 }
@@ -210,19 +210,19 @@ static inline uintptr_t sdram_physramaddr(uintptr_t vregaddr)
  * Name: nfcsram_physramaddr
  *
  * Description:
- *   Give the virtual address of an NFC SRAM memory location, return the
+ *   Given the virtual address of an NFC SRAM memory location, return the
  *   physical address of that location
  *
  ****************************************************************************/
 
-static inline uintptr_t nfcsram_physramaddr(uintptr_t vregaddr)
+static inline uintptr_t nfcsram_physramaddr(uintptr_t virtramaddr)
 {
 #if SAM_NFCSRAM_PSECTION != SAM_NFCSRAM_VSECTION
   /* Get the offset into the virtual memory region section containing the
    * RAM memory location.
    */
 
-  uintptr_t sectoffset = vregaddr - SAM_NFCSRAM_VSECTION;
+  uintptr_t sectoffset = virtramaddr - SAM_NFCSRAM_VSECTION;
 
   /* Add that offset to the physical base address of the memory region */
 
@@ -231,7 +231,7 @@ static inline uintptr_t nfcsram_physramaddr(uintptr_t vregaddr)
 #else
   /* 1-to-1 mapping */
 
-  return vregaddr;
+  return virtramaddr;
 
 #endif
 }
@@ -240,19 +240,19 @@ static inline uintptr_t nfcsram_physramaddr(uintptr_t vregaddr)
  * Name: udphsram_physramaddr
  *
  * Description:
- *   Give the virtual address of an UDPH SRAM memory location, return the
+ *   Given the virtual address of an UDPH SRAM memory location, return the
  *   physical address of that location
  *
  ****************************************************************************/
 
-static inline uintptr_t udphsram_physramaddr(uintptr_t vregaddr)
+static inline uintptr_t udphsram_physramaddr(uintptr_t virtramaddr)
 {
 #if SAM_UDPHSRAM_PSECTION != SAM_UDPHSRAM_VSECTION
   /* Get the offset into the virtual memory region section containing the
    * RAM memory location.
    */
 
-  uintptr_t sectoffset = vregaddr - SAM_UDPHSRAM_VSECTION;
+  uintptr_t sectoffset = virtramaddr - SAM_UDPHSRAM_VSECTION;
 
   /* Add that offset to the physical base address of the memory region */
 
@@ -261,7 +261,7 @@ static inline uintptr_t udphsram_physramaddr(uintptr_t vregaddr)
 #else
   /* 1-to-1 mapping */
 
-  return vregaddr;
+  return virtramaddr;
 
 #endif
 }
@@ -270,21 +270,21 @@ static inline uintptr_t udphsram_physramaddr(uintptr_t vregaddr)
  * Name: ebics0_physramaddr
  *
  * Description:
- *   Give the virtual address of an external CS0 SRAM memory location,
+ *   Given the virtual address of an external CS0 SRAM memory location,
  *   return the physical address of that location
  *
  ****************************************************************************/
 
 #if defined(CONFIG_SAMA5_EBICS0) && (defined(CONFIG_SAMA5_EBICS0_SRAM) || \
     defined(CONFIG_SAMA5_EBICS0_PSRAM))
-static inline uintptr_t ebics0_physramaddr(uintptr_t vregaddr)
+static inline uintptr_t ebics0_physramaddr(uintptr_t virtramaddr)
 {
 #if SAM_EBICS0_PSECTION != SAM_EBICS0_VSECTION
   /* Get the offset into the virtual memory region section containing the
    * RAM memory location.
    */
 
-  uintptr_t sectoffset = vregaddr - SAM_EBICS0_VSECTION;
+  uintptr_t sectoffset = virtramaddr - SAM_EBICS0_VSECTION;
 
   /* Add that offset to the physical base address of the memory region */
 
@@ -293,7 +293,7 @@ static inline uintptr_t ebics0_physramaddr(uintptr_t vregaddr)
 #else
   /* 1-to-1 mapping */
 
-  return vregaddr;
+  return virtramaddr;
 
 #endif
 }
@@ -303,21 +303,21 @@ static inline uintptr_t ebics0_physramaddr(uintptr_t vregaddr)
  * Name: ebics1_physramaddr
  *
  * Description:
- *   Give the virtual address of an external CS1 SRAM memory location,
+ *   Given the virtual address of an external CS1 SRAM memory location,
  *   return the physical address of that location
  *
  ****************************************************************************/
 
 #if defined(CONFIG_SAMA5_EBICS1) && (defined(CONFIG_SAMA5_EBICS1_SRAM) || \
     defined(CONFIG_SAMA5_EBICS1_PSRAM))
-static inline uintptr_t ebics1_physramaddr(uintptr_t vregaddr)
+static inline uintptr_t ebics1_physramaddr(uintptr_t virtramaddr)
 {
 #if SAM_EBICS1_PSECTION != SAM_EBICS1_VSECTION
   /* Get the offset into the virtual memory region section containing the
    * RAM memory location.
    */
 
-  uintptr_t sectoffset = vregaddr - SAM_EBICS1_VSECTION;
+  uintptr_t sectoffset = virtramaddr - SAM_EBICS1_VSECTION;
 
   /* Add that offset to the physical base address of the memory region */
 
@@ -326,7 +326,7 @@ static inline uintptr_t ebics1_physramaddr(uintptr_t vregaddr)
 #else
   /* 1-to-1 mapping */
 
-  return vregaddr;
+  return virtramaddr;
 
 #endif
 }
@@ -336,21 +336,21 @@ static inline uintptr_t ebics1_physramaddr(uintptr_t vregaddr)
  * Name: ebics2_physramaddr
  *
  * Description:
- *   Give the virtual address of an external CS2 SRAM memory location,
+ *   Given the virtual address of an external CS2 SRAM memory location,
  *   return the physical address of that location
  *
  ****************************************************************************/
 
 #if defined(CONFIG_SAMA5_EBICS2) && (defined(CONFIG_SAMA5_EBICS2_SRAM) || \
     defined(CONFIG_SAMA5_EBICS2_PSRAM))
-static inline uintptr_t ebics2_physramaddr(uintptr_t vregaddr)
+static inline uintptr_t ebics2_physramaddr(uintptr_t virtramaddr)
 {
 #if SAM_EBICS2_PSECTION != SAM_EBICS2_VSECTION
   /* Get the offset into the virtual memory region section containing the
    * RAM memory location.
    */
 
-  uintptr_t sectoffset = vregaddr - SAM_EBICS2_VSECTION;
+  uintptr_t sectoffset = virtramaddr - SAM_EBICS2_VSECTION;
 
   /* Add that offset to the physical base address of the memory region */
 
@@ -359,7 +359,7 @@ static inline uintptr_t ebics2_physramaddr(uintptr_t vregaddr)
 #else
   /* 1-to-1 mapping */
 
-  return vregaddr;
+  return virtramaddr;
 
 #endif
 }
@@ -369,21 +369,21 @@ static inline uintptr_t ebics2_physramaddr(uintptr_t vregaddr)
  * Name: ebics3_physramaddr
  *
  * Description:
- *   Give the virtual address of an external CS3 SRAM memory location,
+ *   Given the virtual address of an external CS3 SRAM memory location,
  *   return the physical address of that location
  *
  ****************************************************************************/
 
 #if defined(CONFIG_SAMA5_EBICS3) && (defined(CONFIG_SAMA5_EBICS3_SRAM) || \
     defined(CONFIG_SAMA5_EBICS3_PSRAM))
-static inline uintptr_t ebics3_physramaddr(uintptr_t vregaddr)
+static inline uintptr_t ebics3_physramaddr(uintptr_t virtramaddr)
 {
 #if SAM_EBICS3_PSECTION != SAM_EBICS3_VSECTION
   /* Get the offset into the virtual memory region section containing the
    * RAM memory location.
    */
 
-  uintptr_t sectoffset = vregaddr - SAM_EBICS3_VSECTION;
+  uintptr_t sectoffset = virtramaddr - SAM_EBICS3_VSECTION;
 
   /* Add that offset to the physical base address of the memory region */
 
@@ -392,7 +392,261 @@ static inline uintptr_t ebics3_physramaddr(uintptr_t vregaddr)
 #else
   /* 1-to-1 mapping */
 
-  return vregaddr;
+  return virtramaddr;
+
+#endif
+}
+#endif
+
+/****************************************************************************
+ * Name: isram_virtramaddr
+ *
+ * Description:
+ *   Given the physical address of an internal SRAM memory location, return
+ *   the virtual address of that location
+ *
+ ****************************************************************************/
+
+static inline uintptr_t isram_virtramaddr(uintptr_t physramaddr)
+{
+#if SAM_ISRAM_PSECTION != SAM_ISRAM_VSECTION
+  /* Get the offset into the virtual memory region section containing the
+   * RAM memory location.
+   */
+
+  uintptr_t sectoffset = physramaddr - SAM_ISRAM_PSECTION;
+
+  /* Add that offset to the physical base address of the memory region */
+
+  return SAM_ISRAM_VSECTION + sectoffset;
+
+#else
+  /* 1-to-1 mapping */
+
+  return physramaddr;
+
+#endif
+}
+
+/****************************************************************************
+ * Name: sdram_virtramaddr
+ *
+ * Description:
+ *   Given the physical address of an external SDRAM memory location, return
+ *   the virtual address of that location
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SAMA5_DDRCS
+static inline uintptr_t sdram_virtramaddr(uintptr_t physramaddr)
+{
+#if SAM_DDRCS_PSECTION != SAM_DDRCS_VSECTION
+  /* Get the offset into the virtual memory region section containing the
+   * RAM memory location.
+   */
+
+  uintptr_t sectoffset = physramaddr - SAM_DDRCS_PSECTION;
+
+  /* Add that offset to the physical base address of the memory region */
+
+  return SAM_DDRCS_VSECTION + sectoffset;
+
+#else
+  /* 1-to-1 mapping */
+
+  return physramaddr;
+
+#endif
+}
+#endif
+
+/****************************************************************************
+ * Name: nfcsram_virtramaddr
+ *
+ * Description:
+ *   Given the physical address of an NFC SRAM memory location, return the
+ *   virtual address of that location
+ *
+ ****************************************************************************/
+
+static inline uintptr_t nfcsram_virtramaddr(uintptr_t physramaddr)
+{
+#if SAM_NFCSRAM_PSECTION != SAM_NFCSRAM_VSECTION
+  /* Get the offset into the virtual memory region section containing the
+   * RAM memory location.
+   */
+
+  uintptr_t sectoffset = physramaddr - SAM_NFCSRAM_PSECTION;
+
+  /* Add that offset to the physical base address of the memory region */
+
+  return SAM_NFCSRAM_VSECTION + sectoffset;
+
+#else
+  /* 1-to-1 mapping */
+
+  return physramaddr;
+
+#endif
+}
+
+/****************************************************************************
+ * Name: udphsram_virtramaddr
+ *
+ * Description:
+ *   Given the physical address of an UDPH SRAM memory location, return the
+ *   virtual address of that location
+ *
+ ****************************************************************************/
+
+static inline uintptr_t udphsram_virtramaddr(uintptr_t physramaddr)
+{
+#if SAM_UDPHSRAM_PSECTION != SAM_UDPHSRAM_VSECTION
+  /* Get the offset into the virtual memory region section containing the
+   * RAM memory location.
+   */
+
+  uintptr_t sectoffset = physramaddr - SAM_UDPHSRAM_PSECTION;
+
+  /* Add that offset to the physical base address of the memory region */
+
+  return SAM_UDPHSRAM_VSECTION + sectoffset;
+
+#else
+  /* 1-to-1 mapping */
+
+  return physramaddr;
+
+#endif
+}
+
+/****************************************************************************
+ * Name: ebics0_virtramaddr
+ *
+ * Description:
+ *   Given the physical address of an external CS0 SRAM memory location,
+ *   return the virtual address of that location
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_SAMA5_EBICS0) && (defined(CONFIG_SAMA5_EBICS0_SRAM) || \
+    defined(CONFIG_SAMA5_EBICS0_PSRAM))
+static inline uintptr_t ebics0_virtramaddr(uintptr_t physramaddr)
+{
+#if SAM_EBICS0_PSECTION != SAM_EBICS0_VSECTION
+  /* Get the offset into the virtual memory region section containing the
+   * RAM memory location.
+   */
+
+  uintptr_t sectoffset = physramaddr - SAM_EBICS0_PSECTION;
+
+  /* Add that offset to the physical base address of the memory region */
+
+  return SAM_EBICS0_VSECTION + sectoffset;
+
+#else
+  /* 1-to-1 mapping */
+
+  return physramaddr;
+
+#endif
+}
+#endif
+
+/****************************************************************************
+ * Name: ebics1_virtramaddr
+ *
+ * Description:
+ *   Given the physical address of an external CS1 SRAM memory location,
+ *   return the virtual address of that location
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_SAMA5_EBICS1) && (defined(CONFIG_SAMA5_EBICS1_SRAM) || \
+    defined(CONFIG_SAMA5_EBICS1_PSRAM))
+static inline uintptr_t ebics1_virtramaddr(uintptr_t physramaddr)
+{
+#if SAM_EBICS1_PSECTION != SAM_EBICS1_VSECTION
+  /* Get the offset into the virtual memory region section containing the
+   * RAM memory location.
+   */
+
+  uintptr_t sectoffset = physramaddr - SAM_EBICS1_PSECTION;
+
+  /* Add that offset to the physical base address of the memory region */
+
+  return SAM_EBICS1_VSECTION + sectoffset;
+
+#else
+  /* 1-to-1 mapping */
+
+  return physramaddr;
+
+#endif
+}
+#endif
+
+/****************************************************************************
+ * Name: ebics2_virtramaddr
+ *
+ * Description:
+ *   Given the physical address of an external CS2 SRAM memory location,
+ *   return the virtual address of that location
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_SAMA5_EBICS2) && (defined(CONFIG_SAMA5_EBICS2_SRAM) || \
+    defined(CONFIG_SAMA5_EBICS2_PSRAM))
+static inline uintptr_t ebics2_virtramaddr(uintptr_t physramaddr)
+{
+#if SAM_EBICS2_PSECTION != SAM_EBICS2_VSECTION
+  /* Get the offset into the virtual memory region section containing the
+   * RAM memory location.
+   */
+
+  uintptr_t sectoffset = physramaddr - SAM_EBICS2_PSECTION;
+
+  /* Add that offset to the physical base address of the memory region */
+
+  return SAM_EBICS2_VSECTION + sectoffset;
+
+#else
+  /* 1-to-1 mapping */
+
+  return physramaddr;
+
+#endif
+}
+#endif
+
+/****************************************************************************
+ * Name: ebics3_virtramaddr
+ *
+ * Description:
+ *   Given the physical address of an external CS3 SRAM memory location,
+ *   return the virtual address of that location
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_SAMA5_EBICS3) && (defined(CONFIG_SAMA5_EBICS3_SRAM) || \
+    defined(CONFIG_SAMA5_EBICS3_PSRAM))
+static inline uintptr_t ebics3_virtramaddr(uintptr_t physramaddr)
+{
+#if SAM_EBICS3_PSECTION != SAM_EBICS3_VSECTION
+  /* Get the offset into the virtual memory region section containing the
+   * RAM memory location.
+   */
+
+  uintptr_t sectoffset = physramaddr - SAM_EBICS3_PSECTION;
+
+  /* Add that offset to the physical base address of the memory region */
+
+  return SAM_EBICS3_VSECTION + sectoffset;
+
+#else
+  /* 1-to-1 mapping */
+
+  return physramaddr;
 
 #endif
 }
@@ -406,35 +660,35 @@ static inline uintptr_t ebics3_physramaddr(uintptr_t vregaddr)
  * Name: sam_physregaddr
  *
  * Description:
- *   Give the virtual address of a register, return the physical address of
+ *   Given the virtual address of a register, return the physical address of
  *   the register
  *
  ****************************************************************************/
 
-uintptr_t sam_physregaddr(uintptr_t vregaddr)
+uintptr_t sam_physregaddr(uintptr_t virtregaddr)
 {
   /* Check for a peripheral A register */
 
-  if (vregaddr >= SAM_PERIPHA_VSECTION &&
-      vregaddr < (SAM_PERIPHA_VSECTION + SAM_PERIPHA_SIZE))
+  if (virtregaddr >= SAM_PERIPHA_VSECTION &&
+      virtregaddr < (SAM_PERIPHA_VSECTION + SAM_PERIPHA_SIZE))
     {
-      return peripha_physregaddr(vregaddr);
+      return peripha_physregaddr(virtregaddr);
     }
 
   /* Check for a peripheral A register */
 
-  else if (vregaddr >= SAM_PERIPHB_VSECTION &&
-           vregaddr < (SAM_PERIPHB_VSECTION + SAM_PERIPHB_SIZE))
+  else if (virtregaddr >= SAM_PERIPHB_VSECTION &&
+           virtregaddr < (SAM_PERIPHB_VSECTION + SAM_PERIPHB_SIZE))
     {
-      return periphb_physregaddr(vregaddr);
+      return periphb_physregaddr(virtregaddr);
     }
 
   /* Check for a system controller register */
 
-  else if (vregaddr >= SAM_SYSC_VSECTION &&
-           vregaddr < (SAM_SYSC_VSECTION + SAM_SYSC_SIZE))
+  else if (virtregaddr >= SAM_SYSC_VSECTION &&
+           virtregaddr < (SAM_SYSC_VSECTION + SAM_SYSC_SIZE))
     {
-      return sysc_physregaddr(vregaddr);
+      return sysc_physregaddr(virtregaddr);
     }
 
   /* We will not get here unless we are called with an invalid register
@@ -442,64 +696,163 @@ uintptr_t sam_physregaddr(uintptr_t vregaddr)
    */
 
   DEBUGPANIC();
-  return vregaddr;
+  return virtregaddr;
 }
 
 /****************************************************************************
  * Name: sam_physramaddr
  *
  * Description:
- *   Give the virtual address of a RAM memory location, return the physical
+ *   Given the virtual address of a RAM memory location, return the physical
+ *   address of that location.
+ *
+ ****************************************************************************/
+
+uintptr_t sam_physramaddr(uintptr_t virtramaddr)
+{
+  /* Check for internal SRAM.  We we assume that ISRAM0 and ISRAM1 are
+   * contiguous.
+   */
+
+  if (virtramaddr >= SAM_ISRAM_VSECTION &&
+      virtramaddr < (SAM_ISRAM_VSECTION + SAM_ISRAM_SIZE))
+    {
+      return isram_physramaddr(virtramaddr);
+    }
+
+#ifdef CONFIG_SAMA5_DDRCS
+  /* Check for external SDRAM */
+
+  else if (virtramaddr >= SAM_DDRCS_VSECTION &&
+           virtramaddr < (SAM_DDRCS_VSECTION + SAMA5_DDRCS_SIZE))
+    {
+      return sdram_physramaddr(virtramaddr);
+    }
+#endif
+
+  /* Check for NFCS SRAM.  */
+
+  if (virtramaddr >= SAM_NFCSRAM_VSECTION &&
+      virtramaddr < (SAM_NFCSRAM_VSECTION + SAM_NFCSRAM_SIZE))
+    {
+      return nfcsram_physramaddr(virtramaddr);
+    }
+
+  /* Check for UDPH SRAM.  */
+
+  if (virtramaddr >= SAM_UDPHSRAM_VSECTION &&
+      virtramaddr < (SAM_UDPHSRAM_VSECTION + SAM_UDPHSRAM_SIZE))
+    {
+      return udphsram_physramaddr(virtramaddr);
+    }
+
+#if defined(CONFIG_SAMA5_EBICS0) && (defined(CONFIG_SAMA5_EBICS0_SRAM) || \
+    defined(CONFIG_SAMA5_EBICS0_PSRAM))
+  /* Check for external SRAM or PSRAM on CS0 */
+
+  else if (virtramaddr >= SAM_EBICS0_VSECTION &&
+           virtramaddr < (SAM_EBICS0_VSECTION + SAMA5_EBICS0_SIZE))
+    {
+      return ebics0_physramaddr(virtramaddr);
+    }
+#endif
+
+#if defined(CONFIG_SAMA5_EBICS1) && (defined(CONFIG_SAMA5_EBICS1_SRAM) || \
+    defined(CONFIG_SAMA5_EBICS1_PSRAM))
+  /* Check for external SRAM or PSRAM on CS1 */
+
+  else if (virtramaddr >= SAM_EBICS1_VSECTION &&
+           virtramaddr < (SAM_EBICS1_VSECTION + SAMA5_EBICS1_SIZE))
+    {
+      return ebics1_physramaddr(virtramaddr);
+    }
+#endif
+
+#if defined(CONFIG_SAMA5_EBICS2) && (defined(CONFIG_SAMA5_EBICS2_SRAM) || \
+    defined(CONFIG_SAMA5_EBICS2_PSRAM))
+  /* Check for external SRAM or PSRAM on CS2 */
+
+  else if (virtramaddr >= SAM_EBICS2_VSECTION &&
+           virtramaddr < (SAM_EBICS2_VSECTION + SAMA5_EBICS2_SIZE))
+    {
+      return ebics2_physramaddr(virtramaddr);
+    }
+#endif
+
+#if defined(CONFIG_SAMA5_EBICS3) && (defined(CONFIG_SAMA5_EBICS3_SRAM) || \
+    defined(CONFIG_SAMA5_EBICS3_PSRAM))
+  /* Check for external SRAM or PSRAM on CS3 */
+
+  else if (virtramaddr >= SAM_EBICS3_VSECTION &&
+           virtramaddr < (SAM_EBICS3_VSECTION + SAMA5_EBICS3_SIZE))
+    {
+      return ebics3_physramaddr(virtramaddr);
+    }
+#endif
+
+  /* We will not get here unless we are called with an invalid or
+   * unsupported RAM address
+   */
+
+  DEBUGPANIC();
+  return virtramaddr;
+}
+
+/****************************************************************************
+ * Name: sam_virtramaddr
+ *
+ * Description:
+ *   Give the phsical address of a RAM memory location, return the virtual
  *   address of that location.
  *
  ****************************************************************************/
 
-uintptr_t sam_physramaddr(uintptr_t vregaddr)
+uintptr_t sam_virtramaddr(uintptr_t physramaddr)
 {
   /* Check for internal SRAM.  We we assume that ISRAM0 and ISRAM1 are
    * contiguous.
    */
 
-  if (vregaddr >= SAM_ISRAM_VSECTION &&
-      vregaddr < (SAM_ISRAM_VSECTION + SAM_ISRAM_SIZE))
+  if (physramaddr >= SAM_ISRAM_PSECTION &&
+      physramaddr < (SAM_ISRAM_PSECTION + SAM_ISRAM_SIZE))
     {
-      return isram_physramaddr(vregaddr);
+      return isram_virtramaddr(physramaddr);
     }
 
 #ifdef CONFIG_SAMA5_DDRCS
   /* Check for external SDRAM */
 
-  else if (vregaddr >= SAM_DDRCS_VSECTION &&
-           vregaddr < (SAM_DDRCS_VSECTION + SAMA5_DDRCS_SIZE))
+  else if (physramaddr >= SAM_DDRCS_PSECTION &&
+           physramaddr < (SAM_DDRCS_PSECTION + SAMA5_DDRCS_SIZE))
     {
-      return sdram_physramaddr(vregaddr);
+      return sdram_virtramaddr(physramaddr);
     }
 #endif
 
   /* Check for NFCS SRAM.  */
 
-  if (vregaddr >= SAM_NFCSRAM_VSECTION &&
-      vregaddr < (SAM_NFCSRAM_VSECTION + SAM_NFCSRAM_SIZE))
+  if (physramaddr >= SAM_NFCSRAM_PSECTION &&
+      physramaddr < (SAM_NFCSRAM_PSECTION + SAM_NFCSRAM_SIZE))
     {
-      return nfcsram_physramaddr(vregaddr);
+      return nfcsram_virtramaddr(physramaddr);
     }
 
   /* Check for UDPH SRAM.  */
 
-  if (vregaddr >= SAM_UDPHSRAM_VSECTION &&
-      vregaddr < (SAM_UDPHSRAM_VSECTION + SAM_UDPHSRAM_SIZE))
+  if (physramaddr >= SAM_UDPHSRAM_PSECTION &&
+      physramaddr < (SAM_UDPHSRAM_PSECTION + SAM_UDPHSRAM_SIZE))
     {
-      return udphsram_physramaddr(vregaddr);
+      return udphsram_virtramaddr(physramaddr);
     }
 
 #if defined(CONFIG_SAMA5_EBICS0) && (defined(CONFIG_SAMA5_EBICS0_SRAM) || \
     defined(CONFIG_SAMA5_EBICS0_PSRAM))
   /* Check for external SRAM or PSRAM on CS0 */
 
-  else if (vregaddr >= SAM_EBICS0_VSECTION &&
-           vregaddr < (SAM_EBICS0_VSECTION + SAMA5_EBICS0_SIZE))
+  else if (physramaddr >= SAM_EBICS0_PSECTION &&
+           physramaddr < (SAM_EBICS0_PSECTION + SAMA5_EBICS0_SIZE))
     {
-      return ebics0_physramaddr(vregaddr);
+      return ebics0_virtramaddr(physramaddr);
     }
 #endif
 
@@ -507,10 +860,10 @@ uintptr_t sam_physramaddr(uintptr_t vregaddr)
     defined(CONFIG_SAMA5_EBICS1_PSRAM))
   /* Check for external SRAM or PSRAM on CS1 */
 
-  else if (vregaddr >= SAM_EBICS1_VSECTION &&
-           vregaddr < (SAM_EBICS1_VSECTION + SAMA5_EBICS1_SIZE))
+  else if (physramaddr >= SAM_EBICS1_PSECTION &&
+           physramaddr < (SAM_EBICS1_PSECTION + SAMA5_EBICS1_SIZE))
     {
-      return ebics1_physramaddr(vregaddr);
+      return ebics1_virtramaddr(physramaddr);
     }
 #endif
 
@@ -518,10 +871,10 @@ uintptr_t sam_physramaddr(uintptr_t vregaddr)
     defined(CONFIG_SAMA5_EBICS2_PSRAM))
   /* Check for external SRAM or PSRAM on CS2 */
 
-  else if (vregaddr >= SAM_EBICS2_VSECTION &&
-           vregaddr < (SAM_EBICS2_VSECTION + SAMA5_EBICS2_SIZE))
+  else if (physramaddr >= SAM_EBICS2_PSECTION &&
+           physramaddr < (SAM_EBICS2_PSECTION + SAMA5_EBICS2_SIZE))
     {
-      return ebics2_physramaddr(vregaddr);
+      return ebics2_virtramaddr(physramaddr);
     }
 #endif
 
@@ -529,10 +882,10 @@ uintptr_t sam_physramaddr(uintptr_t vregaddr)
     defined(CONFIG_SAMA5_EBICS3_PSRAM))
   /* Check for external SRAM or PSRAM on CS3 */
 
-  else if (vregaddr >= SAM_EBICS3_VSECTION &&
-           vregaddr < (SAM_EBICS3_VSECTION + SAMA5_EBICS3_SIZE))
+  else if (physramaddr >= SAM_EBICS3_PSECTION &&
+           physramaddr < (SAM_EBICS3_PSECTION + SAMA5_EBICS3_SIZE))
     {
-      return ebics3_physramaddr(vregaddr);
+      return ebics3_virtramaddr(physramaddr);
     }
 #endif
 
@@ -541,5 +894,5 @@ uintptr_t sam_physramaddr(uintptr_t vregaddr)
    */
 
   DEBUGPANIC();
-  return vregaddr;
+  return physramaddr;
 }
diff --git a/arch/arm/src/sama5/sam_memories.h b/arch/arm/src/sama5/sam_memories.h
index e360759d2e79bef62a4c9bbb8e614df45ead2835..308b06c138270cec1575a9066122c189edfb865c 100644
--- a/arch/arm/src/sama5/sam_memories.h
+++ b/arch/arm/src/sama5/sam_memories.h
@@ -82,7 +82,7 @@ extern "C"
  *
  ****************************************************************************/
 
-uintptr_t sam_physregaddr(uintptr_t vregaddr);
+uintptr_t sam_physregaddr(uintptr_t virtregaddr);
 
 /****************************************************************************
  * Name: sam_physramaddr
@@ -93,7 +93,18 @@ uintptr_t sam_physregaddr(uintptr_t vregaddr);
  *
  ****************************************************************************/
 
-uintptr_t sam_physramaddr(uintptr_t vregaddr);
+uintptr_t sam_physramaddr(uintptr_t vramaddr);
+
+/****************************************************************************
+ * Name: sam_virtramaddr
+ *
+ * Description:
+ *   Give the phsical address of a RAM memory location, return the virtual
+ *   address of that location.
+ *
+ ****************************************************************************/
+
+uintptr_t sam_virtramaddr(uintptr_t physramaddr);
 
 #undef EXTERN
 #if defined(__cplusplus)
diff --git a/arch/arm/src/sama5/sam_ohci.c b/arch/arm/src/sama5/sam_ohci.c
index 0a59faf86776d5b4e9fe02f5ace2d8bcfce5e26e..b7bb025e0f237e5828ed13835f2ca73fc647709d 100644
--- a/arch/arm/src/sama5/sam_ohci.c
+++ b/arch/arm/src/sama5/sam_ohci.c
@@ -61,8 +61,10 @@
 #include "up_arch.h"
 #include "up_internal.h"
 
+#include "cache.h"
 #include "chip.h"
 #include "sam_periphclks.h"
+#include "sam_memories.h"
 #include "sam_usbhost.h"
 #include "chip/sam_pmc.h"
 #include "chip/sam_sfr.h"
@@ -73,14 +75,6 @@
  *******************************************************************************/
 /* Configuration ***************************************************************/
 
-/* Fixed endpoint descriptor size.  The actual size required by the hardware is only
- * 16 bytes, however, we set aside an additional 16 bytes for for internal use by
- * the OHCI host driver.  16-bytes is set aside because the EDs must still be
- * aligned to 16-byte boundaries.
- */
-
-#define SAM_ED_SIZE 32
-
 /* Configurable number of user endpoint descriptors (EDs).  This number excludes
  * the control endpoint that is always allocated.
  */
@@ -89,14 +83,6 @@
 #  define CONFIG_SAMA5_OHCI_NEDS 2
 #endif
 
-/* Fixed transfer descriptor size.  The actual size required by the hardware is
- * only 16 bytes, however, we set aside an additional 16 bytes for for internal
- * use by the OHCI host driver.  16-bytes is set aside because the TDs must still
- * be aligned to 16-byte boundaries.
- */
-
-#define SAM_TD_SIZE 32
-
 /* Configurable number of user transfer descriptors (TDs).  */
 
 #ifndef CONFIG_SAMA5_OHCI_NTDS
@@ -198,7 +184,7 @@ struct sam_rhport_s
   struct usbhost_class_s *class;
 };
 
-/* This structure retains the state of the USB host controller */
+/* This structure retains the overall state of the USB host controller */
 
 struct sam_ohci_s
 {
@@ -219,27 +205,34 @@ struct sam_ohci_s
 };
 
 /* The OCHI expects the size of an endpoint descriptor to be 16 bytes.
- * However, the size allocated for an endpoint descriptor is 32 bytes in
- * sam_ohciram.h.  This extra 16-bytes is used by the OHCI host driver in
- * order to maintain additional endpoint-specific data.
+ * However, the size allocated for an endpoint descriptor is 32 bytes.  This
+ * extra 16-bytes is used by the OHCI host driver in order to maintain
+ * additional endpoint-specific data.
  */
 
+#define SAMD_ED_PADSIZE      (12 - sizeof(sem_t))
+
 struct sam_ed_s
 {
   /* Hardware specific fields */
 
-  struct ohci_ed_s hw;
+  struct ohci_ed_s hw;        /* 0-15 */
 
   /* Software specific fields */
 
-  uint8_t          xfrtype;   /* Transfer type.  See SB_EP_ATTR_XFER_* in usb.h */
-  uint8_t          interval;  /* Periodic EP polling interval: 2, 4, 6, 16, or 32 */
-  volatile uint8_t tdstatus;  /* TD control status bits from last Writeback Done Head event */
-  volatile bool    wdhwait;   /* TRUE: Thread is waiting for WDH interrupt */
-  sem_t            wdhsem;    /* Semaphore used to wait for Writeback Done Head event */
-                              /* Unused bytes follow, depending on the size of sem_t */
+  uint8_t          xfrtype;   /* 16: Transfer type.  See SB_EP_ATTR_XFER_* in usb.h */
+  uint8_t          interval;  /* 17: Periodic EP polling interval: 2, 4, 6, 16, or 32 */
+  volatile uint8_t tdstatus;  /* 18: TD control status bits from last Writeback Done Head event */
+  volatile bool    wdhwait;   /* 19: TRUE: Thread is waiting for WDH interrupt */
+  sem_t            wdhsem;    /* 20-23: Semaphore used to wait for Writeback Done Head event */
+
+  /* Padding to 32-bytes follow.  The amount of padding depends on the size of sem_t */
+
+  uint8_t          pad[SAMD_ED_PADSIZE];
 };
 
+#define SIZEOF_SAM_ED_S 32
+
 /* The OCHI expects the size of an transfer descriptor to be 16 bytes.
  * However, the size allocated for an endpoint descriptor is 32 bytes in
  * RAM.  This extra 16-bytes is used by the OHCI host driver in order to
@@ -250,15 +243,17 @@ struct sam_gtd_s
 {
   /* Hardware specific fields */
 
-  struct ohci_gtd_s hw;
+  struct ohci_gtd_s hw;      /* 0-15 */
 
   /* Software specific fields */
 
-  struct sam_ed_s *ed;       /* Pointer to parent ED */
-  bool             prealloc; /* Indicates a pre-allocated ED */
-  uint8_t          pad[11];
+  struct sam_ed_s *ed;       /* 16-19: Pointer to parent ED */
+  bool             prealloc; /* 20:    Indicates a pre-allocated ED */
+  uint8_t          pad[11];  /* 21-31: Pad to 32 bytes */
 };
 
+#define SIZEOF_SAM_TD_S 32
+
 /* The following is used to manage lists of free EDs, TDs, and TD buffers */
 
 struct sam_list_s
@@ -730,11 +725,14 @@ static inline int sam_addbulked(struct sam_ed_s *ed)
 {
 #ifndef CONFIG_USBHOST_BULK_DISABLE
   uint32_t regval;
+  uintptr_t physed;
 
   /* Add the new bulk ED to the head of the bulk list */
 
   ed->hw.nexted = sam_getreg(SAM_USBHOST_BULKHEADED);
-  sam_putreg((uint32_t)ed, SAM_USBHOST_BULKHEADED);
+
+  physed = sam_physramaddr((uintptr_t)ed);
+  sam_putreg((uint32_t)physed, SAM_USBHOST_BULKHEADED);
 
   /* BulkListEnable. This bit is set to enable the processing of the
    * Bulk list.  Note: once enabled, it remains.  We really should
@@ -763,14 +761,15 @@ static inline int sam_rembulked(struct sam_ed_s *ed)
 #ifndef CONFIG_USBHOST_BULK_DISABLE
   struct sam_ed_s *curr;
   struct sam_ed_s *prev;
-  uint32_t         regval;
+  uintptr_t physed;
+  uint32_t regval;
 
   /* Find the ED in the bulk list.  NOTE: We really should never be mucking
    * with the bulk list while BLE is set.
    */
 
-  for (curr = (struct sam_ed_s *)sam_getreg(SAM_USBHOST_BULKHEADED),
-       prev = NULL;
+  physed = sam_getreg(SAM_USBHOST_BULKHEADED);
+  for (curr = (struct sam_ed_s *)sam_virtramaddr(physed), prev = NULL;
        curr && curr != ed;
        prev = curr, curr = (struct sam_ed_s *)curr->hw.nexted);
 
@@ -897,7 +896,8 @@ static inline int sam_addinted(const FAR struct usbhost_epdesc_s *epdesc,
 #ifndef CONFIG_USBHOST_INT_DISABLE
   unsigned int interval;
   unsigned int offset;
-  uint32_t head;
+  uintptr_t physed;
+  uintptr_t physhead;
   uint32_t regval;
 
   /* Disable periodic list processing.  Does this take effect immediately?  Or
@@ -949,11 +949,12 @@ static inline int sam_addinted(const FAR struct usbhost_epdesc_s *epdesc,
     }
   uvdbg("min interval: %d offset: %d\n", interval, offset);
 
-  /* Get the head of the first of the duplicated entries.  The first offset
-   * entry is always guaranteed to contain the common ED list head.
+  /* Get the (physical) head of the first of the duplicated entries.  The
+   * first offset entry is always guaranteed to contain the common ED list
+   * head.
    */
 
-  head = g_hcca.inttbl[offset];
+  physhead = g_hcca.inttbl[offset];
 
   /* Clear all current entries in the interrupt table for this direction */
 
@@ -964,9 +965,10 @@ static inline int sam_addinted(const FAR struct usbhost_epdesc_s *epdesc,
    * interrupt table.
    */
 
-  ed->hw.nexted = head;
-  sam_setinttab((uint32_t)ed, interval, offset);
-  uvdbg("head: %08x next: %08x\n", ed, head);
+  ed->hw.nexted = physhead;
+  physed        =  sam_virtramaddr((uintptr_t)ed);
+  sam_setinttab((uint32_t)physed, interval, offset);
+  uvdbg("head: %08x next: %08x\n", physed, physhead);
 
   /* Re-enabled periodic list processing */
 
@@ -1005,9 +1007,10 @@ static inline int sam_reminted(struct sam_ed_s *ed)
   struct sam_ed_s *head;
   struct sam_ed_s *curr;
   struct sam_ed_s *prev;
-  unsigned int     interval;
-  unsigned int     offset;
-  uint32_t         regval;
+  uintptr_t physhead;
+  unsigned int interval;
+  unsigned int offset;
+  uint32_t regval;
 
   /* Disable periodic list processing.  Does this take effect immediately?  Or
    * at the next SOF... need to check.
@@ -1034,9 +1037,11 @@ static inline int sam_reminted(struct sam_ed_s *ed)
    * entry is always guaranteed to contain the common ED list head.
    */
 
-  head = (struct sam_ed_s *)g_hcca.inttbl[offset];
+  physhead = g_hcca.inttbl[offset];
+  head     = (struct sam_ed_s *)sam_virtramaddr((uintptr_t)physhead);
+
   uvdbg("ed: %08x head: %08x next: %08x offset: %d\n",
-        ed, head, head ? head->hw.nexted : 0, offset);
+        ed, physhead, head ? head->hw.nexted : 0, offset);
 
   /* Find the ED to be removed in the ED list */
 
@@ -1059,7 +1064,8 @@ static inline int sam_reminted(struct sam_ed_s *ed)
         {
           /* Yes... set the head of the bulk list to skip over this ED */
 
-          head = (struct sam_ed_s *)ed->hw.nexted;
+          physhead = ed->hw.nexted;
+          head     = (struct sam_ed_s *)sam_virtramaddr((uintptr_t)physhead);
         }
       else
         {
@@ -1069,8 +1075,9 @@ static inline int sam_reminted(struct sam_ed_s *ed)
 
           prev->hw.nexted = ed->hw.nexted;
         }
-        uvdbg("ed: %08x head: %08x next: %08x\n",
-              ed, head, head ? head->hw.nexted : 0);
+
+      uvdbg("ed: %08x head: %08x next: %08x\n",
+            ed, physhead, head ? head->hw.nexted : 0);
 
       /* Calculate the new minimum interval for this list */
 
@@ -1082,6 +1089,7 @@ static inline int sam_reminted(struct sam_ed_s *ed)
               interval = curr->interval;
             }
         }
+
       uvdbg("min interval: %d offset: %d\n", interval, offset);
 
       /* Save the new minimum interval */
@@ -1099,7 +1107,7 @@ static inline int sam_reminted(struct sam_ed_s *ed)
        * table (head might be NULL).
        */
 
-      sam_setinttab((uint32_t)head, interval, offset);
+      sam_setinttab((uint32_t)physhead, interval, offset);
     }
 
   /* Re-enabled periodic list processing */
@@ -1166,6 +1174,9 @@ static int sam_enqueuetd(struct sam_rhport_s *rhport, struct sam_ed_s *ed,
 {
   struct sam_gtd_s *td;
   struct sam_gtd_s *tdtail;
+  uintptr_t phytd;
+  uintptr_t phytail;
+  uintptr_t phybuf;
   int ret = -ENOMEM;
 
   /* Allocate a TD from the free list */
@@ -1173,29 +1184,52 @@ static int sam_enqueuetd(struct sam_rhport_s *rhport, struct sam_ed_s *ed,
   td = sam_tdalloc();
   if (td != NULL)
     {
+      /* Skip processing of this ED */
+
+      ed->hw.ctrl      |= ED_CONTROL_K;
+
+      /* Select the common tail ED for this root hub port */
+
       tdtail            = &g_tdtail[rhport->rhpndx];
 
+      /* Get physical addresses to support the DMA */
+
+      phytd             =  sam_physramaddr((uintptr_t)td);
+      phytail           =  sam_physramaddr((uintptr_t)tdtail);
+      phybuf            =  sam_physramaddr((uintptr_t)buffer);
+
       /* Initialize the allocated TD and link it before the common tail TD. */
 
-      td->hw.ctrl       = (GTD_STATUS_R | dirpid | TD_DELAY(0) | toggle | GTD_STATUS_CC_MASK);
+      td->hw.ctrl       = (GTD_STATUS_R | dirpid | TD_DELAY(0) |
+                           toggle | GTD_STATUS_CC_MASK);
       tdtail->hw.ctrl   = 0;
-      td->hw.cbp        = (uint32_t)buffer;
+      td->hw.cbp        = (uint32_t)phybuf;
       tdtail->hw.cbp    = 0;
-      td->hw.nexttd     = (uint32_t)tdtail;
+      td->hw.nexttd     = (uint32_t)phytail;
       tdtail->hw.nexttd = 0;
-      td->hw.be         = (uint32_t)(buffer + (buflen - 1));
+      td->hw.be         = (uint32_t)(phybuf + (buflen - 1));
       tdtail->hw.be     = 0;
 
       /* Configure driver-only fields in the extended TD structure */
 
-      td->ed             = ed;
+      td->ed            = ed;
 
       /* Link the td to the head of the ED's TD list */
 
-      ed->hw.headp       = (uint32_t)td | ((ed->hw.headp) & ED_HEADP_C);
-      ed->hw.tailp       = (uint32_t)tdtail;
+      ed->hw.headp      = (uint32_t)phytd | ((ed->hw.headp) & ED_HEADP_C);
+      ed->hw.tailp      = (uint32_t)phytail;
+
+      /* Flush the buffer, the new TD, and the modified ED to RAM */
+
+      cp15_coherent_dcache((uintptr_t)buffer, buflen);
+      cp15_coherent_dcache((uintptr_t)tdtail, sizeof(struct sam_gtd_s));
+      cp15_coherent_dcache((uintptr_t)td, sizeof(struct sam_gtd_s));
 
-      ret                = OK;
+      /* Resume processing of this ED */
+
+      ed->hw.ctrl      &= ~ED_CONTROL_K;
+      cp15_coherent_dcache((uintptr_t)ed, sizeof(struct sam_ed_s));
+      ret               = OK;
     }
 
   return ret;
@@ -1296,6 +1330,13 @@ static int sam_ctrltd(struct sam_rhport_s *rhport, uint32_t dirpid,
 
       sam_takesem(&edctrl->wdhsem);
 
+      /* Invalidate the D cache to force the control ED to be reloaded from
+       * RAM.
+       */
+
+      cp15_invalidate_dcache((uintptr_t)edctrl,
+                             (uintptr_t)edctrl + sizeof(struct sam_ed_s));
+
       /* Check the TD completion status bits */
 
       if (edctrl->tdstatus == TD_CC_NOERROR)
@@ -1470,7 +1511,7 @@ static void sam_wdh_interrupt(void)
    * cleared in the interrupt status register.
    */
 
-  td = (struct sam_gtd_s *)g_hcca.donehead;
+  td = (struct sam_gtd_s *)sam_virtramaddr(g_hcca.donehead);
   g_hcca.donehead = 0;
 
   /* Process each TD in the write done list */
@@ -1795,6 +1836,10 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
   /* Set the transfer type to control */
 
   edctrl->xfrtype = USB_EP_ATTR_XFER_CONTROL;
+
+  /* Flush the modified control ED to RAM */
+
+  cp15_coherent_dcache((uintptr_t)edctrl, sizeof(struct sam_ed_s));
   sam_givesem(&g_ohci.exclsem);
 
   uvdbg("RHPort%d EP0 CTRL: %08x\n", rhport->rhpndx + 1, edctrl->hw.ctrl);
@@ -2195,7 +2240,8 @@ static int sam_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer)
  *      created by DRVR_ALLOC.
  *   buffer - A buffer used for sending the request and for returning any
  *     responses.  This buffer must be large enough to hold the length value
- *     in the request description. buffer must have been allocated using DRVR_ALLOC
+ *     in the request description. buffer must have been allocated using
+ *     DRVR_ALLOC
  *
  *   NOTE: On an IN transaction, req and buffer may refer to the same allocated
  *   memory.
@@ -2243,7 +2289,13 @@ static int sam_ctrlin(FAR struct usbhost_driver_s *drvr,
         }
     }
 
+  /* On an IN transaction, we need to invalidate the buffer contents to force
+   * it to be reloaded from RAM after the DMA.
+   */
+
   sam_givesem(&g_ohci.exclsem);
+  cp15_invalidate_dcache((uintptr_t)buffer, (uintptr_t)buffer + len);
+
   return ret;
 }
 
@@ -2337,6 +2389,7 @@ static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
   DEBUGASSERT(rhport && ed && buffer && buflen > 0);
 
   in = (ed->hw.ctrl  & ED_CONTROL_D_MASK) == ED_CONTROL_D_IN;
+
   uvdbg("EP%d %s toggle: %d maxpacket: %d buflen: %d\n",
         (ed->hw.ctrl  & ED_CONTROL_EN_MASK) >> ED_CONTROL_EN_SHIFT,
         in ? "IN" : "OUT",
@@ -2391,10 +2444,25 @@ static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
 
       sam_takesem(&ed->wdhsem);
 
+      /* Invalidate the D cache to force the ED to be reloaded from RAM */
+
+      cp15_invalidate_dcache((uintptr_t)ed,
+                             (uintptr_t)ed + sizeof(struct sam_ed_s));
+
       /* Check the TD completion status bits */
 
       if (ed->tdstatus == TD_CC_NOERROR)
         {
+          /* On an IN transaction, we also need to invalidate the buffer
+           * contents to force it to be reloaded from RAM.
+           */
+
+          if (in)
+            {
+              cp15_invalidate_dcache((uintptr_t)buffer,
+                                     (uintptr_t)buffer + buflen);
+            }
+
           ret = OK;
         }
       else
@@ -2467,6 +2535,8 @@ static inline void sam_ep0init(void)
   struct sam_ed_s *edctrl;
   struct sam_ed_s *preved;
   struct sam_gtd_s *tdtail;
+  uintptr_t phyctrl;
+  uintptr_t phytail;
   int rhpndx;
 
   /* Initialize the EP0 control EDs */
@@ -2475,14 +2545,16 @@ static inline void sam_ep0init(void)
        rhpndx < SAM_USBHOST_NRHPORT;
        rhpndx++, preved = edctrl)
     {
-      /* Set up some default values */
+      /* Get some pointers to the EP0 control ED and to the common tail TD
+       * for this root hub port.
+       */
 
-      (void)sam_ep0configure(&g_ohci.rhport[rhpndx].drvr, 1, 8);
+      tdtail           = &g_tdtail[rhpndx];
+      edctrl           = &g_edctrl[rhpndx];
 
-      /* Get some convenience pointers */
+      /* We will also need the physical addresses for the DMA */
 
-      tdtail = &g_tdtail[rhpndx];
-      edctrl = &g_edctrl[rhpndx];
+      phytail          = sam_physramaddr((uintptr_t)tdtail);
 
       /* Initialize the common tail TD for this port */
 
@@ -2495,10 +2567,14 @@ static inline void sam_ep0init(void)
       memset(edctrl, 0, sizeof(struct sam_ed_s));
       sem_init(&edctrl->wdhsem, 0, 0);
 
+      /* Set up some default values (like max packetsize = 8). */
+
+      (void)sam_ep0configure(&g_ohci.rhport[rhpndx].drvr, 0, 8);
+
       /* Link the common tail TD to the ED's TD list */
 
-      edctrl->hw.headp  = (uint32_t)tdtail;
-      edctrl->hw.tailp  = (uint32_t)tdtail;
+      edctrl->hw.headp  = (uint32_t)phytail;
+      edctrl->hw.tailp  = (uint32_t)phytail;
 
       /* If this is not the first ED in the list, then link the previous ED
        * to this one.  Because of the memset, the last ED in the list will
@@ -2507,13 +2583,22 @@ static inline void sam_ep0init(void)
 
       if (preved)
         {
-          preved->hw.nexted = (uint32_t)edctrl;
+          phyctrl           = sam_physramaddr((uintptr_t)edctrl);
+          preved->hw.nexted = (uint32_t)phyctrl;
         }
     }
 
+  /* Flush all of the control EDs and tail TDs to RAM */
+
+  cp15_coherent_dcache((uintptr_t)g_edctrl,
+                      SAM_USBHOST_NRHPORT * sizeof(struct sam_ed_s));
+  cp15_coherent_dcache((uintptr_t)g_tdtail,
+                      SAM_USBHOST_NRHPORT * sizeof(struct sam_gtd_s));
+
   /* Set the head of the control list to the EP0 ED for RHport0. */
 
-  sam_putreg((uint32_t)&g_edctrl[0], SAM_USBHOST_CTRLHEADED);
+  sam_putreg((uint32_t)sam_physramaddr((uintptr_t)&g_edctrl[0]),
+             SAM_USBHOST_CTRLHEADED);
 
   /* ControlListEnable.  This bit is set to enable the processing of the
    * Control list.  Note: once enabled, it remains enabled and we may even
@@ -2562,13 +2647,11 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller)
   irqstate_t flags;
   int i;
 
-  /* Sanity checks.  NOTE: If certain OS features are enabled, it may be
-   * necessary to increase the size of SAM_ED/TD_SIZE in sam_ohciram.h
-   */
+  /* One time sanity checks */
 
   DEBUGASSERT(controller == 0);
-  DEBUGASSERT(sizeof(struct sam_ed_s)  <= SAM_ED_SIZE);
-  DEBUGASSERT(sizeof(struct sam_gtd_s) <= SAM_TD_SIZE);
+  DEBUGASSERT(sizeof(struct sam_ed_s)  == SIZEOF_SAM_ED_S);
+  DEBUGASSERT(sizeof(struct sam_gtd_s) == SIZEOF_SAM_TD_S);
 
   /* Initialize the state data structure */
 
@@ -2722,6 +2805,13 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller)
       return NULL;
     }
 
+  /* Drive Vbus +5V (the smoke test).  Should be done elsewhere in OTG
+   * mode.
+   */
+
+  sam_usbhost_vbusdrive(SAM_OHCI_IFACE, true);
+  up_mdelay(50);
+
   /* If there is a USB device in the slot at power up, then we will not
    * get the status change interrupt to signal us that the device is
    * connected.  We need to set the initial connected state accordingly.
@@ -2736,12 +2826,6 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller)
             i+1, g_ohci.rhport[i].connected ? "YES" : "NO");
     }
 
-  /* Drive Vbus +5V (the smoke test).  Should be done elsewhere in OTG
-   * mode.
-   */
-
-  sam_usbhost_vbusdrive(SAM_OHCI_IFACE, true);
-
   /* Enable interrupts at the interrupt controller */
 
   up_enable_irq(SAM_IRQ_UHPHS); /* enable USB interrupt */