# define m32_swap(x) cpu_to_le32(x)
 #endif /* CONFIG_SYS_OHCI_BE_CONTROLLER */
 
+#ifdef CONFIG_DM_USB
+/*
+ * We really should do proper cache flushing everywhere, but for now we only
+ * do it for new (driver-model) usb code to avoid regressions.
+ */
+#define flush_dcache_buffer(addr, size) \
+       flush_dcache_range((unsigned long)(addr), \
+               ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN))
+#define invalidate_dcache_buffer(addr, size) \
+       invalidate_dcache_range((unsigned long)(addr), \
+               ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN))
+#else
+#define flush_dcache_buffer(addr, size)
+#define invalidate_dcache_buffer(addr, size)
+#endif
+
+/* Do not use sizeof(ed / td) as our ed / td structs contain extra members */
+#define flush_dcache_ed(addr) flush_dcache_buffer(addr, 16)
+#define flush_dcache_td(addr) flush_dcache_buffer(addr, 16)
+#define flush_dcache_iso_td(addr) flush_dcache_buffer(addr, 32)
+#define flush_dcache_hcca(addr) flush_dcache_buffer(addr, 256)
+#define invalidate_dcache_ed(addr) invalidate_dcache_buffer(addr, 16)
+#define invalidate_dcache_td(addr) invalidate_dcache_buffer(addr, 16)
+#define invalidate_dcache_iso_td(addr) invalidate_dcache_buffer(addr, 32)
+#define invalidate_dcache_hcca(addr) invalidate_dcache_buffer(addr, 256)
+
 /* global ohci_t */
 static ohci_t gohci;
 /* this must be aligned to a 256 byte boundary */
                ed_p = &(ohci->hcca->int_table [i]);
                if (*ed_p == 0)
                    continue;
+               invalidate_dcache_ed(ed_p);
                printf(__FILE__ ": %s branch int %2d(%2x):", str, i, i);
                while (*ed_p != 0 && j--) {
                        ed_t *ed = (ed_t *)m32_swap(ed_p);
+                       invalidate_dcache_ed(ed);
                        printf(" ed: %4x;", ed->hwINFO);
                        ed_p = &ed->hwNextED;
                }
 
        if (value) {
                dbg("%s %08x", label, value);
+               invalidate_dcache_ed(edp);
                dbg("%08x", edp->hwINFO);
                dbg("%08x", edp->hwTailP);
                dbg("%08x", edp->hwHeadP);
        ohci_dump_status(controller);
        if (verbose)
                ep_print_int_eds(controller, "hcca");
+       invalidate_dcache_hcca(controller->hcca);
        dbg("hcca frame #%04x", controller->hcca->frame_no);
        ohci_dump_roothub(controller, 1);
 }
 /* tell us the current USB frame number */
 static int sohci_get_current_frame_number(ohci_t *ohci)
 {
+       invalidate_dcache_hcca(ohci->hcca);
        return m16_swap(ohci->hcca->frame_no);
 }
 #endif
        switch (ed->type) {
        case PIPE_CONTROL:
                ed->hwNextED = 0;
+               flush_dcache_ed(ed);
                if (ohci->ed_controltail == NULL)
                        ohci_writel(ed, &ohci->regs->ed_controlhead);
                else
 
        case PIPE_BULK:
                ed->hwNextED = 0;
+               flush_dcache_ed(ed);
                if (ohci->ed_bulktail == NULL)
                        ohci_writel(ed, &ohci->regs->ed_bulkhead);
                else
                                        inter = ep_rev(6,
                                                 ((ed_t *)ed_p)->int_interval);
                        ed->hwNextED = *ed_p;
+                       flush_dcache_ed(ed);
                        *ed_p = m32_swap((unsigned long)ed);
+                       flush_dcache_hcca(ohci->hcca);
                }
                break;
        }
 static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed,
                            unsigned index, unsigned period)
 {
+       __maybe_unused unsigned long aligned_ed_p;
+
        for (; index < NUM_INTS; index += period) {
                __u32   *ed_p = &ohci->hcca->int_table [index];
 
                        if (((struct ed *)
                                        m32_swap((unsigned long)ed_p)) == ed) {
                                *ed_p = ed->hwNextED;
+#ifdef CONFIG_DM_USB
+                               aligned_ed_p = (unsigned long)ed_p;
+                               aligned_ed_p &= ~(ARCH_DMA_MINALIGN - 1);
+                               flush_dcache_range(aligned_ed_p,
+                                       aligned_ed_p + ARCH_DMA_MINALIGN);
+#endif
                                break;
                        }
                        ed_p = &(((struct ed *)
        int i;
 
        ed->hwINFO |= m32_swap(OHCI_ED_SKIP);
+       flush_dcache_ed(ed);
 
        switch (ed->type) {
        case PIPE_CONTROL:
                                &ohci->regs->ed_controlhead);
                } else {
                        ed->ed_prev->hwNextED = ed->hwNextED;
+                       flush_dcache_ed(ed->ed_prev);
                }
                if (ohci->ed_controltail == ed) {
                        ohci->ed_controltail = ed->ed_prev;
                               &ohci->regs->ed_bulkhead);
                } else {
                        ed->ed_prev->hwNextED = ed->hwNextED;
+                       flush_dcache_ed(ed->ed_prev);
                }
                if (ohci->ed_bulktail == ed) {
                        ohci->ed_bulktail = ed->ed_prev;
                ed->int_load = load;
        }
 
+       flush_dcache_ed(ed);
+
        return ed_ret;
 }
 
        /* use this td as the next dummy */
        td_pt = urb_priv->td [index];
        td_pt->hwNextTD = 0;
+       flush_dcache_td(td_pt);
 
        /* fill the old dummy TD */
        td = urb_priv->td [index] =
                td->hwBE = 0;
 
        td->hwNextTD = m32_swap((unsigned long)td_pt);
+       flush_dcache_td(td);
 
        /* append to queue */
        td->ed->hwTailP = td->hwNextTD;
+       flush_dcache_ed(td->ed);
 }
 
 /*-------------------------------------------------------------------------*/
        __u32 info = 0;
        unsigned int toggle = 0;
 
+       flush_dcache_buffer(buffer, data_len);
+
        /* OHCI handles the DATA-toggles itself, we just use the USB-toggle
         * bits for reseting */
        if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
        case PIPE_CONTROL:
                /* Setup phase */
                info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+               flush_dcache_buffer(setup, 8);
                td_fill(ohci, info, setup, 8, dev, cnt++, urb);
 
                /* Optional Data phase */
        if (cc) {
                err(" USB-error: %s (%x)", cc_to_string[cc], cc);
 
+               invalidate_dcache_ed(td_list->ed);
                if (*phwHeadP & m32_swap(0x1)) {
                        if (lurb_priv &&
                            ((td_list->index + 1) < urb_len)) {
                                                     td_list->index - 1;
                        } else
                                *phwHeadP &= m32_swap(0xfffffff2);
+                       flush_dcache_ed(td_list->ed);
                }
 #ifdef CONFIG_MPC5200
                td_list->hwNextTD = 0;
+               flush_dcache_td(td_list);
 #endif
        }
 }
        td_t *td_rev = NULL;
        td_t *td_list = NULL;
 
+       invalidate_dcache_hcca(ohci->hcca);
        td_list_hc = m32_swap(ohci->hcca->done_head) & 0xfffffff0;
        ohci->hcca->done_head = 0;
+       flush_dcache_hcca(ohci->hcca);
 
        while (td_list_hc) {
                td_list = (td_t *)td_list_hc;
+               invalidate_dcache_td(td_list);
                check_status(td_list);
                td_list->next_dl_td = td_rev;
                td_rev = td_list;
        urb_priv_t *lurb_priv;
        __u32 tdINFO, edHeadP, edTailP;
 
+       invalidate_dcache_td(td_list);
        tdINFO = m32_swap(td_list->hwINFO);
 
        ed = td_list->ed;
                lurb_priv->td_cnt, lurb_priv->length);
 
        if (ed->state != ED_NEW && (!usb_pipeint(lurb_priv->pipe))) {
+               invalidate_dcache_ed(ed);
                edHeadP = m32_swap(ed->hwHeadP) & 0xfffffff0;
                edTailP = m32_swap(ed->hwTailP);
 
        dev->status = stat;
        dev->act_len = urb->actual_length;
 
+       if (usb_pipein(pipe) && dev->status == 0 && dev->act_len)
+               invalidate_dcache_buffer(buffer, dev->act_len);
+
 #ifdef DEBUG
        pkt_print(ohci, urb, dev, pipe, buffer, transfer_len,
                  setup, "RET(ctlr)", usb_pipein(pipe));
        int ints;
        int stat = -1;
 
+       invalidate_dcache_hcca(ohci->hcca);
+
        if ((ohci->hcca->done_head != 0) &&
                                !(m32_swap(ohci->hcca->done_head) & 0x01)) {
                ints =  OHCI_INTR_WDH;