usb: dwc3: gadget: make use of No Response Update Transfer
authorFelipe Balbi <felipe.balbi@linux.intel.com>
Thu, 22 Sep 2016 07:56:08 +0000 (10:56 +0300)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Mon, 31 Oct 2016 09:15:34 +0000 (11:15 +0200)
No Response Update Transfer is a special type of
Update Transfer command which can be used whenever
we're not relying on XferNotReady to prepare
transfers. With this, we don't need to wait for
CMDACT to be cleared and issue further commands to
the endpoint straight away.

Let's start using this version to skip the long-ish
wait.

Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
drivers/usb/dwc3/gadget.c

index 4ed8b34540f20236f01cc1d97b0afdd3a737b700..45782d7ec67b5299d2b6168c24a026ac1f1fdcf1 100644 (file)
@@ -233,6 +233,7 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc);
 int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
                struct dwc3_gadget_ep_cmd_params *params)
 {
+       const struct usb_endpoint_descriptor *desc = dep->endpoint.desc;
        struct dwc3             *dwc = dep->dwc;
        u32                     timeout = 500;
        u32                     reg;
@@ -276,7 +277,28 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
        dwc3_writel(dep->regs, DWC3_DEPCMDPAR1, params->param1);
        dwc3_writel(dep->regs, DWC3_DEPCMDPAR2, params->param2);
 
-       dwc3_writel(dep->regs, DWC3_DEPCMD, cmd | DWC3_DEPCMD_CMDACT);
+       /*
+        * Synopsys Databook 2.60a states in section 6.3.2.5.6 of that if we're
+        * not relying on XferNotReady, we can make use of a special "No
+        * Response Update Transfer" command where we should clear both CmdAct
+        * and CmdIOC bits.
+        *
+        * With this, we don't need to wait for command completion and can
+        * straight away issue further commands to the endpoint.
+        *
+        * NOTICE: We're making an assumption that control endpoints will never
+        * make use of Update Transfer command. This is a safe assumption
+        * because we can never have more than one request at a time with
+        * Control Endpoints. If anybody changes that assumption, this chunk
+        * needs to be updated accordingly.
+        */
+       if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_UPDATETRANSFER &&
+                       !usb_endpoint_xfer_isoc(desc))
+               cmd &= ~(DWC3_DEPCMD_CMDIOC | DWC3_DEPCMD_CMDACT);
+       else
+               cmd |= DWC3_DEPCMD_CMDACT;
+
+       dwc3_writel(dep->regs, DWC3_DEPCMD, cmd);
        do {
                reg = dwc3_readl(dep->regs, DWC3_DEPCMD);
                if (!(reg & DWC3_DEPCMD_CMDACT)) {