On 01/02/2024 20:52, Andrew Davis wrote: > On 2/1/24 6:12 AM, Roger Quadros wrote: >> All AM62 devices have Errata i2409 [1] due to which >> USB2 PHY may lock up due to short suspend. >> >> Workaround involves setting bit 5 and 4 PLL_REG12 >> in PHY2 register space after USB controller is brought >> out of LPSC reset but before controller initialization. >> >> Handle this workaround. >> >> [1] - https://www.ti.com/lit/er/sprz487d/sprz487d.pdf >> >> Signed-off-by: Roger Quadros <rogerq@xxxxxxxxxx> >> --- >> drivers/usb/dwc3/dwc3-am62.c | 29 +++++++++++++++++++++++++++++ >> 1 file changed, 29 insertions(+) >> >> diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c >> index af1ce934e7fb..35d7a2fb128e 100644 >> --- a/drivers/usb/dwc3/dwc3-am62.c >> +++ b/drivers/usb/dwc3/dwc3-am62.c >> @@ -101,11 +101,17 @@ >> #define PHY_CORE_VOLTAGE_MASK BIT(31) >> #define PHY_PLL_REFCLK_MASK GENMASK(3, 0) >> +/* USB PHY2 register offsets */ >> +#define USB_PHY_PLL_REG12 0x130 >> +#define USB_PHY_PLL_LDO_REF_EN BIT(5) >> +#define USB_PHY_PLL_LDO_REF_EN_EN BIT(4) >> + >> #define DWC3_AM62_AUTOSUSPEND_DELAY 100 >> struct dwc3_am62 { >> struct device *dev; >> void __iomem *usbss; >> + void __iomem *phy; > > Why do you need this in the driver data? You only use it in probe(), > just have it be a local variable. OK. > >> struct clk *usb2_refclk; >> int rate_code; >> struct regmap *syscon; >> @@ -140,6 +146,16 @@ static inline void dwc3_ti_writel(struct dwc3_am62 *am62, u32 offset, u32 value) >> writel(value, (am62->usbss) + offset); >> } >> +static inline u32 dwc3_ti_phy_readl(struct dwc3_am62 *am62, u32 offset) >> +{ > > Do you really need these one line functions? They add more code than > they save and just hide a single deference? Just do that directly. Sure. Thanks. > > Andrew > >> + return readl((am62->phy) + offset); >> +} >> + >> +static inline void dwc3_ti_phy_writel(struct dwc3_am62 *am62, u32 offset, u32 value) >> +{ >> + writel(value, (am62->phy) + offset); >> +} >> + >> static int phy_syscon_pll_refclk(struct dwc3_am62 *am62) >> { >> struct device *dev = am62->dev; >> @@ -201,6 +217,12 @@ static int dwc3_ti_probe(struct platform_device *pdev) >> return PTR_ERR(am62->usbss); >> } >> + am62->phy = devm_platform_ioremap_resource(pdev, 1); >> + if (IS_ERR(am62->phy)) { >> + dev_err(dev, "can't map PHY IOMEM resource. Won't apply i2409 fix.\n"); >> + am62->phy = NULL; >> + } >> + >> am62->usb2_refclk = devm_clk_get(dev, "ref"); >> if (IS_ERR(am62->usb2_refclk)) { >> dev_err(dev, "can't get usb2_refclk\n"); >> @@ -227,6 +249,13 @@ static int dwc3_ti_probe(struct platform_device *pdev) >> if (ret) >> return ret; >> + /* Workaround Errata i2409 */ >> + if (am62->phy) { >> + reg = dwc3_ti_phy_readl(am62, USB_PHY_PLL_REG12); >> + reg |= USB_PHY_PLL_LDO_REF_EN | USB_PHY_PLL_LDO_REF_EN_EN; >> + dwc3_ti_phy_writel(am62, USB_PHY_PLL_REG12, reg); >> + } >> + >> /* VBUS divider select */ >> am62->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider"); >> reg = dwc3_ti_readl(am62, USBSS_PHY_CONFIG); -- cheers, -roger