|
@@ -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);
|
|
|
|