From 55a95f8f58cf5c884edfe8714bf681cd17ef7242 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 26 Nov 2022 13:57:53 +0100 Subject: usb: Expand buffer size in usb_find_and_bind_driver() The "generic_bus_%x_dev_%x" string which is printed into this buffer can be up to 34 characters long ("generic_bus_12345678_dev_12345678"). The buffer would be clipped by snprintf() if both %x were at maximum range. Make sure the buffer is long enough to cover such possibility. Signed-off-by: Marek Vasut Reviewed-by: Simon Glass --- drivers/usb/host/usb-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 27e2fc6fcd3..060f3441df0 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; -- cgit v1.3.1 From 8ae84e64530e81f23066d86417b9225388ba96ae Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 27 Nov 2022 15:31:52 +0100 Subject: usb: dwc3: Cache ref_clk pointer in struct dwc3 Cache ref_clk clock pointer in struct dwc3 . This is a preparatory patch for subsequent backports from Linux kernel which configure GFLADJ register content based on the ref_clk rate and therefore need access to the ref_clk pointer. It is possible to extract the clock pointer from existing clk_bulk list of already claimed clock, no need to call clk_get*() again. Reviewed-by: Sean Anderson Signed-off-by: Marek Vasut --- drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/dwc3-generic.c | 9 +++++++++ 2 files changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index d7cce3a861a..0d20fe285b0 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -668,6 +668,7 @@ 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 * @nr_scratch: number of scratch buffers @@ -766,6 +767,8 @@ struct dwc3 { struct usb_gadget gadget; struct usb_gadget_driver *gadget_driver; + struct clk *ref_clk; + void __iomem *regs; size_t regs_size; diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 466b25a0c38..78966718d01 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 /* -- cgit v1.3.1 From 57548e8bc7cb6eb1c1a0206579c2a84737a70650 Mon Sep 17 00:00:00 2001 From: Balaji Prakash J Date: Sun, 27 Nov 2022 15:31:53 +0100 Subject: usb: dwc3: reference clock period configuration Set reference clock period when it differs from dwc3 default hardware set. We could calculate clock period based on reference clock frequency. But this information is not always available. This is the case of PCI bus attached USB host. For that reason we use a custom property. Tested (USB2 only) on IPQ6010 SoC based board with 24 MHz reference clock while hardware default is 19.2 MHz. [ baruch: rewrite commit message; drop GFLADJ code; remove 'quirk-' from property name; mention tested hardware ] [ marek: Ported from Linux kernel commit 7bee318838890 ("usb: dwc3: reference clock period configuration") ] Reviewed-by: Sean Anderson Signed-off-by: Balaji Prakash J Signed-off-by: Baruch Siach Signed-off-by: Marek Vasut # Port from Linux --- drivers/usb/dwc3/core.c | 27 +++++++++++++++++++++++++++ drivers/usb/dwc3/core.h | 6 ++++++ 2 files changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index b592a487e00..300450100c9 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "core.h" #include "gadget.h" @@ -114,6 +115,28 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj) dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); } +/** + * 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) +{ + u32 reg; + + if (dwc->ref_clk_per == 0) + return; + + reg = dwc3_readl(dwc->regs, DWC3_GUCTL); + reg &= ~DWC3_GUCTL_REFCLKPER_MASK; + reg |= FIELD_PREP(DWC3_GUCTL_REFCLKPER_MASK, dwc->ref_clk_per); + dwc3_writel(dwc->regs, DWC3_GUCTL, reg); +} + /** * dwc3_free_one_event_buffer - Frees one event buffer * @dwc: Pointer to our controller context structure @@ -640,6 +663,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; @@ -1043,6 +1069,7 @@ void dwc3_of_parse(struct dwc3 *dwc) | (dwc->is_utmi_l1_suspend << 4); dev_read_u32(dev, "snps,quirk-frame-length-adjustment", &dwc->fladj); + dev_read_u32(dev, "snps,ref-clock-period-ns", &dwc->ref_clk_per); /* * Handle property "snps,incr-burst-type-adjustment". diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 0d20fe285b0..b4a7d9e52bc 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -249,6 +249,10 @@ #define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7) #define DWC3_GFLADJ_30MHZ_MASK 0x3f +/* 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) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) @@ -671,6 +675,7 @@ struct dwc3_scratchpad_array { * @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 @@ -832,6 +837,7 @@ struct dwc3 { u8 lpm_nyet_threshold; u8 hird_threshold; u32 fladj; + u32 ref_clk_per; u8 incrx_mode; u32 incrx_size; -- cgit v1.3.1 From 6bae0eb5b8bd7f7f87c7bf106acea869da187b66 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Sun, 27 Nov 2022 15:31:54 +0100 Subject: usb: dwc3: Calculate REFCLKPER based on reference clock Instead of using a special property to determine the reference clock period, use the rate of the reference clock. When we have a legacy snps,ref-clock-period-ns property and no reference clock, use it instead. Fractional clocks are not currently supported, and will be dealt with in the next commit. [ marek: Ported from Linux kernel commit 5114c3ee24875 ("usb: dwc3: Calculate REFCLKPER based on reference clock") ] Reviewed-by: Sean Anderson Signed-off-by: Sean Anderson Signed-off-by: Marek Vasut # Port from Linux --- drivers/usb/dwc3/core.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 300450100c9..ed5d0d16f78 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -14,6 +14,7 @@ */ #include +#include #include #include #include @@ -126,14 +127,24 @@ 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 rate; u32 reg; - if (dwc->ref_clk_per == 0) + if (dwc->ref_clk) { + rate = clk_get_rate(dwc->ref_clk); + if (!rate) + return; + period = NSEC_PER_SEC / rate; + } else if (dwc->ref_clk_per) { + period = dwc->ref_clk_per; + } else { return; + } reg = dwc3_readl(dwc->regs, DWC3_GUCTL); reg &= ~DWC3_GUCTL_REFCLKPER_MASK; - reg |= FIELD_PREP(DWC3_GUCTL_REFCLKPER_MASK, dwc->ref_clk_per); + reg |= FIELD_PREP(DWC3_GUCTL_REFCLKPER_MASK, period); dwc3_writel(dwc->regs, DWC3_GUCTL, reg); } -- cgit v1.3.1 From c55ac51a550c8d2f8485abe94cb80c15b81d08fa Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Sun, 27 Nov 2022 15:31:55 +0100 Subject: usb: dwc3: Program GFLADJ 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 Signed-off-by: Sean Anderson Signed-off-by: Marek Vasut # Port from Linux --- drivers/usb/dwc3/core.c | 41 +++++++++++++++++++++++++++++++++++++++++ drivers/usb/dwc3/core.h | 3 +++ 2 files changed, 44 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ed5d0d16f78..6e0876d2c45 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "core.h" #include "gadget.h" @@ -37,6 +38,8 @@ #include "linux-compat.h" +#define NSEC_PER_SEC 1000000000L + static LIST_HEAD(dwc3_list); /* -------------------------------------------------------------------------- */ @@ -128,6 +131,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; @@ -138,6 +143,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; } @@ -146,6 +152,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 -- cgit v1.3.1 From db5bace4f6cb37251a5863efe4c0c1547d1334bd Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 27 Nov 2022 15:31:56 +0100 Subject: usb: dwc3: Drop support for "snps, ref-clock-period-ns" DT property Drop support for quickly deprecated DT property "snps,ref-clock-period-ns" to prevent its proliferation. Reviewed-by: Sean Anderson Signed-off-by: Marek Vasut --- drivers/usb/dwc3/core.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 6e0876d2c45..49f6a1900b0 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -141,9 +141,6 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc) if (!rate) return; period = NSEC_PER_SEC / rate; - } else if (dwc->ref_clk_per) { - period = dwc->ref_clk_per; - rate = NSEC_PER_SEC / period; } else { return; } @@ -1121,7 +1118,6 @@ void dwc3_of_parse(struct dwc3 *dwc) | (dwc->is_utmi_l1_suspend << 4); dev_read_u32(dev, "snps,quirk-frame-length-adjustment", &dwc->fladj); - dev_read_u32(dev, "snps,ref-clock-period-ns", &dwc->ref_clk_per); /* * Handle property "snps,incr-burst-type-adjustment". -- cgit v1.3.1