mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
UPSTREAM: usb: dwc3: Set the ClearPendIN bit on Clear Stall EP command
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.
Change-Id: Ic513ca50aa900fbfc64b8197a6311113630ce18a
Signed-off-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Signed-off-by: Wu Liang feng <wulf@rock-chips.com>
(cherry picked from commit 50c763f8c1)
This commit is contained in:
@@ -400,6 +400,7 @@
|
||||
#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
|
||||
#define DWC3_DEPCMD_STATUS(x) (((x) >> 12) & 0x0F)
|
||||
#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
|
||||
#define DWC3_DEPCMD_CLEARPENDIN (1 << 11)
|
||||
#define DWC3_DEPCMD_CMDACT (1 << 10)
|
||||
#define DWC3_DEPCMD_CMDIOC (1 << 8)
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -1325,8 +1347,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);
|
||||
@@ -2251,7 +2272,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];
|
||||
@@ -2263,9 +2283,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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user