diff options
author | Tom Rini <trini@konsulko.com> | 2022-11-28 09:35:02 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2022-11-28 09:35:02 -0500 |
commit | 597e7b784dbfec29fd8d6c450bc9a3a607c4feae (patch) | |
tree | 2eef180252fa91862c30acaf18b0b39339d1bedc | |
parent | 27c415ae8b743710e412ef408b52894af68141c6 (diff) | |
parent | db5bace4f6cb37251a5863efe4c0c1547d1334bd (diff) | |
download | u-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.c | 75 | ||||
-rw-r--r-- | drivers/usb/dwc3/core.h | 12 | ||||
-rw-r--r-- | drivers/usb/dwc3/dwc3-generic.c | 9 | ||||
-rw-r--r-- | drivers/usb/host/usb-uclass.c | 2 |
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; |