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: Shengzhou Liu <Shengzhou.Liu@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
67990472c7
commit
3735ba8db8
3 changed files with 42 additions and 18 deletions
|
@ -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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
#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 @@
|
||||||
#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 @@
|
||||||
|
|
||||||
#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
|
||||||
|
|
Loading…
Reference in a new issue