[PATCH 1/8] usb: dwc3: core: Handle fladj becoming zero

Varadarajan Narayanan
2023-03-02T09:56:34Z

In dwc3_ref_clk_period, the computation

fladj = div64_u64(125000ULL * NSEC_PER_SEC, (u64)rate * period);
fladj -= 125000;

could turn out to be zero. If fladj is zero, the following
FIELD_PREP clears out that field and the user overridden value
set in the DTS using "snps,quirk-frame-length-adjustment" is
lost. Ensure to retain the user overridden value if the above
evaluates to 0.

Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com>
---
drivers/usb/dwc3/core.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 476b636..63af83b 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -401,6 +401,33 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc)
fladj -= 125000;

/*
+ * Since rate = NSEC_PER_SEC / period and period = NSEC_PER_SEC / rate
+ * above calculation could turn out to be zero.
+ *
+ * if (dwc->ref_clk)
+ * 125000 * NSEC_PER_SEC 125000 * NSEC_PER_SEC
+ * --------------------- => ---------------------
+ * rate * period rate * NSEC_PER_SEC
+ * ------------
+ * rate
+ * else
+ * 125000 * NSEC_PER_SEC 125000 * NSEC_PER_SEC
+ * --------------------- => ---------------------
+ * rate * period NSEC_PER_SEC * period
+ * ------------
+ * period
+ * Hence, the calculation
+ * div64_u64(125000ULL * NSEC_PER_SEC, (u64)rate * period)
+ * returns 125000ULL and fladj -= 125000 sets fladj to zero.
+ * If fladj is zero, the following FIELD_PREP clears out that
+ * field and the user overridden value set in the DTS using
+ * "snps,quirk-frame-length-adjustment" is lost. Ensure to retain
+ * the user overridden value if the above calculation evaluates to 0.
+ */
+ if (fladj == 0)
+ fladj = FIELD_GET(DWC3_GFLADJ_REFCLK_FLADJ_MASK, dwc->fladj);
+
+ /*
* The documented 240MHz constant is scaled by 2 to get PLS1 as well.
*/
decr = 480000000 / rate;
--
2.7.4