BACKPORT: FROMGIT: usb: dwc3: add power down scale setting
Some SoC(e.g NXP imx8MQ) may have a wrong default power down scale setting so need init it to be the correct value, the power down scale setting description in DWC3 databook: Power Down Scale (PwrDnScale) The USB3 suspend_clk input replaces pipe3_rx_pclk as a clock source to a small part of the USB3 core that operates when the SS PHY is in its lowest power (P3) state, and therefore does not provide a clock. The Power Down Scale field specifies how many suspend_clk periods fit into a 16 kHz clock period. When performing the division, round up the remainder. For example, when using an 8-bit/16-bit/32-bit PHY and 25-MHz Suspend clock, Power Down Scale = 25000 kHz/16 kHz = 13'd1563 (rounder up) So use the suspend clock rate to calculate it. Reviewed-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Signed-off-by: Li Jun <jun.li@nxp.com> Link: https://lore.kernel.org/r/1654568404-3461-1-git-send-email-jun.li@nxp.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Bug: 234219431 (cherry picked from commit 3497b9a5c8c3d4efaa15ab542cc6a774b0e0a7c6 git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing) [jindong: rebase to v5.15, get "suspend" clk from of to replace nonexistent dwc->susp_clk] Change-Id: I0ce2c8041810d4add84b628fc8c3964063aacd5c Signed-off-by: Jindong Yue <jindong.yue@nxp.com>
This commit is contained in:
@@ -927,6 +927,44 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc)
|
||||
dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg);
|
||||
}
|
||||
|
||||
static void dwc3_set_power_down_clk_scale(struct dwc3 *dwc)
|
||||
{
|
||||
struct device *dev = dwc->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct clk *suspend_clk;
|
||||
u32 scale;
|
||||
u32 reg;
|
||||
|
||||
if (dwc->num_clks == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* The power down scale field specifies how many suspend_clk
|
||||
* periods fit into a 16KHz clock period. When performing
|
||||
* the division, round up the remainder.
|
||||
*
|
||||
* The power down scale value is calculated using the fastest
|
||||
* frequency of the suspend_clk. If it isn't fixed (but within
|
||||
* the accuracy requirement), the driver may not know the max
|
||||
* rate of the suspend_clk, so only update the power down scale
|
||||
* if the default is less than the calculated value from
|
||||
* clk_get_rate() or if the default is questionably high
|
||||
* (3x or more) to be within the requirement.
|
||||
*/
|
||||
suspend_clk = of_clk_get_by_name(node, "suspend");
|
||||
if (IS_ERR(suspend_clk))
|
||||
return;
|
||||
|
||||
scale = DIV_ROUND_UP(clk_get_rate(suspend_clk), 16000);
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
if ((reg & DWC3_GCTL_PWRDNSCALE_MASK) < DWC3_GCTL_PWRDNSCALE(scale) ||
|
||||
(reg & DWC3_GCTL_PWRDNSCALE_MASK) > DWC3_GCTL_PWRDNSCALE(scale*3)) {
|
||||
reg &= ~(DWC3_GCTL_PWRDNSCALE_MASK);
|
||||
reg |= DWC3_GCTL_PWRDNSCALE(scale);
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_core_init - Low-level initialization of DWC3 Core
|
||||
* @dwc: Pointer to our controller context structure
|
||||
@@ -1003,6 +1041,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
/* Set power down scale of suspend_clk */
|
||||
dwc3_set_power_down_clk_scale(dwc);
|
||||
|
||||
/* Adjust Frame Length */
|
||||
dwc3_frame_length_adjustment(dwc);
|
||||
|
||||
|
||||
@@ -230,6 +230,7 @@
|
||||
|
||||
/* Global Configuration Register */
|
||||
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
|
||||
#define DWC3_GCTL_PWRDNSCALE_MASK DWC3_GCTL_PWRDNSCALE(0x1fff)
|
||||
#define DWC3_GCTL_U2RSTECN BIT(16)
|
||||
#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6)
|
||||
#define DWC3_GCTL_CLK_BUS (0)
|
||||
|
||||
Reference in New Issue
Block a user