Skip to content

Commit

Permalink
powerpc/usb: fix bug of CPU hang when missing USB PHY clock
Browse files Browse the repository at this point in the history
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@freescale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Shengzhou Liu authored and Greg Kroah-Hartman committed Sep 5, 2012
1 parent 6799047 commit 3735ba8
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 18 deletions.
58 changes: 40 additions & 18 deletions drivers/usb/host/ehci-fsl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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*/
}
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions drivers/usb/host/ehci-fsl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
1 change: 1 addition & 0 deletions include/linux/fsl_devices.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 3735ba8

Please sign in to comment.