Merge tag 'dwc3-for-v3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi...
[pandora-kernel.git] / drivers / usb / dwc3 / gadget.c
index 561625a..3df1a19 100644 (file)
@@ -276,6 +276,33 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
        }
 }
 
+int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param)
+{
+       u32             timeout = 500;
+       u32             reg;
+
+       dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
+       dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
+
+       do {
+               reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
+               if (!(reg & DWC3_DGCMD_CMDACT)) {
+                       dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+                                       DWC3_DGCMD_STATUS(reg));
+                       return 0;
+               }
+
+               /*
+                * We can't sleep here, because it's also called from
+                * interrupt context.
+                */
+               timeout--;
+               if (!timeout)
+                       return -ETIMEDOUT;
+               udelay(1);
+       } while (1);
+}
+
 int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
                unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
 {
@@ -929,10 +956,12 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
        }
 
        dep->flags |= DWC3_EP_BUSY;
-       dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
-                       dep->number);
 
-       WARN_ON_ONCE(!dep->res_trans_idx);
+       if (start_new) {
+               dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+                               dep->number);
+               WARN_ON_ONCE(!dep->res_trans_idx);
+       }
 
        return 0;
 }
@@ -966,28 +995,37 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 
        list_add_tail(&req->list, &dep->request_list);
 
+       if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && (dep->flags & DWC3_EP_BUSY))
+               dep->flags |= DWC3_EP_PENDING_REQUEST;
+
        /*
-        * There is one special case: XferNotReady with
-        * empty list of requests. We need to kick the
-        * transfer here in that situation, otherwise
-        * we will be NAKing forever.
+        * There are two special cases:
+        *
+        * 1. XferNotReady with empty list of requests. We need to kick the
+        *    transfer here in that situation, otherwise we will be NAKing
+        *    forever. If we get XferNotReady before gadget driver has a
+        *    chance to queue a request, we will ACK the IRQ but won't be
+        *    able to receive the data until the next request is queued.
+        *    The following code is handling exactly that.
         *
-        * If we get XferNotReady before gadget driver
-        * has a chance to queue a request, we will ACK
-        * the IRQ but won't be able to receive the data
-        * until the next request is queued. The following
-        * code is handling exactly that.
+        * 2. XferInProgress on Isoc EP with an active transfer. We need to
+        *    kick the transfer here after queuing a request, otherwise the
+        *    core may not see the modified TRB(s).
         */
        if (dep->flags & DWC3_EP_PENDING_REQUEST) {
-               int ret;
-               int start_trans;
+               int     ret;
+               int     start_trans = 1;
+               u8      trans_idx = dep->res_trans_idx;
 
-               start_trans = 1;
                if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
-                               (dep->flags & DWC3_EP_BUSY))
+                               (dep->flags & DWC3_EP_BUSY)) {
                        start_trans = 0;
+                       WARN_ON_ONCE(!trans_idx);
+               } else {
+                       trans_idx = 0;
+               }
 
-               ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
+               ret = __dwc3_gadget_kick_transfer(dep, trans_idx, start_trans);
                if (ret && ret != -EBUSY) {
                        struct dwc3     *dwc = dep->dwc;
 
@@ -1355,7 +1393,24 @@ static int dwc3_gadget_start(struct usb_gadget *g,
 
        reg = dwc3_readl(dwc->regs, DWC3_DCFG);
        reg &= ~(DWC3_DCFG_SPEED_MASK);
-       reg |= dwc->maximum_speed;
+
+       /**
+        * WORKAROUND: DWC3 revision < 2.20a have an issue
+        * which would cause metastability state on Run/Stop
+        * bit if we try to force the IP to USB2-only mode.
+        *
+        * Because of that, we cannot configure the IP to any
+        * speed other than the SuperSpeed
+        *
+        * Refers to:
+        *
+        * STAR#9000525659: Clock Domain Crossing on DCTL in
+        * USB 2.0 Mode
+        */
+       if (dwc->revision < DWC3_REVISION_220A)
+               reg |= DWC3_DCFG_SUPERSPEED;
+       else
+               reg |= dwc->maximum_speed;
        dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
        dwc->start_config_issued = false;
@@ -1915,6 +1970,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
        reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+       reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA);
        dwc3_writel(dwc->regs, DWC3_DCTL, reg);
        dwc->test_mode = false;
 
@@ -2262,8 +2318,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
                goto err1;
        }
 
-       dwc->setup_buf = kzalloc(sizeof(*dwc->setup_buf) * 2,
-                       GFP_KERNEL);
+       dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
        if (!dwc->setup_buf) {
                dev_err(dwc->dev, "failed to allocate setup buffer\n");
                ret = -ENOMEM;
@@ -2271,7 +2326,8 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
        }
 
        dwc->ep0_bounce = dma_alloc_coherent(dwc->dev,
-                       512, &dwc->ep0_bounce_addr, GFP_KERNEL);
+                       DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr,
+                       GFP_KERNEL);
        if (!dwc->ep0_bounce) {
                dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
                ret = -ENOMEM;
@@ -2312,6 +2368,14 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
                goto err5;
        }
 
+       reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+       reg |= DWC3_DCFG_LPM_CAP;
+       dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+       reg |= DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA;
+       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
        /* Enable all but Start and End of Frame IRQs */
        reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
                        DWC3_DEVTEN_EVNTOVERFLOWEN |
@@ -2350,8 +2414,8 @@ err5:
        dwc3_gadget_free_endpoints(dwc);
 
 err4:
-       dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
-                       dwc->ep0_bounce_addr);
+       dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
+                       dwc->ep0_bounce, dwc->ep0_bounce_addr);
 
 err3:
        kfree(dwc->setup_buf);
@@ -2380,8 +2444,8 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
 
        dwc3_gadget_free_endpoints(dwc);
 
-       dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
-                       dwc->ep0_bounce_addr);
+       dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
+                       dwc->ep0_bounce, dwc->ep0_bounce_addr);
 
        kfree(dwc->setup_buf);