aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2022-11-28 09:35:02 -0500
committerTom Rini <trini@konsulko.com>2022-11-28 09:35:02 -0500
commit597e7b784dbfec29fd8d6c450bc9a3a607c4feae (patch)
tree2eef180252fa91862c30acaf18b0b39339d1bedc
parent27c415ae8b743710e412ef408b52894af68141c6 (diff)
parentdb5bace4f6cb37251a5863efe4c0c1547d1334bd (diff)
downloadu-boot-WIP/28Nov2022.zip
u-boot-WIP/28Nov2022.tar.gz
u-boot-WIP/28Nov2022.tar.bz2
Merge https://source.denx.de/u-boot/custodians/u-boot-usbWIP/28Nov2022
- DWC3 fixes / improvements
-rw-r--r--drivers/usb/dwc3/core.c75
-rw-r--r--drivers/usb/dwc3/core.h12
-rw-r--r--drivers/usb/dwc3/dwc3-generic.c9
-rw-r--r--drivers/usb/host/usb-uclass.c2
4 files changed, 97 insertions, 1 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index b592a48..49f6a19 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -14,6 +14,7 @@
*/
#include <common.h>
+#include <clk.h>
#include <cpu_func.h>
#include <malloc.h>
#include <dwc3-uboot.h>
@@ -28,6 +29,8 @@
#include <generic-phy.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/bitfield.h>
+#include <linux/math64.h>
#include "core.h"
#include "gadget.h"
@@ -35,6 +38,8 @@
#include "linux-compat.h"
+#define NSEC_PER_SEC 1000000000L
+
static LIST_HEAD(dwc3_list);
/* -------------------------------------------------------------------------- */
@@ -115,6 +120,73 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj)
}
/**
+ * dwc3_ref_clk_period - Reference clock period configuration
+ * Default reference clock period depends on hardware
+ * configuration. For systems with reference clock that differs
+ * from the default, this will set clock period in DWC3_GUCTL
+ * register.
+ * @dwc: Pointer to our controller context structure
+ * @ref_clk_per: reference clock period in ns
+ */
+static void dwc3_ref_clk_period(struct dwc3 *dwc)
+{
+ unsigned long period;
+ unsigned long fladj;
+ unsigned long decr;
+ unsigned long rate;
+ u32 reg;
+
+ if (dwc->ref_clk) {
+ rate = clk_get_rate(dwc->ref_clk);
+ if (!rate)
+ return;
+ period = NSEC_PER_SEC / rate;
+ } else {
+ return;
+ }
+
+ reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
+ 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);
+}
+
+/**
* dwc3_free_one_event_buffer - Frees one event buffer
* @dwc: Pointer to our controller context structure
* @evt: Pointer to event buffer to be freed
@@ -640,6 +712,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
/* Adjust Frame Length */
dwc3_frame_length_adjustment(dwc, dwc->fladj);
+ /* Adjust Reference Clock Period */
+ dwc3_ref_clk_period(dwc);
+
dwc3_set_incr_burst_type(dwc);
return 0;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index d7cce3a..532746d 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -248,6 +248,13 @@
/* 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
+#define DWC3_GUCTL_REFCLKPER_SEL 22
/* Device Configuration Register */
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
@@ -668,8 +675,10 @@ struct dwc3_scratchpad_array {
* @event_buffer_list: a list of event buffers
* @gadget: device side representation of the peripheral controller
* @gadget_driver: pointer to the gadget driver
+ * @ref_clk: reference clock
* @regs: base address for our registers
* @regs_size: address space size
+ * @ref_clk_per: reference clock period configuration
* @nr_scratch: number of scratch buffers
* @num_event_buffers: calculated number of event buffers
* @u1u2: only used on revisions <1.83a for workaround
@@ -766,6 +775,8 @@ struct dwc3 {
struct usb_gadget gadget;
struct usb_gadget_driver *gadget_driver;
+ struct clk *ref_clk;
+
void __iomem *regs;
size_t regs_size;
@@ -829,6 +840,7 @@ struct dwc3 {
u8 lpm_nyet_threshold;
u8 hird_threshold;
u32 fladj;
+ u32 ref_clk_per;
u8 incrx_mode;
u32 incrx_size;
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index 466b25a..7896671 100644
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -59,12 +59,21 @@ static int dwc3_generic_probe(struct udevice *dev,
struct dwc3_generic_plat *plat = dev_get_plat(dev);
struct dwc3 *dwc3 = &priv->dwc3;
struct dwc3_glue_data *glue = dev_get_plat(dev->parent);
+ int __maybe_unused index;
+ ofnode __maybe_unused node;
dwc3->dev = dev;
dwc3->maximum_speed = plat->maximum_speed;
dwc3->dr_mode = plat->dr_mode;
#if CONFIG_IS_ENABLED(OF_CONTROL)
dwc3_of_parse(dwc3);
+
+ node = dev_ofnode(dev->parent);
+ index = ofnode_stringlist_search(node, "clock-names", "ref");
+ if (index < 0)
+ index = ofnode_stringlist_search(node, "clock-names", "ref_clk");
+ if (index >= 0)
+ dwc3->ref_clk = &glue->clks.clks[index];
#endif
/*
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
index 27e2fc6..060f344 100644
--- a/drivers/usb/host/usb-uclass.c
+++ b/drivers/usb/host/usb-uclass.c
@@ -557,7 +557,7 @@ static int usb_find_and_bind_driver(struct udevice *parent,
struct usb_driver_entry *start, *entry;
int n_ents;
int ret;
- char name[30], *str;
+ char name[34], *str;
ofnode node = usb_get_ofnode(parent, port);
*devp = NULL;