diff options
| author | Chris Morgan <[email protected]> | 2026-01-15 17:01:34 -0600 |
|---|---|---|
| committer | Mattijs Korpershoek <[email protected]> | 2026-01-30 08:59:21 +0100 |
| commit | de69f14a0991f3b9afe78dc0721a9184d297e303 (patch) | |
| tree | 6901b7dd919bb4b63204cbcbade059e0e047b19a /drivers/usb | |
| parent | 7590f29e2cd72fb8ed50efde3cdb786d74dc1f10 (diff) | |
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.
Note that this patch was submitted upstream in Linux in 2020 [1],
and I've confirmed I need it in U-Boot to enable gadget mode.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/patch/drivers/usb/dwc3?id=5b738211fb59e114727381d07c647a77c0010996
Signed-off-by: Thinh Nguyen <[email protected]>
Signed-off-by: Chris Morgan <[email protected]>
Reviewed-by: Mattijs Korpershoek <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Mattijs Korpershoek <[email protected]>
Diffstat (limited to 'drivers/usb')
| -rw-r--r-- | drivers/usb/dwc3/gadget.c | 16 | ||||
| -rw-r--r-- | drivers/usb/dwc3/gadget.h | 14 |
2 files changed, 21 insertions, 9 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d2ae892d554..24ae0c232f6 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -62,7 +62,7 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) return -EINVAL; } - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); return 0; } @@ -1422,7 +1422,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) dwc->pullups_connected = false; } - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); do { udelay(2000); @@ -2137,10 +2137,8 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_INITU1ENA; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - reg &= ~DWC3_DCTL_INITU2ENA; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); dwc3_disconnect_gadget(dwc); dwc->start_config_issued = false; @@ -2189,7 +2187,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_TSTCTRL_MASK; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); dwc->test_mode = false; dwc3_stop_active_transfers(dwc); @@ -2305,11 +2303,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A) reg |= DWC3_DCTL_LPM_ERRATA(dwc->lpm_nyet_threshold); - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); } else { reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_HIRD_THRES_MASK; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); } dep = dwc->eps[0]; @@ -2417,7 +2415,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, reg &= ~u1u2; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); break; default: /* do nothing */ diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index f28a9755dcb..e4f5a096956 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -104,4 +104,18 @@ static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number) return 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 */ |
