]> git.sur5r.net Git - u-boot/blobdiff - drivers/usb/host/ehci-hcd.c
serial: Remove duplicated line in Makefile
[u-boot] / drivers / usb / host / ehci-hcd.c
index c664b1629e090cc68975cb9d392aa2846fa3cd2e..2582bf36eb9fb4e8b2f5d6442d765f66cf9a0be4 100644 (file)
@@ -52,8 +52,8 @@ static struct descriptor {
                0,              /* wHubCharacteristics */
                10,             /* bPwrOn2PwrGood */
                0,              /* bHubCntrCurrent */
-               {},             /* Device removable */
-               {}              /* at most 7 ports! XXX */
+               {               /* Device removable */
+                             /* at most 7 ports! XXX */
        },
        {
                0x12,           /* bLength */
@@ -134,6 +134,8 @@ static void ehci_set_usbmode(struct ehci_ctrl *ctrl)
        tmp |= USBMODE_CM_HC;
 #if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
        tmp |= USBMODE_BE;
+#else
+       tmp &= ~USBMODE_BE;
 #endif
        ehci_writel(reg_ptr, tmp);
 }
@@ -146,9 +148,12 @@ static void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
 
 static uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
 {
-       if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+       int max_ports = HCS_N_PORTS(ehci_readl(&ctrl->hccr->cr_hcsparams));
+
+       if (port < 0 || port >= max_ports) {
                /* Printing the message would cause a scan failure! */
-               debug("The request port(%u) is not configured\n", port);
+               debug("The request port(%u) exceeds maximum port number\n",
+                     port);
                return NULL;
        }
 
@@ -203,18 +208,19 @@ static int ehci_shutdown(struct ehci_ctrl *ctrl)
 {
        int i, ret = 0;
        uint32_t cmd, reg;
-
-       if (!ctrl || !ctrl->hcor)
-               return -EINVAL;
+       int max_ports = HCS_N_PORTS(ehci_readl(&ctrl->hccr->cr_hcsparams));
 
        cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
+       /* If not run, directly return */
+       if (!(cmd & CMD_RUN))
+               return 0;
        cmd &= ~(CMD_PSE | CMD_ASE);
        ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
        ret = handshake(&ctrl->hcor->or_usbsts, STS_ASS | STS_PSS, 0,
                100 * 1000);
 
        if (!ret) {
-               for (i = 0; i < CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS; i++) {
+               for (i = 0; i < max_ports; i++) {
                        reg = ehci_readl(&ctrl->hcor->or_portsc[i]);
                        reg |= EHCI_PS_SUSP;
                        ehci_writel(&ctrl->hcor->or_portsc[i], reg);
@@ -235,7 +241,7 @@ static int ehci_shutdown(struct ehci_ctrl *ctrl)
 static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)
 {
        uint32_t delta, next;
-       uint32_t addr = (unsigned long)buf;
+       unsigned long addr = (unsigned long)buf;
        int idx;
 
        if (addr != ALIGN(addr, ARCH_DMA_MINALIGN))
@@ -245,7 +251,7 @@ static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)
 
        idx = 0;
        while (idx < QT_BUFFER_CNT) {
-               td->qt_buffer[idx] = cpu_to_hc32(addr);
+               td->qt_buffer[idx] = cpu_to_hc32(virt_to_phys((void *)addr));
                td->qt_buffer_hi[idx] = 0;
                next = (addr + EHCI_PAGE_SIZE) & ~(EHCI_PAGE_SIZE - 1);
                delta = next - addr;
@@ -398,7 +404,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
         *   qh_overlay.qt_next ...... 13-10 H
         * - qh_overlay.qt_altnext
         */
-       qh->qh_link = cpu_to_hc32((unsigned long)&ctrl->qh_list | QH_LINK_TYPE_QH);
+       qh->qh_link = cpu_to_hc32(virt_to_phys(&ctrl->qh_list) | QH_LINK_TYPE_QH);
        c = (dev->speed != USB_SPEED_HIGH) && !usb_pipeendpoint(pipe);
        maxpacket = usb_maxpacket(dev, pipe);
        endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) |
@@ -415,7 +421,6 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
        qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
 
        tdp = &qh->qh_overlay.qt_next;
-
        if (req != NULL) {
                /*
                 * Setup request qTD (3.5 in ehci-r10.pdf)
@@ -438,7 +443,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
                        goto fail;
                }
                /* Update previous qTD! */
-               *tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]);
+               *tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter]));
                tdp = &qtd[qtd_counter++].qt_next;
                toggle = 1;
        }
@@ -497,7 +502,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
                                goto fail;
                        }
                        /* Update previous qTD! */
-                       *tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]);
+                       *tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter]));
                        tdp = &qtd[qtd_counter++].qt_next;
                        /*
                         * Data toggle has to be adjusted since the qTD transfer
@@ -528,11 +533,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
                        QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);
                qtd[qtd_counter].qt_token = cpu_to_hc32(token);
                /* Update previous qTD! */
-               *tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]);
+               *tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter]));
                tdp = &qtd[qtd_counter++].qt_next;
        }
 
-       ctrl->qh_list.qh_link = cpu_to_hc32((unsigned long)qh | QH_LINK_TYPE_QH);
+       ctrl->qh_list.qh_link = cpu_to_hc32(virt_to_phys(qh) | QH_LINK_TYPE_QH);
 
        /* Flush dcache */
        flush_dcache_range((unsigned long)&ctrl->qh_list,
@@ -542,7 +547,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
                           ALIGN_END_ADDR(struct qTD, qtd, qtd_count));
 
        /* Set async. queue head pointer. */
-       ehci_writel(&ctrl->hcor->or_asynclistaddr, (unsigned long)&ctrl->qh_list);
+       ehci_writel(&ctrl->hcor->or_asynclistaddr, virt_to_phys(&ctrl->qh_list));
 
        usbsts = ehci_readl(&ctrl->hcor->or_usbsts);
        ehci_writel(&ctrl->hcor->or_usbsts, (usbsts & 0x3f));
@@ -587,8 +592,9 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
         * dangerous operation, it's responsibility of the calling
         * code to make sure enough space is reserved.
         */
-       invalidate_dcache_range((unsigned long)buffer,
-               ALIGN((unsigned long)buffer + length, ARCH_DMA_MINALIGN));
+       if (buffer != NULL && length > 0)
+               invalidate_dcache_range((unsigned long)buffer,
+                       ALIGN((unsigned long)buffer + length, ARCH_DMA_MINALIGN));
 
        /* Check that the TD processing happened */
        if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)
@@ -933,7 +939,7 @@ unknown:
        return -1;
 }
 
-const struct ehci_ops default_ehci_ops = {
+static const struct ehci_ops default_ehci_ops = {
        .set_usb_mode           = ehci_set_usbmode,
        .get_port_speed         = ehci_get_port_speed,
        .powerup_fixup          = ehci_powerup_fixup,
@@ -989,7 +995,7 @@ static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks)
 
        /* Set head of reclaim list */
        memset(qh_list, 0, sizeof(*qh_list));
-       qh_list->qh_link = cpu_to_hc32((unsigned long)qh_list | QH_LINK_TYPE_QH);
+       qh_list->qh_link = cpu_to_hc32(virt_to_phys(qh_list) | QH_LINK_TYPE_QH);
        qh_list->qh_endpt1 = cpu_to_hc32(QH_ENDPT1_H(1) |
                                                QH_ENDPT1_EPS(USB_SPEED_HIGH));
        qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
@@ -1001,7 +1007,7 @@ static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks)
                           ALIGN_END_ADDR(struct QH, qh_list, 1));
 
        /* Set async. queue head pointer. */
-       ehci_writel(&ctrl->hcor->or_asynclistaddr, (unsigned long)qh_list);
+       ehci_writel(&ctrl->hcor->or_asynclistaddr, virt_to_phys(qh_list));
 
        /*
         * Set up periodic list
@@ -1104,6 +1110,8 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
        rc = ehci_hcd_init(index, init, &ctrl->hccr, &ctrl->hcor);
        if (rc)
                return rc;
+       if (!ctrl->hccr || !ctrl->hcor)
+               return -1;
        if (init == USB_INIT_DEVICE)
                goto done;
 
@@ -1588,17 +1596,31 @@ static int ehci_destroy_int_queue(struct udevice *dev, struct usb_device *udev,
        return _ehci_destroy_int_queue(udev, queue);
 }
 
+static int ehci_get_max_xfer_size(struct udevice *dev, size_t *size)
+{
+       /*
+        * EHCD can handle any transfer length as long as there is enough
+        * free heap space left, hence set the theoretical max number here.
+        */
+       *size = SIZE_MAX;
+
+       return 0;
+}
+
 int ehci_register(struct udevice *dev, struct ehci_hccr *hccr,
                  struct ehci_hcor *hcor, const struct ehci_ops *ops,
                  uint tweaks, enum usb_init_type init)
 {
        struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
        struct ehci_ctrl *ctrl = dev_get_priv(dev);
-       int ret;
+       int ret = -1;
 
        debug("%s: dev='%s', ctrl=%p, hccr=%p, hcor=%p, init=%d\n", __func__,
              dev->name, ctrl, hccr, hcor, init);
 
+       if (!ctrl || !hccr || !hcor)
+               goto err;
+
        priv->desc_before_addr = true;
 
        ehci_setup_ops(ctrl, ops);
@@ -1614,6 +1636,12 @@ int ehci_register(struct udevice *dev, struct ehci_hccr *hccr,
        if (ret)
                goto err;
 
+       if (ctrl->ops.init_after_reset) {
+               ret = ctrl->ops.init_after_reset(ctrl);
+               if (ret)
+                       goto err;
+       }
+
        ret = ehci_common_init(ctrl, tweaks);
        if (ret)
                goto err;
@@ -1644,6 +1672,7 @@ struct dm_usb_ops ehci_usb_ops = {
        .create_int_queue = ehci_create_int_queue,
        .poll_int_queue = ehci_poll_int_queue,
        .destroy_int_queue = ehci_destroy_int_queue,
+       .get_max_xfer_size  = ehci_get_max_xfer_size,
 };
 
 #endif