Message ID | 20201021100229.18366-2-ran.wang_1@nxp.com |
---|---|
State | Deferred |
Delegated to: | Tom Rini |
Headers | show |
Series | dwc3-generic: Add Layerscape support | expand |
Hi Bin, Marek, Any comment for this serial? Thanks in advance. Regards, Ran On Wednesday, October 21, 2020 6:02 PM, Ran Wang wrote: > > 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; > }; > -- > 2.7.4
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; };
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(+)