mirror of
https://github.com/AsahiLinux/u-boot
synced 2025-02-17 22:49:02 +00:00
- DWC3 fixes / improvements
This commit is contained in:
commit
597e7b784d
4 changed files with 97 additions and 1 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue