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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Shengzhou Liu
				Shengzhou Liu