[PATCH v2 4/5] usb: dwc3: Program GFLADJ
Marek Vasut
marex at denx.de
Tue Nov 8 02:40:12 CET 2022
From: Sean Anderson <sean.anderson at seco.com>
GUCTL.REFCLKPER can only account for clock frequencies with integer
periods. To address this, program REFCLK_FLADJ with the relative error
caused by period truncation. The formula given in the register reference
has been rearranged to allow calculation based on rate (instead of
period), and to allow for fixed-point arithmetic.
Additionally, calculate a value for 240MHZDECR. This configures a
simulated 240Mhz clock using a counter with one fractional bit (PLS1).
This register is programmed only for versions >= 2.50a, since this is
the check also used by commit db2be4e9e30c ("usb: dwc3: Add frame length
adjustment quirk").
[ marek: Ported from Linux kernel commit
596c87856e08d ("usb: dwc3: Program GFLADJ") ]
Reviewed-by: Sean Anderson <seanga2 at gmail.com>
Signed-off-by: Sean Anderson <sean.anderson at seco.com>
Signed-off-by: Marek Vasut <marex at denx.de> # Port from Linux
---
Cc: Angus Ainslie <angus at akkea.ca>
Cc: Bin Meng <bmeng.cn at gmail.com>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Kunihiko Hayashi <hayashi.kunihiko at socionext.com>
Cc: Michal Simek <michal.simek at xilinx.com>
Cc: Peng Fan <peng.fan at nxp.com>
Cc: Sean Anderson <sean.anderson at seco.com>
Cc: Stefano Babic <sbabic at denx.de>
---
V2: No change
---
drivers/usb/dwc3/core.c | 41 +++++++++++++++++++++++++++++++++++++++++
drivers/usb/dwc3/core.h | 3 +++
2 files changed, 44 insertions(+)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index cf66976a088..fcd062dc898 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -29,6 +29,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/bitfield.h>
+#include <linux/math64.h>
#include "core.h"
#include "gadget.h"
@@ -36,6 +37,8 @@
#include "linux-compat.h"
+#define NSEC_PER_SEC 1000000000L
+
static LIST_HEAD(dwc3_list);
/* -------------------------------------------------------------------------- */
@@ -127,6 +130,8 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj)
static void dwc3_ref_clk_period(struct dwc3 *dwc)
{
unsigned long period;
+ unsigned long fladj;
+ unsigned long decr;
unsigned long rate;
u32 reg;
@@ -137,6 +142,7 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc)
period = NSEC_PER_SEC / rate;
} else if (dwc->ref_clk_per) {
period = dwc->ref_clk_per;
+ rate = NSEC_PER_SEC / period;
} else {
return;
}
@@ -145,6 +151,41 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc)
reg &= ~DWC3_GUCTL_REFCLKPER_MASK;
reg |= FIELD_PREP(DWC3_GUCTL_REFCLKPER_MASK, period);
dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
+
+ if (dwc->revision <= DWC3_REVISION_250A)
+ return;
+
+ /*
+ * The calculation below is
+ *
+ * 125000 * (NSEC_PER_SEC / (rate * period) - 1)
+ *
+ * but rearranged for fixed-point arithmetic. The division must be
+ * 64-bit because 125000 * NSEC_PER_SEC doesn't fit in 32 bits (and
+ * neither does rate * period).
+ *
+ * Note that rate * period ~= NSEC_PER_SECOND, minus the number of
+ * nanoseconds of error caused by the truncation which happened during
+ * the division when calculating rate or period (whichever one was
+ * derived from the other). We first calculate the relative error, then
+ * scale it to units of 8 ppm.
+ */
+ fladj = div64_u64(125000ULL * NSEC_PER_SEC, (u64)rate * period);
+ fladj -= 125000;
+
+ /*
+ * The documented 240MHz constant is scaled by 2 to get PLS1 as well.
+ */
+ decr = 480000000 / rate;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
+ reg &= ~DWC3_GFLADJ_REFCLK_FLADJ_MASK
+ & ~DWC3_GFLADJ_240MHZDECR
+ & ~DWC3_GFLADJ_240MHZDECR_PLS1;
+ reg |= FIELD_PREP(DWC3_GFLADJ_REFCLK_FLADJ_MASK, fladj)
+ | FIELD_PREP(DWC3_GFLADJ_240MHZDECR, decr >> 1)
+ | FIELD_PREP(DWC3_GFLADJ_240MHZDECR_PLS1, decr & 1);
+ dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
}
/**
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index b4a7d9e52bc..532746dd88d 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -248,6 +248,9 @@
/* Global Frame Length Adjustment Register */
#define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7)
#define DWC3_GFLADJ_30MHZ_MASK 0x3f
+#define DWC3_GFLADJ_REFCLK_FLADJ_MASK GENMASK(21, 8)
+#define DWC3_GFLADJ_240MHZDECR GENMASK(30, 24)
+#define DWC3_GFLADJ_240MHZDECR_PLS1 BIT(31)
/* Global User Control Register*/
#define DWC3_GUCTL_REFCLKPER_MASK 0xffc00000
--
2.35.1
More information about the U-Boot
mailing list