Commit 3735ba8d authored by Shengzhou Liu's avatar Shengzhou Liu Committed by Greg Kroah-Hartman

powerpc/usb: fix bug of CPU hang when missing USB PHY clock

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: default avatarShengzhou Liu <Shengzhou.Liu@freescale.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 67990472
...@@ -210,11 +210,11 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, ...@@ -210,11 +210,11 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
usb_put_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, enum fsl_usb2_phy_modes phy_mode,
unsigned int port_offset) unsigned int port_offset)
{ {
u32 portsc, temp; u32 portsc;
struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_hcd *ehci = hcd_to_ehci(hcd);
void __iomem *non_ehci = hcd->regs; void __iomem *non_ehci = hcd->regs;
struct device *dev = hcd->self.controller; struct device *dev = hcd->self.controller;
...@@ -232,9 +232,15 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd, ...@@ -232,9 +232,15 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
case FSL_USB2_PHY_ULPI: case FSL_USB2_PHY_ULPI:
if (pdata->controller_ver) { if (pdata->controller_ver) {
/* controller version 1.6 or above */ /* controller version 1.6 or above */
temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); setbits32(non_ehci + FSL_SOC_USB_CTRL,
out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | ULPI_PHY_CLK_SEL);
USB_CTRL_USB_EN | 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; portsc |= PORT_PTS_ULPI;
break; break;
...@@ -247,9 +253,7 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd, ...@@ -247,9 +253,7 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
case FSL_USB2_PHY_UTMI: case FSL_USB2_PHY_UTMI:
if (pdata->controller_ver) { if (pdata->controller_ver) {
/* controller version 1.6 or above */ /* controller version 1.6 or above */
temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN);
out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
UTMI_PHY_EN | USB_CTRL_USB_EN);
mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to
become stable - 10ms*/ become stable - 10ms*/
} }
...@@ -262,23 +266,34 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd, ...@@ -262,23 +266,34 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
case FSL_USB2_PHY_NONE: case FSL_USB2_PHY_NONE:
break; 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]); 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 usb_hcd *hcd = ehci_to_hcd(ehci);
struct fsl_usb2_platform_data *pdata; struct fsl_usb2_platform_data *pdata;
void __iomem *non_ehci = hcd->regs; void __iomem *non_ehci = hcd->regs;
u32 temp;
pdata = hcd->self.controller->platform_data; pdata = hcd->self.controller->platform_data;
/* Enable PHY interface in the control reg. */
if (pdata->have_sysif_regs) { 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 * Turn on cache snooping hardware, since some PowerPC platforms
* wholly rely on hardware to deal with cache coherent * wholly rely on hardware to deal with cache coherent
...@@ -293,7 +308,8 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) ...@@ -293,7 +308,8 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
if ((pdata->operating_mode == FSL_USB2_DR_HOST) || if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
(pdata->operating_mode == FSL_USB2_DR_OTG)) (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) { if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
unsigned int chip, rev, svr; unsigned int chip, rev, svr;
...@@ -307,9 +323,12 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) ...@@ -307,9 +323,12 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
ehci->has_fsl_port_bug = 1; ehci->has_fsl_port_bug = 1;
if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) 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) 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) { if (pdata->have_sysif_regs) {
...@@ -322,12 +341,15 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) ...@@ -322,12 +341,15 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
#endif #endif
out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
} }
return 0;
} }
/* called after powerup, by probe or system-pm "wakeup" */ /* called after powerup, by probe or system-pm "wakeup" */
static int ehci_fsl_reinit(struct ehci_hcd *ehci) 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); ehci_port_power(ehci, 0);
return 0; return 0;
......
...@@ -61,4 +61,5 @@ ...@@ -61,4 +61,5 @@
#define PLL_RESET (1<<8) #define PLL_RESET (1<<8)
#define UTMI_PHY_EN (1<<9) #define UTMI_PHY_EN (1<<9)
#define ULPI_PHY_CLK_SEL (1<<10) #define ULPI_PHY_CLK_SEL (1<<10)
#define PHY_CLK_VALID (1<<17)
#endif /* _EHCI_FSL_H */ #endif /* _EHCI_FSL_H */
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#define FSL_UTMI_PHY_DLY 10 /*As per P1010RM, delay for UTMI #define FSL_UTMI_PHY_DLY 10 /*As per P1010RM, delay for UTMI
PHY CLK to become stable - 10ms*/ PHY CLK to become stable - 10ms*/
#define FSL_USB_PHY_CLK_TIMEOUT 1000 /* uSec */
#define FSL_USB_VER_OLD 0 #define FSL_USB_VER_OLD 0
#define FSL_USB_VER_1_6 1 #define FSL_USB_VER_1_6 1
#define FSL_USB_VER_2_2 2 #define FSL_USB_VER_2_2 2
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment