]> git.karo-electronics.de Git - karo-tx-uboot.git/blobdiff - drivers/usb/host/ehci-hcd.c
Merge branch 'master' of git://git.denx.de/u-boot-arm
[karo-tx-uboot.git] / drivers / usb / host / ehci-hcd.c
index 635a3b45110ceb604659045f1b5fdc307c4b7db5..c671c72cb1cfc014a00b47b8b7ad38c1a52e5b0f 100644 (file)
@@ -119,15 +119,12 @@ static struct descriptor {
 #define ehci_is_TDI()  (0)
 #endif
 
-int __ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+__weak int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
 {
        return PORTSC_PSPD(reg);
 }
 
-int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
-       __attribute__((weak, alias("__ehci_get_port_speed")));
-
-void __ehci_set_usbmode(int index)
+__weak void ehci_set_usbmode(int index)
 {
        uint32_t tmp;
        uint32_t *reg_ptr;
@@ -141,17 +138,11 @@ void __ehci_set_usbmode(int index)
        ehci_writel(reg_ptr, tmp);
 }
 
-void ehci_set_usbmode(int index)
-       __attribute__((weak, alias("__ehci_set_usbmode")));
-
-void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+__weak void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
 {
        mdelay(50);
 }
 
-void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
-       __attribute__((weak, alias("__ehci_powerup_fixup")));
-
 static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 {
        uint32_t result;
@@ -996,6 +987,7 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
         * Set up periodic list
         * Step 1: Parent QH for all periodic transfers.
         */
+       ehcic[index].periodic_schedules = 0;
        periodic = &ehcic[index].periodic_queue;
        memset(periodic, 0, sizeof(*periodic));
        periodic->qh_link = cpu_to_hc32(QH_LINK_TERMINATE);
@@ -1105,6 +1097,7 @@ submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 }
 
 struct int_queue {
+       int elementsize;
        struct QH *first;
        struct QH *current;
        struct QH *last;
@@ -1154,8 +1147,6 @@ disable_periodic(struct ehci_ctrl *ctrl)
        return 0;
 }
 
-static int periodic_schedules;
-
 struct int_queue *
 create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
                 int elementsize, void *buffer)
@@ -1164,6 +1155,23 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
        struct int_queue *result = NULL;
        int i;
 
+       /*
+        * Interrupt transfers requiring several transactions are not supported
+        * because bInterval is ignored.
+        *
+        * Also, ehci_submit_async() relies on wMaxPacketSize being a power of 2
+        * <= PKT_ALIGN if several qTDs are required, while the USB
+        * specification does not constrain this for interrupt transfers. That
+        * means that ehci_submit_async() would support interrupt transfers
+        * requiring several transactions only as long as the transfer size does
+        * not require more than a single qTD.
+        */
+       if (elementsize > usb_maxpacket(dev, pipe)) {
+               printf("%s: xfers requiring several transactions are not supported.\n",
+                      __func__);
+               return NULL;
+       }
+
        debug("Enter create_int_queue\n");
        if (usb_pipetype(pipe) != PIPE_INTERRUPT) {
                debug("non-interrupt pipe (type=%lu)", usb_pipetype(pipe));
@@ -1184,6 +1192,7 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
                debug("ehci intr queue: out of memory\n");
                goto fail1;
        }
+       result->elementsize = elementsize;
        result->first = memalign(USB_DMA_MINALIGN,
                                 sizeof(struct QH) * queuesize);
        if (!result->first) {
@@ -1259,9 +1268,11 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
                           ALIGN_END_ADDR(struct qTD, result->tds,
                                          queuesize));
 
-       if (disable_periodic(ctrl) < 0) {
-               debug("FATAL: periodic should never fail, but did");
-               goto fail3;
+       if (ctrl->periodic_schedules > 0) {
+               if (disable_periodic(ctrl) < 0) {
+                       debug("FATAL: periodic should never fail, but did");
+                       goto fail3;
+               }
        }
 
        /* hook up to periodic list */
@@ -1278,7 +1289,7 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
                debug("FATAL: periodic should never fail, but did");
                goto fail3;
        }
-       periodic_schedules++;
+       ctrl->periodic_schedules++;
 
        debug("Exit create_int_queue\n");
        return result;
@@ -1318,6 +1329,11 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
                queue->current++;
        else
                queue->current = NULL;
+
+       invalidate_dcache_range((uint32_t)cur->buffer,
+                               ALIGN_END_ADDR(char, cur->buffer,
+                                              queue->elementsize));
+
        debug("Exit poll_int_queue with completed intr transfer. token is %x at %p (first at %p)\n",
              hc32_to_cpu(cur_td->qt_token), cur, queue->first);
        return cur->buffer;
@@ -1335,7 +1351,7 @@ destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
                debug("FATAL: periodic should never fail, but did");
                goto out;
        }
-       periodic_schedules--;
+       ctrl->periodic_schedules--;
 
        struct QH *cur = &ctrl->periodic_queue;
        timeout = get_timer(0) + 500; /* abort after 500ms */
@@ -1357,7 +1373,7 @@ destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
                }
        }
 
-       if (periodic_schedules > 0) {
+       if (ctrl->periodic_schedules > 0) {
                result = enable_periodic(ctrl);
                if (result < 0)
                        debug("FATAL: periodic should never fail, but did");
@@ -1383,24 +1399,9 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
        debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
              dev, pipe, buffer, length, interval);
 
-       /*
-        * Interrupt transfers requiring several transactions are not supported
-        * because bInterval is ignored.
-        *
-        * Also, ehci_submit_async() relies on wMaxPacketSize being a power of 2
-        * <= PKT_ALIGN if several qTDs are required, while the USB
-        * specification does not constrain this for interrupt transfers. That
-        * means that ehci_submit_async() would support interrupt transfers
-        * requiring several transactions only as long as the transfer size does
-        * not require more than a single qTD.
-        */
-       if (length > usb_maxpacket(dev, pipe)) {
-               printf("%s: Interrupt transfers requiring several "
-                       "transactions are not supported.\n", __func__);
-               return -1;
-       }
-
        queue = create_int_queue(dev, pipe, 1, length, buffer);
+       if (!queue)
+               return -1;
 
        timeout = get_timer(0) + USB_TIMEOUT_MS(pipe);
        while ((backbuffer = poll_int_queue(dev, queue)) == NULL)
@@ -1416,9 +1417,6 @@ 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;