From 45cf59ff70696a147e39034c6b8418cb687c9f84 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Sat, 26 Aug 2017 01:49:51 +0800 Subject: [PATCH] MLK-16273-1 usb: dwc3: add suspend clock setting interface Some dwc3 based USB3 IP may have a wrong default suspend clk setting, so add an interface to correct it by board setting. Acked-by: Peng Fan Signed-off-by: Li Jun (cherry picked from commit 240b636718313e03db505a713e66e3f893cb7727) (cherry picked from commit ac64f460533f734ac5b2659f8e8ba9fbdd56e539) --- drivers/usb/dwc3/core.c | 24 ++++++++++++++++++++++++ drivers/usb/dwc3/core.h | 2 ++ include/dwc3-uboot.h | 1 + 3 files changed, 27 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 56e2a046bf..d62737008f 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -396,6 +396,25 @@ static void dwc3_phy_setup(struct dwc3 *dwc) mdelay(100); } +void dwc3_set_suspend_clk(struct dwc3 *dwc) +{ + u32 reg; + + /* + * DWC3_GCTL.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. + */ + reg = dwc3_readl(dwc->regs, DWC3_GCTL); + reg &= ~(DWC3_GCTL_PWRDNSCALE(0x1fff)); + reg |= DWC3_GCTL_PWRDNSCALE(dwc->power_down_scale); + dwc3_writel(dwc->regs, DWC3_GCTL, reg); +} + /** * dwc3_core_init - Low-level initialization of DWC3 Core * @dwc: Pointer to our controller context structure @@ -444,6 +463,9 @@ static int dwc3_core_init(struct dwc3 *dwc) if (ret) goto err0; + if (dwc->power_down_scale) + dwc3_set_suspend_clk(dwc); + reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~DWC3_GCTL_SCALEDOWN_MASK; @@ -674,6 +696,8 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev) if (dwc3_dev->tx_de_emphasis) tx_de_emphasis = dwc3_dev->tx_de_emphasis; + dwc->power_down_scale = dwc3_dev->power_down_scale; + /* default to superspeed if no maximum_speed passed */ if (dwc->maximum_speed == USB_SPEED_UNKNOWN) dwc->maximum_speed = USB_SPEED_SUPER; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index cfe29884e7..388d960ee5 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -642,6 +642,7 @@ struct dwc3_scratchpad_array { * @dr_mode: requested mode of operation * @dcfg: saved contents of DCFG register * @gctl: saved contents of GCTL register + * @power_down_scale: 16KHz clock periods for suspend_clk * @isoch_delay: wValue from Set Isochronous Delay request; * @u2sel: parameter from Set SEL request. * @u2pel: parameter from Set SEL request. @@ -766,6 +767,7 @@ struct dwc3 { enum dwc3_ep0_state ep0state; enum dwc3_link_state link_state; + u16 power_down_scale; u16 isoch_delay; u16 u2sel; u16 u2pel; diff --git a/include/dwc3-uboot.h b/include/dwc3-uboot.h index 9941cc37a3..aeda1d669d 100644 --- a/include/dwc3-uboot.h +++ b/include/dwc3-uboot.h @@ -15,6 +15,7 @@ struct dwc3_device { unsigned long base; enum usb_dr_mode dr_mode; u32 maximum_speed; + u16 power_down_scale; unsigned tx_fifo_resize:1; unsigned has_lpm_erratum; u8 lpm_nyet_threshold; -- 2.17.1