|
@@ -347,6 +347,28 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep)
|
|
|
+{
|
|
|
+ struct dwc3 *dwc = dep->dwc;
|
|
|
+ struct dwc3_gadget_ep_cmd_params params;
|
|
|
+ u32 cmd = DWC3_DEPCMD_CLEARSTALL;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * As of core revision 2.60a the recommended programming model
|
|
|
+ * is to set the ClearPendIN bit when issuing a Clear Stall EP
|
|
|
+ * command for IN endpoints. This is to prevent an issue where
|
|
|
+ * some (non-compliant) hosts may not send ACK TPs for pending
|
|
|
+ * IN transfers due to a mishandled error condition. Synopsys
|
|
|
+ * STAR 9000614252.
|
|
|
+ */
|
|
|
+ if (dep->direction && (dwc->revision >= DWC3_REVISION_260A))
|
|
|
+ cmd |= DWC3_DEPCMD_CLEARPENDIN;
|
|
|
+
|
|
|
+ memset(¶ms, 0, sizeof(params));
|
|
|
+
|
|
|
+ return dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms);
|
|
|
+}
|
|
|
+
|
|
|
static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
|
|
|
struct dwc3_trb *trb)
|
|
|
{
|
|
@@ -1314,8 +1336,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
|
|
|
else
|
|
|
dep->flags |= DWC3_EP_STALL;
|
|
|
} else {
|
|
|
- ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
|
|
|
- DWC3_DEPCMD_CLEARSTALL, ¶ms);
|
|
|
+ ret = dwc3_send_clear_stall_ep_cmd(dep);
|
|
|
if (ret)
|
|
|
dev_err(dwc->dev, "failed to clear STALL on %s\n",
|
|
|
dep->name);
|
|
@@ -2247,7 +2268,6 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
|
|
|
|
|
|
for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
|
|
|
struct dwc3_ep *dep;
|
|
|
- struct dwc3_gadget_ep_cmd_params params;
|
|
|
int ret;
|
|
|
|
|
|
dep = dwc->eps[epnum];
|
|
@@ -2259,9 +2279,7 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
|
|
|
|
|
|
dep->flags &= ~DWC3_EP_STALL;
|
|
|
|
|
|
- memset(¶ms, 0, sizeof(params));
|
|
|
- ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
|
|
|
- DWC3_DEPCMD_CLEARSTALL, ¶ms);
|
|
|
+ ret = dwc3_send_clear_stall_ep_cmd(dep);
|
|
|
WARN_ON_ONCE(ret);
|
|
|
}
|
|
|
}
|