Merge branch 'master' of git://git.denx.de/u-boot-usb
authorTom Rini <trini@ti.com>
Thu, 1 Aug 2013 13:19:28 +0000 (09:19 -0400)
committerTom Rini <trini@ti.com>
Thu, 1 Aug 2013 13:19:28 +0000 (09:19 -0400)
12 files changed:
common/cmd_dfu.c
common/usb_hub.c
drivers/dfu/dfu.c
drivers/serial/usbtty.h
drivers/usb/gadget/f_dfu.c
drivers/usb/gadget/gadget_chips.h
drivers/usb/gadget/mv_udc.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/ehci.h
include/dfu.h
include/usb/mv_udc.h

index db066acc364b5989b1e7333dbac1c26106f5d32e..793c42212369a85d11047d7315e0f386e77c0e05 100644 (file)
@@ -19,8 +19,8 @@ static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
        const char *str_env;
        char *s = "dfu";
+       int ret, i = 0;
        char *env_bkp;
-       int ret;
 
        if (argc < 3)
                return CMD_RET_USAGE;
@@ -49,6 +49,15 @@ static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
        g_dnl_register(s);
        while (1) {
+               if (dfu_reset())
+                       /*
+                        * This extra number of usb_gadget_handle_interrupts()
+                        * calls is necessary to assure correct transmission
+                        * completion with dfu-util
+                        */
+                       if (++i == 10)
+                               goto exit;
+
                if (ctrlc())
                        goto exit;
 
@@ -60,6 +69,9 @@ done:
        dfu_free_entities();
        free(env_bkp);
 
+       if (dfu_reset())
+               run_command("reset", 0);
+
        return CMD_RET_SUCCESS;
 }
 
index 754d436ad4ec69380033dde2725c9ba5032e3595..a11b401e624b8d1e3edf33c2f89ce5d35487d65d 100644 (file)
@@ -110,7 +110,7 @@ static void usb_hub_power_on(struct usb_hub_device *hub)
                ret = usb_get_port_status(dev, i + 1, portsts);
                if (ret < 0) {
                        debug("port %d: get_port_status failed\n", i + 1);
-                       return;
+                       continue;
                }
 
                /*
@@ -125,7 +125,7 @@ static void usb_hub_power_on(struct usb_hub_device *hub)
                portstatus = le16_to_cpu(portsts->wPortStatus);
                if (portstatus & (USB_PORT_STAT_POWER << 1)) {
                        debug("port %d: Port power change failed\n", i + 1);
-                       return;
+                       continue;
                }
        }
 
index b8870ecf7309bba6215bb0ecff0e2e8b79a8f17b..d73d5103919662e8a8c044be35922e4bed33dec4 100644 (file)
 #include <linux/list.h>
 #include <linux/compiler.h>
 
+static bool dfu_reset_request;
 static LIST_HEAD(dfu_list);
 static int dfu_alt_num;
 
+bool dfu_reset(void)
+{
+       return dfu_reset_request;
+}
+
+void dfu_trigger_reset()
+{
+       dfu_reset_request = true;
+}
+
 static int dfu_find_alt_num(const char *s)
 {
        int i = 0;
index bbabb325f83a2d777d5bd5b1e50ceba5305f231b..e243a8e3b203fe2106beae5b7b3b957629acfacb 100644 (file)
@@ -22,6 +22,8 @@
 #include <usb/pxa27x_udc.h>
 #elif defined(CONFIG_DW_UDC)
 #include <usb/designware_udc.h>
+#elif defined(CONFIG_MV_UDC)
+#include <usb/mv_udc.h>
 #endif
 
 #include <version.h>
index 5321a689d4dc3905651fade571dd27fcb8b5dc2a..37d04a19285e605a6d4e34ae9b54b989eca28891 100644 (file)
@@ -312,6 +312,8 @@ static int state_dfu_idle(struct f_dfu *f_dfu,
                        DFU_STATE_dfuMANIFEST_WAIT_RST;
                to_runtime_mode(f_dfu);
                f_dfu->dfu_state = DFU_STATE_appIDLE;
+
+               dfu_trigger_reset();
                break;
        default:
                f_dfu->dfu_state = DFU_STATE_dfuERROR;
index f038747e63e0d5175bb58ee495b7e419140d8c98..aa54b8547e73d2945a9b5d8df5486c87ec73f3bc 100644 (file)
 #define        gadget_is_m66592(g)     0
 #endif
 
-#ifdef CONFIG_USB_GADGET_MV
+#ifdef CONFIG_MV_UDC
 #define gadget_is_mv(g)        (!strcmp("mv_udc", (g)->name))
 #else
 #define gadget_is_mv(g)        0
index 7fa5288803809653a12fb5308edafaf15b0405e4..7574e31a8f3e8d18fbf7cc0ce7c838f824f656a7 100644 (file)
 #include <linux/types.h>
 #include <usb/mv_udc.h>
 
+#if CONFIG_USB_MAX_CONTROLLER_COUNT > 1
+#error This driver only supports one single controller.
+#endif
+
+/*
+ * Check if the system has too long cachelines. If the cachelines are
+ * longer then 128b, the driver will not be able flush/invalidate data
+ * cache over separate QH entries. We use 128b because one QH entry is
+ * 64b long and there are always two QH list entries for each endpoint.
+ */
+#if ARCH_DMA_MINALIGN > 128
+#error This driver can not work on systems with caches longer than 128b
+#endif
+
 #ifndef DEBUG
 #define DBG(x...) do {} while (0)
 #else
@@ -39,8 +53,6 @@ static const char *reqname(unsigned r)
 }
 #endif
 
-#define PAGE_SIZE      4096
-#define QH_MAXNUM      32
 static struct usb_endpoint_descriptor ep0_out_desc = {
        .bLength = sizeof(struct usb_endpoint_descriptor),
        .bDescriptorType = USB_DT_ENDPOINT,
@@ -55,8 +67,6 @@ static struct usb_endpoint_descriptor ep0_in_desc = {
        .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
 };
 
-struct ept_queue_head *epts;
-struct ept_queue_item *items[2 * NUM_ENDPOINTS];
 static int mv_pullup(struct usb_gadget *gadget, int is_on);
 static int mv_ep_enable(struct usb_ep *ep,
                const struct usb_endpoint_descriptor *desc);
@@ -79,14 +89,115 @@ static struct usb_ep_ops mv_ep_ops = {
        .free_request   = mv_ep_free_request,
 };
 
-static struct mv_ep ep[2 * NUM_ENDPOINTS];
+/* Init values for USB endpoints. */
+static const struct usb_ep mv_ep_init[2] = {
+       [0] = { /* EP 0 */
+               .maxpacket      = 64,
+               .name           = "ep0",
+               .ops            = &mv_ep_ops,
+       },
+       [1] = { /* EP 1..n */
+               .maxpacket      = 512,
+               .name           = "ep-",
+               .ops            = &mv_ep_ops,
+       },
+};
+
 static struct mv_drv controller = {
-       .gadget = {
-               .ep0 = &ep[0].ep,
-               .name = "mv_udc",
+       .gadget = {
+               .name   = "mv_udc",
+               .ops    = &mv_udc_ops,
        },
 };
 
+/**
+ * mv_get_qh() - return queue head for endpoint
+ * @ep_num:    Endpoint number
+ * @dir_in:    Direction of the endpoint (IN = 1, OUT = 0)
+ *
+ * This function returns the QH associated with particular endpoint
+ * and it's direction.
+ */
+static struct ept_queue_head *mv_get_qh(int ep_num, int dir_in)
+{
+       return &controller.epts[(ep_num * 2) + dir_in];
+}
+
+/**
+ * mv_get_qtd() - return queue item for endpoint
+ * @ep_num:    Endpoint number
+ * @dir_in:    Direction of the endpoint (IN = 1, OUT = 0)
+ *
+ * This function returns the QH associated with particular endpoint
+ * and it's direction.
+ */
+static struct ept_queue_item *mv_get_qtd(int ep_num, int dir_in)
+{
+       return controller.items[(ep_num * 2) + dir_in];
+}
+
+/**
+ * mv_flush_qh - flush cache over queue head
+ * @ep_num:    Endpoint number
+ *
+ * This function flushes cache over QH for particular endpoint.
+ */
+static void mv_flush_qh(int ep_num)
+{
+       struct ept_queue_head *head = mv_get_qh(ep_num, 0);
+       const uint32_t start = (uint32_t)head;
+       const uint32_t end = start + 2 * sizeof(*head);
+
+       flush_dcache_range(start, end);
+}
+
+/**
+ * mv_invalidate_qh - invalidate cache over queue head
+ * @ep_num:    Endpoint number
+ *
+ * This function invalidates cache over QH for particular endpoint.
+ */
+static void mv_invalidate_qh(int ep_num)
+{
+       struct ept_queue_head *head = mv_get_qh(ep_num, 0);
+       uint32_t start = (uint32_t)head;
+       uint32_t end = start + 2 * sizeof(*head);
+
+       invalidate_dcache_range(start, end);
+}
+
+/**
+ * mv_flush_qtd - flush cache over queue item
+ * @ep_num:    Endpoint number
+ *
+ * This function flushes cache over qTD pair for particular endpoint.
+ */
+static void mv_flush_qtd(int ep_num)
+{
+       struct ept_queue_item *item = mv_get_qtd(ep_num, 0);
+       const uint32_t start = (uint32_t)item;
+       const uint32_t end_raw = start + 2 * sizeof(*item);
+       const uint32_t end = roundup(end_raw, ARCH_DMA_MINALIGN);
+
+       flush_dcache_range(start, end);
+}
+
+/**
+ * mv_invalidate_qtd - invalidate cache over queue item
+ * @ep_num:    Endpoint number
+ *
+ * This function invalidates cache over qTD pair for particular endpoint.
+ */
+static void mv_invalidate_qtd(int ep_num)
+{
+       struct ept_queue_item *item = mv_get_qtd(ep_num, 0);
+       const uint32_t start = (uint32_t)item;
+       const uint32_t end_raw = start + 2 * sizeof(*item);
+       const uint32_t end = roundup(end_raw, ARCH_DMA_MINALIGN);
+
+       invalidate_dcache_range(start, end);
+}
+
 static struct usb_request *
 mv_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags)
 {
@@ -102,9 +213,9 @@ static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *_req)
 static void ep_enable(int num, int in)
 {
        struct ept_queue_head *head;
-       struct mv_udc *udc = controller.udc;
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor;
        unsigned n;
-       head = epts + 2*num + in;
+       head = mv_get_qh(num, in);
 
        n = readl(&udc->epctrl[num]);
        if (in)
@@ -112,8 +223,10 @@ static void ep_enable(int num, int in)
        else
                n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
 
-       if (num != 0)
+       if (num != 0) {
                head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE) | CONFIG_ZLT;
+               mv_flush_qh(num);
+       }
        writel(n, &udc->epctrl[num]);
 }
 
@@ -134,40 +247,108 @@ static int mv_ep_disable(struct usb_ep *ep)
        return 0;
 }
 
+static int mv_bounce(struct mv_ep *ep)
+{
+       uint32_t addr = (uint32_t)ep->req.buf;
+       uint32_t ba;
+
+       /* Input buffer address is not aligned. */
+       if (addr & (ARCH_DMA_MINALIGN - 1))
+               goto align;
+
+       /* Input buffer length is not aligned. */
+       if (ep->req.length & (ARCH_DMA_MINALIGN - 1))
+               goto align;
+
+       /* The buffer is well aligned, only flush cache. */
+       ep->b_len = ep->req.length;
+       ep->b_buf = ep->req.buf;
+       goto flush;
+
+align:
+       /* Use internal buffer for small payloads. */
+       if (ep->req.length <= 64) {
+               ep->b_len = 64;
+               ep->b_buf = ep->b_fast;
+       } else {
+               ep->b_len = roundup(ep->req.length, ARCH_DMA_MINALIGN);
+               ep->b_buf = memalign(ARCH_DMA_MINALIGN, ep->b_len);
+               if (!ep->b_buf)
+                       return -ENOMEM;
+       }
+
+       memcpy(ep->b_buf, ep->req.buf, ep->req.length);
+
+flush:
+       ba = (uint32_t)ep->b_buf;
+       flush_dcache_range(ba, ba + ep->b_len);
+
+       return 0;
+}
+
+static void mv_debounce(struct mv_ep *ep)
+{
+       uint32_t addr = (uint32_t)ep->req.buf;
+       uint32_t ba = (uint32_t)ep->b_buf;
+
+       invalidate_dcache_range(ba, ba + ep->b_len);
+
+       /* Input buffer address is not aligned. */
+       if (addr & (ARCH_DMA_MINALIGN - 1))
+               goto copy;
+
+       /* Input buffer length is not aligned. */
+       if (ep->req.length & (ARCH_DMA_MINALIGN - 1))
+               goto copy;
+
+       /* The buffer is well aligned, only invalidate cache. */
+       return;
+
+copy:
+       memcpy(ep->req.buf, ep->b_buf, ep->req.length);
+
+       /* Large payloads use allocated buffer, free it. */
+       if (ep->req.length > 64)
+               free(ep->b_buf);
+}
+
 static int mv_ep_queue(struct usb_ep *ep,
                struct usb_request *req, gfp_t gfp_flags)
 {
        struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
-       struct mv_udc *udc = controller.udc;
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor;
        struct ept_queue_item *item;
        struct ept_queue_head *head;
-       unsigned phys;
-       int bit, num, len, in;
+       int bit, num, len, in, ret;
        num = mv_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
        in = (mv_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
-       item = items[2 * num + in];
-       head = epts + 2 * num + in;
-       phys = (unsigned)req->buf;
+       item = mv_get_qtd(num, in);
+       head = mv_get_qh(num, in);
        len = req->length;
 
+       ret = mv_bounce(mv_ep);
+       if (ret)
+               return ret;
+
        item->next = TERMINATE;
        item->info = INFO_BYTES(len) | INFO_IOC | INFO_ACTIVE;
-       item->page0 = phys;
-       item->page1 = (phys & 0xfffff000) + 0x1000;
+       item->page0 = (uint32_t)mv_ep->b_buf;
+       item->page1 = ((uint32_t)mv_ep->b_buf & 0xfffff000) + 0x1000;
 
        head->next = (unsigned) item;
        head->info = 0;
 
-       DBG("ept%d %s queue len %x, buffer %x\n",
-                       num, in ? "in" : "out", len, phys);
+       DBG("ept%d %s queue len %x, buffer %p\n",
+           num, in ? "in" : "out", len, mv_ep->b_buf);
 
        if (in)
                bit = EPT_TX(num);
        else
                bit = EPT_RX(num);
 
-       flush_cache(phys, len);
-       flush_cache((unsigned long)item, sizeof(struct ept_queue_item));
+       mv_flush_qh(num);
+       mv_flush_qtd(num);
+
        writel(bit, &udc->epprime);
 
        return 0;
@@ -181,13 +362,17 @@ static void handle_ep_complete(struct mv_ep *ep)
        in = (ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
        if (num == 0)
                ep->desc = &ep0_out_desc;
-       item = items[2 * num + in];
-
+       item = mv_get_qtd(num, in);
+       mv_invalidate_qtd(num);
+       
        if (item->info & 0xff)
                printf("EP%d/%s FAIL nfo=%x pg0=%x\n",
                        num, in ? "in" : "out", item->info, item->page0);
 
        len = (item->info >> 16) & 0x7fff;
+
+       mv_debounce(ep);
+
        ep->req.length -= len;
        DBG("ept%d %s complete %x\n",
                        num, in ? "in" : "out", len);
@@ -203,16 +388,16 @@ static void handle_ep_complete(struct mv_ep *ep)
 
 static void handle_setup(void)
 {
-       struct usb_request *req = &ep[0].req;
-       struct mv_udc *udc = controller.udc;
+       struct usb_request *req = &controller.ep[0].req;
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor;
        struct ept_queue_head *head;
        struct usb_ctrlrequest r;
        int status = 0;
        int num, in, _num, _in, i;
        char *buf;
-       head = epts;
+       head = mv_get_qh(0, 0); /* EP0 OUT */
 
-       flush_cache((unsigned long)head, sizeof(struct ept_queue_head));
+       mv_invalidate_qh(0);
        memcpy(&r, head->setup_data, sizeof(struct usb_ctrlrequest));
        writel(EPT_RX(0), &udc->epstat);
        DBG("handle setup %s, %x, %x index %x value %x\n", reqname(r.bRequest),
@@ -226,11 +411,11 @@ static void handle_setup(void)
                if ((r.wValue == 0) && (r.wLength == 0)) {
                        req->length = 0;
                        for (i = 0; i < NUM_ENDPOINTS; i++) {
-                               if (!ep[i].desc)
+                               if (!controller.ep[i].desc)
                                        continue;
-                               num = ep[i].desc->bEndpointAddress
-                                       & USB_ENDPOINT_NUMBER_MASK;
-                               in = (ep[i].desc->bEndpointAddress
+                               num = controller.ep[i].desc->bEndpointAddress
+                                               & USB_ENDPOINT_NUMBER_MASK;
+                               in = (controller.ep[i].desc->bEndpointAddress
                                                & USB_DIR_IN) != 0;
                                if ((num == _num) && (in == _in)) {
                                        ep_enable(num, in);
@@ -277,7 +462,7 @@ static void stop_activity(void)
 {
        int i, num, in;
        struct ept_queue_head *head;
-       struct mv_udc *udc = controller.udc;
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor;
        writel(readl(&udc->epcomp), &udc->epcomp);
        writel(readl(&udc->epstat), &udc->epstat);
        writel(0xffffffff, &udc->epflush);
@@ -286,19 +471,21 @@ static void stop_activity(void)
        for (i = 0; i < NUM_ENDPOINTS; i++) {
                if (i != 0)
                        writel(0, &udc->epctrl[i]);
-               if (ep[i].desc) {
-                       num = ep[i].desc->bEndpointAddress
+               if (controller.ep[i].desc) {
+                       num = controller.ep[i].desc->bEndpointAddress
                                & USB_ENDPOINT_NUMBER_MASK;
-                       in = (ep[i].desc->bEndpointAddress & USB_DIR_IN) != 0;
-                       head = epts + (num * 2) + (in);
+                       in = (controller.ep[i].desc->bEndpointAddress
+                               & USB_DIR_IN) != 0;
+                       head = mv_get_qh(num, in);
                        head->info = INFO_ACTIVE;
+                       mv_flush_qh(num);
                }
        }
 }
 
 void udc_irq(void)
 {
-       struct mv_udc *udc = controller.udc;
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor;
        unsigned n = readl(&udc->usbsts);
        writel(n, &udc->usbsts);
        int bit, i, num, in;
@@ -320,8 +507,8 @@ void udc_irq(void)
                if (bit == 2) {
                        controller.gadget.speed = USB_SPEED_HIGH;
                        for (i = 1; i < NUM_ENDPOINTS && n; i++)
-                               if (ep[i].desc)
-                                       ep[i].ep.maxpacket = 512;
+                               if (controller.ep[i].desc)
+                                       controller.ep[i].ep.maxpacket = 512;
                } else {
                        controller.gadget.speed = USB_SPEED_FULL;
                }
@@ -340,14 +527,14 @@ void udc_irq(void)
                        writel(n, &udc->epcomp);
 
                for (i = 0; i < NUM_ENDPOINTS && n; i++) {
-                       if (ep[i].desc) {
-                               num = ep[i].desc->bEndpointAddress
+                       if (controller.ep[i].desc) {
+                               num = controller.ep[i].desc->bEndpointAddress
                                        & USB_ENDPOINT_NUMBER_MASK;
-                               in = (ep[i].desc->bEndpointAddress
+                               in = (controller.ep[i].desc->bEndpointAddress
                                                & USB_DIR_IN) != 0;
                                bit = (in) ? EPT_TX(num) : EPT_RX(num);
                                if (n & bit)
-                                       handle_ep_complete(&ep[i]);
+                                       handle_ep_complete(&controller.ep[i]);
                        }
                }
        }
@@ -356,7 +543,7 @@ void udc_irq(void)
 int usb_gadget_handle_interrupts(void)
 {
        u32 value;
-       struct mv_udc *udc = controller.udc;
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor;
 
        value = readl(&udc->usbsts);
        if (value)
@@ -367,13 +554,13 @@ int usb_gadget_handle_interrupts(void)
 
 static int mv_pullup(struct usb_gadget *gadget, int is_on)
 {
-       struct mv_udc *udc = controller.udc;
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor;
        if (is_on) {
                /* RESET */
                writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RST, &udc->usbcmd);
                udelay(200);
 
-               writel((unsigned) epts, &udc->epinitaddr);
+               writel((unsigned)controller.epts, &udc->epinitaddr);
 
                /* select DEVICE mode */
                writel(USBMODE_DEVICE, &udc->usbmode);
@@ -395,7 +582,7 @@ static int mv_pullup(struct usb_gadget *gadget, int is_on)
 
 void udc_disconnect(void)
 {
-       struct mv_udc *udc = controller.udc;
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor;
        /* disable pullup */
        stop_activity();
        writel(USBCMD_FS2, &udc->usbcmd);
@@ -407,18 +594,48 @@ void udc_disconnect(void)
 static int mvudc_probe(void)
 {
        struct ept_queue_head *head;
+       uint8_t *imem;
        int i;
 
-       controller.gadget.ops = &mv_udc_ops;
-       controller.udc = (struct mv_udc *)CONFIG_USB_REG_BASE;
-       epts = memalign(PAGE_SIZE, QH_MAXNUM * sizeof(struct ept_queue_head));
-       memset(epts, 0, QH_MAXNUM * sizeof(struct ept_queue_head));
+       const int num = 2 * NUM_ENDPOINTS;
+
+       const int eplist_min_align = 4096;
+       const int eplist_align = roundup(eplist_min_align, ARCH_DMA_MINALIGN);
+       const int eplist_raw_sz = num * sizeof(struct ept_queue_head);
+       const int eplist_sz = roundup(eplist_raw_sz, ARCH_DMA_MINALIGN);
+
+       const int ilist_align = roundup(ARCH_DMA_MINALIGN, 32);
+       const int ilist_ent_raw_sz = 2 * sizeof(struct ept_queue_item);
+       const int ilist_ent_sz = roundup(ilist_ent_raw_sz, ARCH_DMA_MINALIGN);
+       const int ilist_sz = NUM_ENDPOINTS * ilist_ent_sz;
+
+       /* The QH list must be aligned to 4096 bytes. */
+       controller.epts = memalign(eplist_align, eplist_sz);
+       if (!controller.epts)
+               return -ENOMEM;
+       memset(controller.epts, 0, eplist_sz);
+
+       /*
+        * Each qTD item must be 32-byte aligned, each qTD touple must be
+        * cacheline aligned. There are two qTD items for each endpoint and
+        * only one of them is used for the endpoint at time, so we can group
+        * them together.
+        */
+       controller.items_mem = memalign(ilist_align, ilist_sz);
+       if (!controller.items_mem) {
+               free(controller.epts);
+               return -ENOMEM;
+       }
+
        for (i = 0; i < 2 * NUM_ENDPOINTS; i++) {
                /*
-                * For item0 and item1, they are served as ep0
-                * out&in seperately
+                * Configure QH for each endpoint. The structure of the QH list
+                * is such that each two subsequent fields, N and N+1 where N is
+                * even, in the QH list represent QH for one endpoint. The Nth
+                * entry represents OUT configuration and the N+1th entry does
+                * represent IN configuration of the endpoint.
                 */
-               head = epts + i;
+               head = controller.epts + i;
                if (i < 2)
                        head->config = CONFIG_MAX_PKT(EP0_MAX_PACKET_SIZE)
                                | CONFIG_ZLT | CONFIG_IOS;
@@ -428,49 +645,65 @@ static int mvudc_probe(void)
                head->next = TERMINATE;
                head->info = 0;
 
-               items[i] = memalign(PAGE_SIZE, sizeof(struct ept_queue_item));
+               imem = controller.items_mem + ((i >> 1) * ilist_ent_sz);
+               if (i & 1)
+                       imem += sizeof(struct ept_queue_item);
+
+               controller.items[i] = (struct ept_queue_item *)imem;
+
+               if (i & 1) {
+                       mv_flush_qh(i - 1);
+                       mv_flush_qtd(i - 1);
+               }
        }
 
        INIT_LIST_HEAD(&controller.gadget.ep_list);
-       ep[0].ep.maxpacket = 64;
-       ep[0].ep.name = "ep0";
-       ep[0].desc = &ep0_in_desc;
+
+       /* Init EP 0 */
+       memcpy(&controller.ep[0].ep, &mv_ep_init[0], sizeof(*mv_ep_init));
+       controller.ep[0].desc = &ep0_in_desc;
+       controller.gadget.ep0 = &controller.ep[0].ep;
        INIT_LIST_HEAD(&controller.gadget.ep0->ep_list);
-       for (i = 0; i < 2 * NUM_ENDPOINTS; i++) {
-               if (i != 0) {
-                       ep[i].ep.maxpacket = 512;
-                       ep[i].ep.name = "ep-";
-                       list_add_tail(&ep[i].ep.ep_list,
-                                     &controller.gadget.ep_list);
-                       ep[i].desc = NULL;
-               }
-               ep[i].ep.ops = &mv_ep_ops;
+
+       /* Init EP 1..n */
+       for (i = 1; i < NUM_ENDPOINTS; i++) {
+               memcpy(&controller.ep[i].ep, &mv_ep_init[1],
+                      sizeof(*mv_ep_init));
+               list_add_tail(&controller.ep[i].ep.ep_list,
+                             &controller.gadget.ep_list);
        }
+
        return 0;
 }
 
 int usb_gadget_register_driver(struct usb_gadget_driver *driver)
 {
-       struct mv_udc *udc = controller.udc;
-       int             retval;
-
-       if (!driver
-                       || driver->speed < USB_SPEED_FULL
-                       || !driver->bind
-                       || !driver->setup) {
-               DBG("bad parameter.\n");
+       struct mv_udc *udc;
+       int ret;
+
+       if (!driver)
                return -EINVAL;
-       }
+       if (!driver->bind || !driver->setup || !driver->disconnect)
+               return -EINVAL;
+       if (driver->speed != USB_SPEED_FULL && driver->speed != USB_SPEED_HIGH)
+               return -EINVAL;
+
+       ret = usb_lowlevel_init(0, (void **)&controller.ctrl);
+       if (ret)
+               return ret;
+
+       ret = mvudc_probe();
+       if (!ret) {
+               udc = (struct mv_udc *)controller.ctrl->hcor;
 
-       if (!mvudc_probe()) {
-               usb_lowlevel_init();
                /* select ULPI phy */
                writel(PTS(PTS_ENABLE) | PFSC, &udc->portsc);
        }
-       retval = driver->bind(&controller.gadget);
-       if (retval) {
-               DBG("driver->bind() returned %d\n", retval);
-               return retval;
+
+       ret = driver->bind(&controller.gadget);
+       if (ret) {
+               DBG("driver->bind() returned %d\n", ret);
+               return ret;
        }
        controller.driver = driver;
 
index 706cf0cb7dba246c2c567b5da4111590bb9679b9..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))
@@ -954,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++) {
index a47e078f62a14e8b107c8b3859b4776b4a4197ff..032d5e5ec25b327ce85fda684c1aac4563304c9b 100644 (file)
@@ -28,18 +28,21 @@ static struct omap_ehci *const ehci = (struct omap_ehci *)OMAP_EHCI_BASE;
 
 static int omap_uhh_reset(void)
 {
-       unsigned long init = get_timer(0);
-
-       /* perform UHH soft reset, and wait until reset is complete */
-       writel(OMAP_UHH_SYSCONFIG_SOFTRESET, &uhh->sysc);
-
-       /* Wait for UHH reset to complete */
-       while (!(readl(&uhh->syss) & OMAP_UHH_SYSSTATUS_EHCI_RESETDONE))
-               if (get_timer(init) > CONFIG_SYS_HZ) {
-                       debug("OMAP UHH error: timeout resetting ehci\n");
-                       return -EL3RST;
-               }
-
+/*
+ * Soft resetting the UHH module causes instability issues on
+ * all OMAPs so we just avoid it.
+ *
+ * See OMAP36xx Errata
+ *  i571: USB host EHCI may stall when entering smart-standby mode
+ *  i660: USBHOST Configured In Smart-Idle Can Lead To a Deadlock
+ *
+ * On OMAP4/5, soft-resetting the UHH module will put it into
+ * Smart-Idle mode and lead to a deadlock.
+ *
+ * On OMAP3, this doesn't seem to be the case but still instabilities
+ * are observed on beagle (3530 ES1.0) if soft-reset is used.
+ * e.g. NFS root failures with Linux kernel.
+ */
        return 0;
 }
 
index d090f0a53e87349ee96a5bfe7d64a917bf153d0e..bd52afe2626fa58df48b23357cf3c987f4c4bdcf 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef USB_EHCI_H
 #define USB_EHCI_H
 
+#include <usb.h>
+
 #if !defined(CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS)
 #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS     2
 #endif
@@ -252,6 +254,17 @@ struct QH {
        };
 };
 
+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;
+};
+
 /* Low level init functions */
 int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor);
 int ehci_hcd_stop(int index);
index 6c7d2271371ebfb4f8c2dd52dab8f904e769d920..1d4006de8bab3f31bb119fe45b477c7d432d6bcc 100644 (file)
@@ -109,6 +109,8 @@ const char *dfu_get_dev_type(enum dfu_device_type t);
 const char *dfu_get_layout(enum dfu_layout l);
 struct dfu_entity *dfu_get_entity(int alt);
 char *dfu_extract_token(char** e, int *n);
+void dfu_trigger_reset(void);
+bool dfu_reset(void);
 
 int dfu_read(struct dfu_entity *de, void *buf, int size, int blk_seq_num);
 int dfu_write(struct dfu_entity *de, void *buf, int size, int blk_seq_num);
index c7696e6a3ef724c5782612575590c4f7af74dee4..c71516cf6daa01f56c6bbea77e7bbf221fd603a6 100644 (file)
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
-/* Endpoint 0 states */
-#define EP0_IDLE               0
-#define EP0_IN_DATA            1
-#define EP0_OUT_DATA           2
-#define EP0_XFER_COMPLETE      3
+#include "../../drivers/usb/host/ehci.h"
 
+#define NUM_ENDPOINTS          6
 
 /* Endpoint parameters */
 #define MAX_ENDPOINTS          4
-#define EP_MAX_PACKET_SIZE     0x200
 
+#define EP_MAX_PACKET_SIZE     0x200
 #define EP0_MAX_PACKET_SIZE    64
-#define UDC_OUT_ENDPOINT        0x02
-#define UDC_OUT_PACKET_SIZE    EP_MAX_PACKET_SIZE
-#define UDC_IN_ENDPOINT         0x01
-#define UDC_IN_PACKET_SIZE      EP_MAX_PACKET_SIZE
-#define UDC_INT_ENDPOINT        0x05
-#define UDC_INT_PACKET_SIZE     EP_MAX_PACKET_SIZE
-#define UDC_BULK_PACKET_SIZE    EP_MAX_PACKET_SIZE
-
-#define        NUM_ENDPOINTS   6
-#define                REQ_COUNT       12
-struct mv_ep {
-       struct usb_ep ep;
-       struct usb_request req;
-       struct list_head queue;
-       const struct usb_endpoint_descriptor *desc;
-};
 
 struct mv_udc {
-       u32 pad0[80];
 #define MICRO_8FRAME   0x8
-#define USBCMD_ITC(x)  (((x > 0xff) ? 0xff : x) << 16)
+#define USBCMD_ITC(x)  ((((x) > 0xff) ? 0xff : x) << 16)
 #define USBCMD_FS2     (1 << 15)
 #define USBCMD_RST     (1 << 1)
 #define USBCMD_RUN     (1)
@@ -62,37 +42,52 @@ struct mv_udc {
        u32 epinitaddr;         /* 0x158 */
        u32 pad2[10];
 #define PTS_ENABLE     2
-#define PTS(x)         ((x & 0x3) << 30)
+#define PTS(x)         (((x) & 0x3) << 30)
 #define PFSC           (1 << 24)
        u32 portsc;             /* 0x184 */
        u32 pad3[8];
 #define USBMODE_DEVICE 2
        u32 usbmode;            /* 0x1a8 */
        u32 epstat;             /* 0x1ac */
-#define EPT_TX(x)      (1 << ((x & 0xffff) + 16))
-#define EPT_RX(x)      (1 << (x & 0xffff))
+#define EPT_TX(x)      (1 << (((x) & 0xffff) + 16))
+#define EPT_RX(x)      (1 << ((x) & 0xffff))
        u32 epprime;            /* 0x1b0 */
        u32 epflush;            /* 0x1b4 */
        u32 pad4;
        u32 epcomp;             /* 0x1bc */
-#define CTRL_TXE              (1 << 23)
-#define CTRL_TXR              (1 << 22)
-#define CTRL_RXE              (1 << 7)
-#define CTRL_RXR              (1 << 6)
-#define CTRL_TXT_BULK         (2 << 18)
-#define CTRL_RXT_BULK         (2 << 2)
+#define CTRL_TXE       (1 << 23)
+#define CTRL_TXR       (1 << 22)
+#define CTRL_RXE       (1 << 7)
+#define CTRL_RXR       (1 << 6)
+#define CTRL_TXT_BULK  (2 << 18)
+#define CTRL_RXT_BULK  (2 << 2)
        u32 epctrl[16];         /* 0x1c0 */
 };
 
+struct mv_ep {
+       struct usb_ep ep;
+       struct list_head queue;
+       const struct usb_endpoint_descriptor *desc;
+
+       struct usb_request req;
+       uint8_t *b_buf;
+       uint32_t b_len;
+       uint8_t b_fast[64] __aligned(ARCH_DMA_MINALIGN);
+};
+
 struct mv_drv {
        struct usb_gadget               gadget;
-       struct usb_gadget_driver                *driver;
-       struct mv_udc                   *udc;
+       struct usb_gadget_driver        *driver;
+       struct ehci_ctrl                *ctrl;
+       struct ept_queue_head           *epts;
+       struct ept_queue_item           *items[2 * NUM_ENDPOINTS];
+       uint8_t                         *items_mem;
+       struct mv_ep                    ep[NUM_ENDPOINTS];
 };
 
 struct ept_queue_head {
        unsigned config;
-       unsigned current; /* read-only */
+       unsigned current;       /* read-only */
 
        unsigned next;
        unsigned info;
@@ -111,9 +106,9 @@ struct ept_queue_head {
        unsigned reserved_4;
 };
 
-#define CONFIG_MAX_PKT(n)     ((n) << 16)
-#define CONFIG_ZLT            (1 << 29)    /* stop on zero-len xfer */
-#define CONFIG_IOS            (1 << 15)    /* IRQ on setup */
+#define CONFIG_MAX_PKT(n)      ((n) << 16)
+#define CONFIG_ZLT             (1 << 29)       /* stop on zero-len xfer */
+#define CONFIG_IOS             (1 << 15)       /* IRQ on setup */
 
 struct ept_queue_item {
        unsigned next;
@@ -127,12 +122,11 @@ struct ept_queue_item {
 };
 
 #define TERMINATE 1
-#define INFO_BYTES(n)         ((n) << 16)
-#define INFO_IOC              (1 << 15)
-#define INFO_ACTIVE           (1 << 7)
-#define INFO_HALTED           (1 << 6)
-#define INFO_BUFFER_ERROR     (1 << 5)
-#define INFO_TX_ERROR         (1 << 3)
-
-extern int usb_lowlevel_init(int index, void **controller);
+#define INFO_BYTES(n)          ((n) << 16)
+#define INFO_IOC               (1 << 15)
+#define INFO_ACTIVE            (1 << 7)
+#define INFO_HALTED            (1 << 6)
+#define INFO_BUFFER_ERROR      (1 << 5)
+#define INFO_TX_ERROR          (1 << 3)
+
 #endif /* __MV_UDC_H__ */