Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+40 −18
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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