staging: dwc2: add check on dwc2_core_reset return

If the GRSTCTL_CSFTRST self-clearing bit never comes
back to 0 for any reason, the controller is under reset
state and cannot be used. It's preferable to abort
initialization in such case.

Signed-off-by: Julien Delacou <julien.delacou@st.com>
Acked-by: Paul Zimmerman <paulz@synopsys.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Julien DELACOU 2013-11-20 17:29:49 +01:00 committed by Greg Kroah-Hartman
parent b34085fdc2
commit beb7e592bc

View File

@ -114,7 +114,7 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
* Do core a soft reset of the core. Be careful with this because it * Do core a soft reset of the core. Be careful with this because it
* resets all the internal state machines of the core. * resets all the internal state machines of the core.
*/ */
static void dwc2_core_reset(struct dwc2_hsotg *hsotg) static int dwc2_core_reset(struct dwc2_hsotg *hsotg)
{ {
u32 greset; u32 greset;
int count = 0; int count = 0;
@ -129,7 +129,7 @@ static void dwc2_core_reset(struct dwc2_hsotg *hsotg)
dev_warn(hsotg->dev, dev_warn(hsotg->dev,
"%s() HANG! AHB Idle GRSTCTL=%0x\n", "%s() HANG! AHB Idle GRSTCTL=%0x\n",
__func__, greset); __func__, greset);
return; return -EBUSY;
} }
} while (!(greset & GRSTCTL_AHBIDLE)); } while (!(greset & GRSTCTL_AHBIDLE));
@ -144,7 +144,7 @@ static void dwc2_core_reset(struct dwc2_hsotg *hsotg)
dev_warn(hsotg->dev, dev_warn(hsotg->dev,
"%s() HANG! Soft Reset GRSTCTL=%0x\n", "%s() HANG! Soft Reset GRSTCTL=%0x\n",
__func__, greset); __func__, greset);
break; return -EBUSY;
} }
} while (greset & GRSTCTL_CSFTRST); } while (greset & GRSTCTL_CSFTRST);
@ -153,11 +153,14 @@ static void dwc2_core_reset(struct dwc2_hsotg *hsotg)
* not stay in host mode after a connector ID change! * not stay in host mode after a connector ID change!
*/ */
usleep_range(150000, 200000); usleep_range(150000, 200000);
return 0;
} }
static void dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
{ {
u32 usbcfg, i2cctl; u32 usbcfg, i2cctl;
int retval = 0;
/* /*
* core_init() is now called on every switch so only call the * core_init() is now called on every switch so only call the
@ -170,7 +173,12 @@ static void dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
writel(usbcfg, hsotg->regs + GUSBCFG); writel(usbcfg, hsotg->regs + GUSBCFG);
/* Reset after a PHY select */ /* Reset after a PHY select */
dwc2_core_reset(hsotg); retval = dwc2_core_reset(hsotg);
if (retval) {
dev_err(hsotg->dev, "%s() Reset failed, aborting",
__func__);
return retval;
}
} }
/* /*
@ -198,14 +206,17 @@ static void dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
i2cctl |= GI2CCTL_I2CEN; i2cctl |= GI2CCTL_I2CEN;
writel(i2cctl, hsotg->regs + GI2CCTL); writel(i2cctl, hsotg->regs + GI2CCTL);
} }
return retval;
} }
static void dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
{ {
u32 usbcfg; u32 usbcfg;
int retval = 0;
if (!select_phy) if (!select_phy)
return; return -ENODEV;
usbcfg = readl(hsotg->regs + GUSBCFG); usbcfg = readl(hsotg->regs + GUSBCFG);
@ -238,20 +249,32 @@ static void dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
writel(usbcfg, hsotg->regs + GUSBCFG); writel(usbcfg, hsotg->regs + GUSBCFG);
/* Reset after setting the PHY parameters */ /* Reset after setting the PHY parameters */
dwc2_core_reset(hsotg); retval = dwc2_core_reset(hsotg);
if (retval) {
dev_err(hsotg->dev, "%s() Reset failed, aborting",
__func__);
return retval;
}
return retval;
} }
static void dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) static int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
{ {
u32 usbcfg; u32 usbcfg;
int retval = 0;
if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL && if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL &&
hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) { hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
/* If FS mode with FS PHY */ /* If FS mode with FS PHY */
dwc2_fs_phy_init(hsotg, select_phy); retval = dwc2_fs_phy_init(hsotg, select_phy);
if (retval)
return retval;
} else { } else {
/* High speed PHY */ /* High speed PHY */
dwc2_hs_phy_init(hsotg, select_phy); retval = dwc2_hs_phy_init(hsotg, select_phy);
if (retval)
return retval;
} }
if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
@ -268,6 +291,8 @@ static void dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M; usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M;
writel(usbcfg, hsotg->regs + GUSBCFG); writel(usbcfg, hsotg->regs + GUSBCFG);
} }
return retval;
} }
static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg) static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
@ -382,12 +407,19 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
writel(usbcfg, hsotg->regs + GUSBCFG); writel(usbcfg, hsotg->regs + GUSBCFG);
/* Reset the Controller */ /* Reset the Controller */
dwc2_core_reset(hsotg); retval = dwc2_core_reset(hsotg);
if (retval) {
dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
__func__);
return retval;
}
/* /*
* This needs to happen in FS mode before any other programming occurs * This needs to happen in FS mode before any other programming occurs
*/ */
dwc2_phy_init(hsotg, select_phy); retval = dwc2_phy_init(hsotg, select_phy);
if (retval)
return retval;
/* Program the GAHBCFG Register */ /* Program the GAHBCFG Register */
retval = dwc2_gahbcfg_init(hsotg); retval = dwc2_gahbcfg_init(hsotg);