- DWC3 fixes / improvements
This commit is contained in:
Tom Rini 2022-11-28 09:35:02 -05:00
commit 597e7b784d
4 changed files with 97 additions and 1 deletions

View file

@ -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);
/* -------------------------------------------------------------------------- */
@ -114,6 +119,73 @@ 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)
{
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
@ -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;

View file

@ -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;

View file

@ -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
/*

View file

@ -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;