]> git.sur5r.net Git - u-boot/blobdiff - drivers/usb/dwc3/gadget.c
Merge branch 'master' of http://git.denx.de/u-boot-sunxi
[u-boot] / drivers / usb / dwc3 / gadget.c
index 1f977290ff0eee2438996a921faffc1fbbbab6ca..f3d649a5ee2f85d66bef3c4f5b1d2a5f55a26a6d 100644 (file)
@@ -244,6 +244,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
 
        list_del(&req->list);
        req->trb = NULL;
+       dwc3_flush_cache((int)req->request.dma, req->request.length);
 
        if (req->request.status == -EINPROGRESS)
                req->request.status = status;
@@ -769,6 +770,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
                trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
 
        trb->ctrl |= DWC3_TRB_CTRL_HWO;
+
+       dwc3_flush_cache((int)dma, length);
+       dwc3_flush_cache((int)trb, sizeof(*trb));
 }
 
 /*
@@ -785,7 +789,6 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
        struct dwc3_request     *req, *n;
        u32                     trbs_left;
        u32                     max;
-       unsigned int            last_one = 0;
 
        BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
 
@@ -835,24 +838,14 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
        list_for_each_entry_safe(req, n, &dep->request_list, list) {
                unsigned        length;
                dma_addr_t      dma;
-               last_one = false;
 
                dma = req->request.dma;
                length = req->request.length;
-               trbs_left--;
-
-               if (!trbs_left)
-                       last_one = 1;
-
-               /* Is this the last request? */
-               if (list_is_last(&req->list, &dep->request_list))
-                       last_one = 1;
 
                dwc3_prepare_one_trb(dep, req, dma, length,
-                               last_one, false, 0);
+                                    true, false, 0);
 
-               if (last_one)
-                       break;
+               break;
        }
 }
 
@@ -970,6 +963,14 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
        req->direction          = dep->direction;
        req->epnum              = dep->number;
 
+       /*
+        * DWC3 hangs on OUT requests smaller than maxpacket size,
+        * so HACK the request length
+        */
+       if (dep->direction == 0 &&
+           req->request.length < dep->endpoint.maxpacket)
+               req->request.length = dep->endpoint.maxpacket;
+
        /*
         * We only add to our list of requests now and
         * start consuming the list once we get XferNotReady
@@ -1604,7 +1605,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
                } else {
                        int             ret;
 
-                       usb_ep_set_maxpacket_limit(&dep->endpoint, 1024);
+                       usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
                        dep->endpoint.max_streams = 15;
                        dep->endpoint.ops = &dwc3_gadget_ep_ops;
                        list_add_tail(&dep->endpoint.ep_list,
@@ -1754,32 +1755,23 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
        struct dwc3_request     *req;
        struct dwc3_trb         *trb;
        unsigned int            slot;
-       int                     ret;
 
-       do {
-               req = next_request(&dep->req_queued);
-               if (!req) {
-                       WARN_ON_ONCE(1);
-                       return 1;
-               }
-
-               slot = req->start_slot;
-               if ((slot == DWC3_TRB_NUM - 1) &&
-                       usb_endpoint_xfer_isoc(dep->endpoint.desc))
-                       slot++;
-               slot %= DWC3_TRB_NUM;
-               trb = &dep->trb_pool[slot];
-
-               ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
-                               event, status);
-               if (ret)
-                       break;
+       req = next_request(&dep->req_queued);
+       if (!req) {
+               WARN_ON_ONCE(1);
+               return 1;
+       }
 
-               dwc3_gadget_giveback(dep, req, status);
+       slot = req->start_slot;
+       if ((slot == DWC3_TRB_NUM - 1) &&
+           usb_endpoint_xfer_isoc(dep->endpoint.desc))
+               slot++;
+       slot %= DWC3_TRB_NUM;
+       trb = &dep->trb_pool[slot];
 
-               if (ret)
-                       break;
-       } while (1);
+       dwc3_flush_cache((int)trb, sizeof(*trb));
+       __dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status);
+       dwc3_gadget_giveback(dep, req, status);
 
        if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
                        list_empty(&dep->req_queued)) {
@@ -2362,7 +2354,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
 static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
                unsigned int evtinfo)
 {
-       unsigned int is_ss = evtinfo & BIT(4);
+       unsigned int is_ss = evtinfo & (1UL << 4);
 
        /**
         * WORKAROUND: DWC3 revison 2.20a with hibernation support
@@ -2575,7 +2567,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
                goto err0;
        }
 
-       dwc->ep0_trb = dma_alloc_coherent(sizeof(*dwc->ep0_trb),
+       dwc->ep0_trb = dma_alloc_coherent(sizeof(*dwc->ep0_trb) * 2,
                                          (unsigned long *)&dwc->ep0_trb_addr);
        if (!dwc->ep0_trb) {
                dev_err(dwc->dev, "failed to allocate ep0 trb\n");
@@ -2583,7 +2575,8 @@ int dwc3_gadget_init(struct dwc3 *dwc)
                goto err1;
        }
 
-       dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
+       dwc->setup_buf = memalign(CONFIG_SYS_CACHELINE_SIZE,
+                                 DWC3_EP0_BOUNCE_SIZE);
        if (!dwc->setup_buf) {
                ret = -ENOMEM;
                goto err2;
@@ -2669,6 +2662,17 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
  */
 void dwc3_gadget_uboot_handle_interrupt(struct dwc3 *dwc)
 {
-       dwc3_interrupt(0, dwc);
-       dwc3_thread_interrupt(0, dwc);
+       int ret = dwc3_interrupt(0, dwc);
+
+       if (ret == IRQ_WAKE_THREAD) {
+               int i;
+               struct dwc3_event_buffer *evt;
+
+               for (i = 0; i < dwc->num_event_buffers; i++) {
+                       evt = dwc->ev_buffs[i];
+                       dwc3_flush_cache((int)evt->buf, evt->length);
+               }
+
+               dwc3_thread_interrupt(0, dwc);
+       }
 }