From 2d18a97422dfd483c3dfd15ed953c84af7256fb0 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Tue, 7 Jun 2022 10:20:04 +0800 Subject: [PATCH] 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 Signed-off-by: Li Jun Link: https://lore.kernel.org/r/1654568404-3461-1-git-send-email-jun.li@nxp.com Signed-off-by: Greg Kroah-Hartman 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 --- drivers/usb/dwc3/core.c | 41 +++++++++++++++++++++++++++++++++++++++++ drivers/usb/dwc3/core.h | 1 + 2 files changed, 42 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a0ec7824d442..c81bbef9c7fd 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -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); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 241bd842f8ef..32a90b147b8b 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -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)