diff options
author | Shengzhou Liu <Shengzhou.Liu@freescale.com> | 2012-08-22 06:17:00 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-09-05 19:52:08 -0400 |
commit | 3735ba8db8e6ea22ad3ff524328926d8d780a884 (patch) | |
tree | 002b17dc5fe22c4c437f4f79ac8657c343587243 /drivers/usb | |
parent | 67990472c77b06cc591dd59923542f64da91453d (diff) |
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>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/ehci-fsl.c | 58 | ||||
-rw-r--r-- | drivers/usb/host/ehci-fsl.h | 1 |
2 files changed, 41 insertions, 18 deletions
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index b7451b29c5a..11ff4b4dc7a 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c | |||
@@ -210,11 +210,11 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, | |||
210 | usb_put_hcd(hcd); | 210 | usb_put_hcd(hcd); |
211 | } | 211 | } |
212 | 212 | ||
213 | static void ehci_fsl_setup_phy(struct usb_hcd *hcd, | 213 | static int ehci_fsl_setup_phy(struct usb_hcd *hcd, |
214 | enum fsl_usb2_phy_modes phy_mode, | 214 | enum fsl_usb2_phy_modes phy_mode, |
215 | unsigned int port_offset) | 215 | unsigned int port_offset) |
216 | { | 216 | { |
217 | u32 portsc, temp; | 217 | u32 portsc; |
218 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | 218 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
219 | void __iomem *non_ehci = hcd->regs; | 219 | void __iomem *non_ehci = hcd->regs; |
220 | struct device *dev = hcd->self.controller; | 220 | struct device *dev = hcd->self.controller; |
@@ -232,9 +232,15 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd, | |||
232 | case FSL_USB2_PHY_ULPI: | 232 | case FSL_USB2_PHY_ULPI: |
233 | if (pdata->controller_ver) { | 233 | if (pdata->controller_ver) { |
234 | /* controller version 1.6 or above */ | 234 | /* controller version 1.6 or above */ |
235 | temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); | 235 | setbits32(non_ehci + FSL_SOC_USB_CTRL, |
236 | out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | | 236 | ULPI_PHY_CLK_SEL); |
237 | USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL); | 237 | /* |
238 | * Due to controller issue of PHY_CLK_VALID in ULPI | ||
239 | * mode, we set USB_CTRL_USB_EN before checking | ||
240 | * PHY_CLK_VALID, otherwise PHY_CLK_VALID doesn't work. | ||
241 | */ | ||
242 | clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, | ||
243 | UTMI_PHY_EN, USB_CTRL_USB_EN); | ||
238 | } | 244 | } |
239 | portsc |= PORT_PTS_ULPI; | 245 | portsc |= PORT_PTS_ULPI; |
240 | break; | 246 | break; |
@@ -247,9 +253,7 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd, | |||
247 | case FSL_USB2_PHY_UTMI: | 253 | case FSL_USB2_PHY_UTMI: |
248 | if (pdata->controller_ver) { | 254 | if (pdata->controller_ver) { |
249 | /* controller version 1.6 or above */ | 255 | /* controller version 1.6 or above */ |
250 | temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); | 256 | setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); |
251 | out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | | ||
252 | UTMI_PHY_EN | USB_CTRL_USB_EN); | ||
253 | mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to | 257 | mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to |
254 | become stable - 10ms*/ | 258 | become stable - 10ms*/ |
255 | } | 259 | } |
@@ -262,23 +266,34 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd, | |||
262 | case FSL_USB2_PHY_NONE: | 266 | case FSL_USB2_PHY_NONE: |
263 | break; | 267 | break; |
264 | } | 268 | } |
269 | |||
270 | if ((pdata->controller_ver) && ((phy_mode == FSL_USB2_PHY_ULPI) || | ||
271 | (phy_mode == FSL_USB2_PHY_UTMI))) { | ||
272 | /* check PHY_CLK_VALID to get phy clk valid */ | ||
273 | if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & | ||
274 | PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) { | ||
275 | printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n"); | ||
276 | return -EINVAL; | ||
277 | } | ||
278 | } | ||
279 | |||
265 | ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); | 280 | ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); |
281 | |||
282 | if (phy_mode != FSL_USB2_PHY_ULPI) | ||
283 | setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN); | ||
284 | |||
285 | return 0; | ||
266 | } | 286 | } |
267 | 287 | ||
268 | static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) | 288 | static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) |
269 | { | 289 | { |
270 | struct usb_hcd *hcd = ehci_to_hcd(ehci); | 290 | struct usb_hcd *hcd = ehci_to_hcd(ehci); |
271 | struct fsl_usb2_platform_data *pdata; | 291 | struct fsl_usb2_platform_data *pdata; |
272 | void __iomem *non_ehci = hcd->regs; | 292 | void __iomem *non_ehci = hcd->regs; |
273 | u32 temp; | ||
274 | 293 | ||
275 | pdata = hcd->self.controller->platform_data; | 294 | pdata = hcd->self.controller->platform_data; |
276 | 295 | ||
277 | /* Enable PHY interface in the control reg. */ | ||
278 | if (pdata->have_sysif_regs) { | 296 | if (pdata->have_sysif_regs) { |
279 | temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); | ||
280 | out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004); | ||
281 | |||
282 | /* | 297 | /* |
283 | * Turn on cache snooping hardware, since some PowerPC platforms | 298 | * Turn on cache snooping hardware, since some PowerPC platforms |
284 | * wholly rely on hardware to deal with cache coherent | 299 | * wholly rely on hardware to deal with cache coherent |
@@ -293,7 +308,8 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) | |||
293 | 308 | ||
294 | if ((pdata->operating_mode == FSL_USB2_DR_HOST) || | 309 | if ((pdata->operating_mode == FSL_USB2_DR_HOST) || |
295 | (pdata->operating_mode == FSL_USB2_DR_OTG)) | 310 | (pdata->operating_mode == FSL_USB2_DR_OTG)) |
296 | ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0); | 311 | if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0)) |
312 | return -EINVAL; | ||
297 | 313 | ||
298 | if (pdata->operating_mode == FSL_USB2_MPH_HOST) { | 314 | if (pdata->operating_mode == FSL_USB2_MPH_HOST) { |
299 | unsigned int chip, rev, svr; | 315 | unsigned int chip, rev, svr; |
@@ -307,9 +323,12 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) | |||
307 | ehci->has_fsl_port_bug = 1; | 323 | ehci->has_fsl_port_bug = 1; |
308 | 324 | ||
309 | if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) | 325 | if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) |
310 | ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0); | 326 | if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0)) |
327 | return -EINVAL; | ||
328 | |||
311 | if (pdata->port_enables & FSL_USB2_PORT1_ENABLED) | 329 | if (pdata->port_enables & FSL_USB2_PORT1_ENABLED) |
312 | ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1); | 330 | if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1)) |
331 | return -EINVAL; | ||
313 | } | 332 | } |
314 | 333 | ||
315 | if (pdata->have_sysif_regs) { | 334 | if (pdata->have_sysif_regs) { |
@@ -322,12 +341,15 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) | |||
322 | #endif | 341 | #endif |
323 | out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); | 342 | out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); |
324 | } | 343 | } |
344 | |||
345 | return 0; | ||
325 | } | 346 | } |
326 | 347 | ||
327 | /* called after powerup, by probe or system-pm "wakeup" */ | 348 | /* called after powerup, by probe or system-pm "wakeup" */ |
328 | static int ehci_fsl_reinit(struct ehci_hcd *ehci) | 349 | static int ehci_fsl_reinit(struct ehci_hcd *ehci) |
329 | { | 350 | { |
330 | ehci_fsl_usb_setup(ehci); | 351 | if (ehci_fsl_usb_setup(ehci)) |
352 | return -EINVAL; | ||
331 | ehci_port_power(ehci, 0); | 353 | ehci_port_power(ehci, 0); |
332 | 354 | ||
333 | return 0; | 355 | return 0; |
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h index 88403684d10..dbd292e9f0a 100644 --- a/drivers/usb/host/ehci-fsl.h +++ b/drivers/usb/host/ehci-fsl.h | |||
@@ -61,4 +61,5 @@ | |||
61 | #define PLL_RESET (1<<8) | 61 | #define PLL_RESET (1<<8) |
62 | #define UTMI_PHY_EN (1<<9) | 62 | #define UTMI_PHY_EN (1<<9) |
63 | #define ULPI_PHY_CLK_SEL (1<<10) | 63 | #define ULPI_PHY_CLK_SEL (1<<10) |
64 | #define PHY_CLK_VALID (1<<17) | ||
64 | #endif /* _EHCI_FSL_H */ | 65 | #endif /* _EHCI_FSL_H */ |