
Register Global frame length adjustment is used to do frame length adjustment for SOF/ITP counter which is running on the ref_clk. Allow updating it could help on avoiding potential USB 2.0 devices time-out over a longer run.
Refer to Linux commit db2be4e9e30c (“usb: dwc3: Add frame length adjustment quirk”)
Signed-off-by: Ran Wang ran.wang_1@nxp.com --- Change in v2: - None
drivers/usb/dwc3/core.c | 34 ++++++++++++++++++++++++++++++++++ drivers/usb/dwc3/core.h | 7 +++++++ 2 files changed, 41 insertions(+)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 2e00353..b3d4751 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -310,6 +310,25 @@ static void dwc3_free_scratch_buffers(struct dwc3 *dwc) kfree(dwc->scratchbuf); }
+/* + * dwc3_frame_length_adjustment - Adjusts frame length if required + * @dwc3: Pointer to our controller context structure + * @val: Value of frame length + */ +static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 val) +{ + u32 reg; + u32 dft; + + reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); + dft = reg & DWC3_GFLADJ_30MHZ_MASK; + if (dft != val) { + reg &= ~DWC3_GFLADJ_30MHZ_MASK; + reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | val; + dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); + } +} + static void dwc3_core_num_eps(struct dwc3 *dwc) { struct dwc3_hwparams *parms = &dwc->hwparams; @@ -569,6 +588,9 @@ static int dwc3_core_init(struct dwc3 *dwc) if (ret) goto err1;
+ if (dwc->fladj_quirk && dwc->revision >= DWC3_REVISION_250A) + dwc3_frame_length_adjustment(dwc, dwc->fladj); + return 0;
err1: @@ -958,6 +980,18 @@ void dwc3_of_parse(struct dwc3 *dwc)
dwc->hird_threshold = hird_threshold | (dwc->is_utmi_l1_suspend << 4); + + dwc->fladj_quirk = false; + if (!dev_read_u32(dev, + "snps,quirk-frame-length-adjustment", + &dwc->fladj)) { + if (dwc->fladj <= DWC3_GFLADJ_30MHZ_MASK) + dwc->fladj_quirk = true; + else + dev_err(dev, + "snps,quirk-frame-length-adjustment invalid: 0x%x\n", + dwc->fladj); + } }
int dwc3_init(struct dwc3 *dwc) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 44533fd..4650216 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -115,6 +115,7 @@ #define DWC3_GEVNTCOUNT(n) (0xc40c + (n * 0x10))
#define DWC3_GHWPARAMS8 0xc600 +#define DWC3_GFLADJ 0xc630
/* Device Registers */ #define DWC3_DCFG 0xc700 @@ -291,6 +292,10 @@ #define DWC3_DCTL_ULSTCHNG_COMPLIANCE (DWC3_DCTL_ULSTCHNGREQ(10)) #define DWC3_DCTL_ULSTCHNG_LOOPBACK (DWC3_DCTL_ULSTCHNGREQ(11))
+/* Global Frame Length Adjustment Register */ +#define DWC3_GFLADJ_30MHZ_SDBND_SEL BIT(7) +#define DWC3_GFLADJ_30MHZ_MASK 0x3f + /* Device Event Enable Register */ #define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN (1 << 12) #define DWC3_DEVTEN_EVNTOVERFLOWEN (1 << 11) @@ -764,6 +769,7 @@ struct dwc3 { u32 num_event_buffers; u32 u1u2; u32 maximum_speed; + u32 fladj; u32 revision;
#define DWC3_REVISION_173A 0x5533173a @@ -845,6 +851,7 @@ struct dwc3 {
unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; + unsigned fladj_quirk:1; int index; struct list_head list; };