Commit 9d4b8270 authored by Changming Huang's avatar Changming Huang Committed by Greg Kroah-Hartman

fsl/usb: Workarourd for USB erratum-A005697

The EHCI specification states the following in the SUSP bit description:
In the Suspend state, the port is sensitive to resume detection.
Note that the bit status does not change until the port is suspended and
that there may be a delay in suspending a port if there is a transaction
currently in progress on the USB.

However, in NXP USBDR controller, the PORTSCx[SUSP] bit changes immediately
when the application sets it and not when the port is actually suspended.

So the application must wait for at least 10 milliseconds after a port
indicates that it is suspended, to make sure this port has entered
suspended state before initiating this port resume using the Force Port
Resume bit. This bit is for NXP controller, not EHCI compatible.
Signed-off-by: default avatarChangming Huang <jerry.huang@nxp.com>
Signed-off-by: default avatarRamneek Mehresh <ramneek.mehresh@nxp.com>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 22547c4c
...@@ -286,6 +286,9 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) ...@@ -286,6 +286,9 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
if (pdata->has_fsl_erratum_a005275 == 1) if (pdata->has_fsl_erratum_a005275 == 1)
ehci->has_fsl_hs_errata = 1; ehci->has_fsl_hs_errata = 1;
if (pdata->has_fsl_erratum_a005697 == 1)
ehci->has_fsl_susp_errata = 1;
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))
if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0)) if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0))
......
...@@ -310,6 +310,14 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) ...@@ -310,6 +310,14 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
} }
spin_unlock_irq(&ehci->lock); spin_unlock_irq(&ehci->lock);
if (changed && ehci_has_fsl_susp_errata(ehci))
/*
* Wait for at least 10 millisecondes to ensure the controller
* enter the suspend status before initiating a port resume
* using the Force Port Resume bit (Not-EHCI compatible).
*/
usleep_range(10000, 20000);
if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) { if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) {
/* /*
* Wait for HCD to enter low-power mode or for the bus * Wait for HCD to enter low-power mode or for the bus
...@@ -1200,6 +1208,12 @@ int ehci_hub_control( ...@@ -1200,6 +1208,12 @@ int ehci_hub_control(
wIndex, (temp1 & HOSTPC_PHCD) ? wIndex, (temp1 & HOSTPC_PHCD) ?
"succeeded" : "failed"); "succeeded" : "failed");
} }
if (ehci_has_fsl_susp_errata(ehci)) {
/* 10ms for HCD enter suspend */
spin_unlock_irqrestore(&ehci->lock, flags);
usleep_range(10000, 20000);
spin_lock_irqsave(&ehci->lock, flags);
}
set_bit(wIndex, &ehci->suspended_ports); set_bit(wIndex, &ehci->suspended_ports);
break; break;
case USB_PORT_FEAT_POWER: case USB_PORT_FEAT_POWER:
......
...@@ -219,6 +219,7 @@ struct ehci_hcd { /* one per controller */ ...@@ -219,6 +219,7 @@ struct ehci_hcd { /* one per controller */
unsigned no_selective_suspend:1; unsigned no_selective_suspend:1;
unsigned has_fsl_port_bug:1; /* FreeScale */ unsigned has_fsl_port_bug:1; /* FreeScale */
unsigned has_fsl_hs_errata:1; /* Freescale HS quirk */ unsigned has_fsl_hs_errata:1; /* Freescale HS quirk */
unsigned has_fsl_susp_errata:1; /* NXP SUSP quirk */
unsigned big_endian_mmio:1; unsigned big_endian_mmio:1;
unsigned big_endian_desc:1; unsigned big_endian_desc:1;
unsigned big_endian_capbase:1; unsigned big_endian_capbase:1;
...@@ -709,6 +710,13 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) ...@@ -709,6 +710,13 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#define ehci_has_fsl_hs_errata(e) (0) #define ehci_has_fsl_hs_errata(e) (0)
#endif #endif
/*
* Some Freescale/NXP processors have an erratum (USB A-005697)
* in which we need to wait for 10ms for bus to enter suspend mode
* after setting SUSP bit.
*/
#define ehci_has_fsl_susp_errata(e) ((e)->has_fsl_susp_errata)
/* /*
* While most USB host controllers implement their registers in * While most USB host controllers implement their registers in
* little-endian format, a minority (celleb companion chip) implement * little-endian format, a minority (celleb companion chip) implement
......
...@@ -226,6 +226,8 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) ...@@ -226,6 +226,8 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
of_property_read_bool(np, "fsl,usb-erratum-a007792"); of_property_read_bool(np, "fsl,usb-erratum-a007792");
pdata->has_fsl_erratum_a005275 = pdata->has_fsl_erratum_a005275 =
of_property_read_bool(np, "fsl,usb-erratum-a005275"); of_property_read_bool(np, "fsl,usb-erratum-a005275");
pdata->has_fsl_erratum_a005697 =
of_property_read_bool(np, "fsl,usb_erratum-a005697");
/* /*
* Determine whether phy_clk_valid needs to be checked * Determine whether phy_clk_valid needs to be checked
......
...@@ -100,6 +100,7 @@ struct fsl_usb2_platform_data { ...@@ -100,6 +100,7 @@ struct fsl_usb2_platform_data {
unsigned already_suspended:1; unsigned already_suspended:1;
unsigned has_fsl_erratum_a007792:1; unsigned has_fsl_erratum_a007792:1;
unsigned has_fsl_erratum_a005275:1; unsigned has_fsl_erratum_a005275:1;
unsigned has_fsl_erratum_a005697:1;
unsigned check_phy_clk_valid:1; unsigned check_phy_clk_valid:1;
/* register save area for suspend/resume */ /* register save area for suspend/resume */
......
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