usb: dwc3: gadget: Don't send unintended link state change

DCTL.ULSTCHNGREQ is a write-only field. When doing a read-modify-write
to DCTL, the driver must make sure that there's no unintended link state
change request from whatever is read from DCTL.ULSTCHNGREQ. Set link
state change to no-action when the driver writes to DCTL.

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Thinh Nguyen 2019-10-23 19:15:43 -07:00 committed by Greg Kroah-Hartman
parent 704a940d55
commit 5b738211fb
2 changed files with 21 additions and 9 deletions

View File

@ -57,7 +57,7 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
return -EINVAL; return -EINVAL;
} }
dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc3_gadget_dctl_write_safe(dwc, reg);
return 0; return 0;
} }
@ -1828,7 +1828,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
dwc->pullups_connected = false; dwc->pullups_connected = false;
} }
dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc3_gadget_dctl_write_safe(dwc, reg);
do { do {
reg = dwc3_readl(dwc->regs, DWC3_DSTS); reg = dwc3_readl(dwc->regs, DWC3_DSTS);
@ -2761,10 +2761,8 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_INITU1ENA; reg &= ~DWC3_DCTL_INITU1ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
reg &= ~DWC3_DCTL_INITU2ENA; reg &= ~DWC3_DCTL_INITU2ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc3_gadget_dctl_write_safe(dwc, reg);
dwc3_disconnect_gadget(dwc); dwc3_disconnect_gadget(dwc);
@ -2816,7 +2814,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK; reg &= ~DWC3_DCTL_TSTCTRL_MASK;
dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc3_gadget_dctl_write_safe(dwc, reg);
dwc->test_mode = false; dwc->test_mode = false;
dwc3_clear_stall_all_ep(dwc); dwc3_clear_stall_all_ep(dwc);
@ -2920,11 +2918,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A) if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A)
reg |= DWC3_DCTL_NYET_THRES(dwc->lpm_nyet_threshold); reg |= DWC3_DCTL_NYET_THRES(dwc->lpm_nyet_threshold);
dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc3_gadget_dctl_write_safe(dwc, reg);
} else { } else {
reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_HIRD_THRES_MASK; reg &= ~DWC3_DCTL_HIRD_THRES_MASK;
dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc3_gadget_dctl_write_safe(dwc, reg);
} }
dep = dwc->eps[0]; dep = dwc->eps[0];
@ -3033,7 +3031,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
reg &= ~u1u2; reg &= ~u1u2;
dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc3_gadget_dctl_write_safe(dwc, reg);
break; break;
default: default:
/* do nothing */ /* do nothing */

View File

@ -127,4 +127,18 @@ static inline void dwc3_gadget_ep_get_transfer_index(struct dwc3_ep *dep)
dep->resource_index = DWC3_DEPCMD_GET_RSC_IDX(res_id); dep->resource_index = DWC3_DEPCMD_GET_RSC_IDX(res_id);
} }
/**
* dwc3_gadget_dctl_write_safe - write to DCTL safe from link state change
* @dwc: pointer to our context structure
* @value: value to write to DCTL
*
* Use this function when doing read-modify-write to DCTL. It will not
* send link state change request.
*/
static inline void dwc3_gadget_dctl_write_safe(struct dwc3 *dwc, u32 value)
{
value &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
dwc3_writel(dwc->regs, DWC3_DCTL, value);
}
#endif /* __DRIVERS_USB_DWC3_GADGET_H */ #endif /* __DRIVERS_USB_DWC3_GADGET_H */