On Aug 22, 2012, at 5:17 AM, Shengzhou Liu wrote: > when missing USB PHY clock, kernel booting up will hang during USB > initialization. We should check USBGP[PHY_CLK_VALID] bit to avoid > CPU hanging in this case. > > Signed-off-by: Shengzhou Liu <Shengzhou.Liu@xxxxxxxxxxxxx> > --- > v2 changes: use spin_event_timeout() instead. > > drivers/usb/host/ehci-fsl.c | 58 +++++++++++++++++++++++++++++------------- > drivers/usb/host/ehci-fsl.h | 1 + > include/linux/fsl_devices.h | 1 + > 3 files changed, 42 insertions(+), 18 deletions(-) Greg, Any issues picking this fix up for v3.6 inclusion? - k > > diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c > index b7451b2..11ff4b4 100644 > --- a/drivers/usb/host/ehci-fsl.c > +++ b/drivers/usb/host/ehci-fsl.c > @@ -210,11 +210,11 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, > usb_put_hcd(hcd); > } > > -static void ehci_fsl_setup_phy(struct usb_hcd *hcd, > +static int ehci_fsl_setup_phy(struct usb_hcd *hcd, > enum fsl_usb2_phy_modes phy_mode, > unsigned int port_offset) > { > - u32 portsc, temp; > + u32 portsc; > struct ehci_hcd *ehci = hcd_to_ehci(hcd); > void __iomem *non_ehci = hcd->regs; > struct device *dev = hcd->self.controller; > @@ -232,9 +232,15 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd, > case FSL_USB2_PHY_ULPI: > if (pdata->controller_ver) { > /* controller version 1.6 or above */ > - temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); > - out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | > - USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL); > + setbits32(non_ehci + FSL_SOC_USB_CTRL, > + ULPI_PHY_CLK_SEL); > + /* > + * Due to controller issue of PHY_CLK_VALID in ULPI > + * mode, we set USB_CTRL_USB_EN before checking > + * PHY_CLK_VALID, otherwise PHY_CLK_VALID doesn't work. > + */ > + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, > + UTMI_PHY_EN, USB_CTRL_USB_EN); > } > portsc |= PORT_PTS_ULPI; > break; > @@ -247,9 +253,7 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd, > case FSL_USB2_PHY_UTMI: > if (pdata->controller_ver) { > /* controller version 1.6 or above */ > - temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); > - out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | > - UTMI_PHY_EN | USB_CTRL_USB_EN); > + setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); > mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to > become stable - 10ms*/ > } > @@ -262,23 +266,34 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd, > case FSL_USB2_PHY_NONE: > break; > } > + > + if ((pdata->controller_ver) && ((phy_mode == FSL_USB2_PHY_ULPI) || > + (phy_mode == FSL_USB2_PHY_UTMI))) { > + /* check PHY_CLK_VALID to get phy clk valid */ > + if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & > + PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) { > + printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n"); > + return -EINVAL; > + } > + } > + > ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); > + > + if (phy_mode != FSL_USB2_PHY_ULPI) > + setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN); > + > + return 0; > } > > -static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) > +static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) > { > struct usb_hcd *hcd = ehci_to_hcd(ehci); > struct fsl_usb2_platform_data *pdata; > void __iomem *non_ehci = hcd->regs; > - u32 temp; > > pdata = hcd->self.controller->platform_data; > > - /* Enable PHY interface in the control reg. */ > if (pdata->have_sysif_regs) { > - temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); > - out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004); > - > /* > * Turn on cache snooping hardware, since some PowerPC platforms > * wholly rely on hardware to deal with cache coherent > @@ -293,7 +308,8 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) > > if ((pdata->operating_mode == FSL_USB2_DR_HOST) || > (pdata->operating_mode == FSL_USB2_DR_OTG)) > - ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0); > + if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0)) > + return -EINVAL; > > if (pdata->operating_mode == FSL_USB2_MPH_HOST) { > unsigned int chip, rev, svr; > @@ -307,9 +323,12 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) > ehci->has_fsl_port_bug = 1; > > if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) > - ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0); > + if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0)) > + return -EINVAL; > + > if (pdata->port_enables & FSL_USB2_PORT1_ENABLED) > - ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1); > + if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1)) > + return -EINVAL; > } > > if (pdata->have_sysif_regs) { > @@ -322,12 +341,15 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) > #endif > out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); > } > + > + return 0; > } > > /* called after powerup, by probe or system-pm "wakeup" */ > static int ehci_fsl_reinit(struct ehci_hcd *ehci) > { > - ehci_fsl_usb_setup(ehci); > + if (ehci_fsl_usb_setup(ehci)) > + return -EINVAL; > ehci_port_power(ehci, 0); > > return 0; > diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h > index 8840368..dbd292e 100644 > --- a/drivers/usb/host/ehci-fsl.h > +++ b/drivers/usb/host/ehci-fsl.h > @@ -61,4 +61,5 @@ > #define PLL_RESET (1<<8) > #define UTMI_PHY_EN (1<<9) > #define ULPI_PHY_CLK_SEL (1<<10) > +#define PHY_CLK_VALID (1<<17) > #endif /* _EHCI_FSL_H */ > diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h > index 15be561..ccfc4bb 100644 > --- a/include/linux/fsl_devices.h > +++ b/include/linux/fsl_devices.h > @@ -19,6 +19,7 @@ > > #define FSL_UTMI_PHY_DLY 10 /*As per P1010RM, delay for UTMI > PHY CLK to become stable - 10ms*/ > +#define FSL_USB_PHY_CLK_TIMEOUT 1000 /* uSec */ > #define FSL_USB_VER_OLD 0 > #define FSL_USB_VER_1_6 1 > #define FSL_USB_VER_2_2 2 > -- > 1.6.4 > -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html