Merge branch 'u-boot-tegra/master' into 'u-boot-arm/master'
[oweals/u-boot.git] / drivers / usb / host / ehci-hcd.c
index 443cc2313465fcc872f21fbca52914a9bf50c2f2..fdad739724eacb545817ebaf8128bdba96a82c91 100644 (file)
 #define CONFIG_USB_MAX_CONTROLLER_COUNT 1
 #endif
 
-static struct ehci_ctrl {
-       struct ehci_hccr *hccr; /* R/O registers, not need for volatile */
-       struct ehci_hcor *hcor;
-       int rootdev;
-       uint16_t portreset;
-       struct QH qh_list __aligned(USB_DMA_MINALIGN);
-       struct QH periodic_queue __aligned(USB_DMA_MINALIGN);
-       uint32_t *periodic_list;
-       int ntds;
-} ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
+static struct ehci_ctrl ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
 
 #define ALIGN_END_ADDR(type, ptr, size)                        \
        ((uint32_t)(ptr) + roundup((size) * sizeof(type), USB_DMA_MINALIGN))
@@ -589,10 +580,12 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
                dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);
        } else {
                dev->act_len = 0;
+#ifndef CONFIG_USB_EHCI_FARADAY
                debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
                      dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts),
                      ehci_readl(&ctrl->hcor->or_portsc[0]),
                      ehci_readl(&ctrl->hcor->or_portsc[1]));
+#endif
        }
 
        free(qtd);
@@ -603,6 +596,17 @@ fail:
        return -1;
 }
 
+__weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+       if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+               /* Printing the message would cause a scan failure! */
+               debug("The request port(%u) is not configured\n", port);
+               return NULL;
+       }
+
+       return (uint32_t *)&hcor->or_portsc[port];
+}
+
 int
 ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
                 int length, struct devrequest *req)
@@ -629,11 +633,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
        case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
        case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
        case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
-               if (!port || port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
-                       printf("The request port(%d) is not configured\n", port - 1);
+               status_reg = ehci_get_portsc_register(ctrl->hcor, port - 1);
+               if (!status_reg)
                        return -1;
-               }
-               status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
                break;
        default:
                status_reg = NULL;
@@ -915,6 +917,9 @@ int usb_lowlevel_init(int index, void **controller)
        qh_list->qh_overlay.qt_token =
                        cpu_to_hc32(QT_TOKEN_STATUS(QT_TOKEN_STATUS_HALTED));
 
+       flush_dcache_range((uint32_t)qh_list,
+                          ALIGN_END_ADDR(struct QH, qh_list, 1));
+
        /* Set async. queue head pointer. */
        ehci_writel(&ehcic[index].hcor->or_asynclistaddr, (uint32_t)qh_list);
 
@@ -928,6 +933,9 @@ int usb_lowlevel_init(int index, void **controller)
        periodic->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
        periodic->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
 
+       flush_dcache_range((uint32_t)periodic,
+                          ALIGN_END_ADDR(struct QH, periodic, 1));
+
        /*
         * Step 2: Setup frame-list: Every microframe, USB tries the same list.
         *         In particular, device specifications on polling frequency
@@ -937,7 +945,9 @@ int usb_lowlevel_init(int index, void **controller)
         *         Split Transactions will be spread across microframes using
         *         S-mask and C-mask.
         */
-       ehcic[index].periodic_list = memalign(4096, 1024*4);
+       if (ehcic[index].periodic_list == NULL)
+               ehcic[index].periodic_list = memalign(4096, 1024 * 4);
+
        if (!ehcic[index].periodic_list)
                return -ENOMEM;
        for (i = 0; i < 1024; i++) {
@@ -945,6 +955,10 @@ int usb_lowlevel_init(int index, void **controller)
                                                | QH_LINK_TYPE_QH;
        }
 
+       flush_dcache_range((uint32_t)ehcic[index].periodic_list,
+                          ALIGN_END_ADDR(uint32_t, ehcic[index].periodic_list,
+                                         1024));
+
        /* Set periodic list base address */
        ehci_writel(&ehcic[index].hcor->or_periodiclistbase,
                (uint32_t)ehcic[index].periodic_list);
@@ -971,10 +985,13 @@ int usb_lowlevel_init(int index, void **controller)
        cmd |= CMD_RUN;
        ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);
 
+#ifndef CONFIG_USB_EHCI_FARADAY
        /* take control over the ports */
        cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
        cmd |= FLAG_CF;
        ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
+#endif
+
        /* unblock posted write */
        cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
        mdelay(5);
@@ -1156,6 +1173,16 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
                *buf = buffer + i * elementsize;
        }
 
+       flush_dcache_range((uint32_t)buffer,
+                          ALIGN_END_ADDR(char, buffer,
+                                         queuesize * elementsize));
+       flush_dcache_range((uint32_t)result->first,
+                          ALIGN_END_ADDR(struct QH, result->first,
+                                         queuesize));
+       flush_dcache_range((uint32_t)result->tds,
+                          ALIGN_END_ADDR(struct qTD, result->tds,
+                                         queuesize));
+
        if (disable_periodic(ctrl) < 0) {
                debug("FATAL: periodic should never fail, but did");
                goto fail3;
@@ -1166,6 +1193,11 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
        result->last->qh_link = list->qh_link;
        list->qh_link = (uint32_t)result->first | QH_LINK_TYPE_QH;
 
+       flush_dcache_range((uint32_t)result->last,
+                          ALIGN_END_ADDR(struct QH, result->last, 1));
+       flush_dcache_range((uint32_t)list,
+                          ALIGN_END_ADDR(struct QH, list, 1));
+
        if (enable_periodic(ctrl) < 0) {
                debug("FATAL: periodic should never fail, but did");
                goto fail3;
@@ -1196,6 +1228,8 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
                return NULL;
        }
        /* still active */
+       invalidate_dcache_range((uint32_t)cur,
+                               ALIGN_END_ADDR(struct QH, cur, 1));
        if (cur->qh_overlay.qt_token & 0x80) {
                debug("Exit poll_int_queue with no completed intr transfer. "
                      "token is %x\n", cur->qh_overlay.qt_token);
@@ -1302,6 +1336,9 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
                return -EINVAL;
        }
 
+       invalidate_dcache_range((uint32_t)buffer,
+                               ALIGN_END_ADDR(char, buffer, length));
+
        ret = destroy_int_queue(dev, queue);
        if (ret < 0)
                return ret;