diff options
author | Felipe Balbi <balbi@ti.com> | 2014-02-25 15:47:54 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2014-03-05 10:44:50 -0500 |
commit | e1dadd3b0f277e59847d6b7de86ff67306bee4b1 (patch) | |
tree | 32b8c2b41f6b57b8ff4aa5acc1b60525cf15dfb0 | |
parent | 32a4a135847b1e600c64756b7c7c7a91eb2f0aa9 (diff) |
usb: dwc3: workaround: bogus hibernation events
Revision 2.20a of the core has a known issue
which would generate bogus hibernation events
_and_ random failures on USB CV TD.9.23 test
case.
The suggested workaround is to ignore hibernation
events which don't match currently connected
speed.
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 9e878d9bc909..7f4e6dd63c00 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c | |||
@@ -2378,6 +2378,30 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, | |||
2378 | dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state); | 2378 | dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state); |
2379 | } | 2379 | } |
2380 | 2380 | ||
2381 | static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, | ||
2382 | unsigned int evtinfo) | ||
2383 | { | ||
2384 | unsigned int is_ss = evtinfo & BIT(4); | ||
2385 | |||
2386 | /** | ||
2387 | * WORKAROUND: DWC3 revison 2.20a with hibernation support | ||
2388 | * have a known issue which can cause USB CV TD.9.23 to fail | ||
2389 | * randomly. | ||
2390 | * | ||
2391 | * Because of this issue, core could generate bogus hibernation | ||
2392 | * events which SW needs to ignore. | ||
2393 | * | ||
2394 | * Refers to: | ||
2395 | * | ||
2396 | * STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0 | ||
2397 | * Device Fallback from SuperSpeed | ||
2398 | */ | ||
2399 | if (is_ss ^ (dwc->speed == USB_SPEED_SUPER)) | ||
2400 | return; | ||
2401 | |||
2402 | /* enter hibernation here */ | ||
2403 | } | ||
2404 | |||
2381 | static void dwc3_gadget_interrupt(struct dwc3 *dwc, | 2405 | static void dwc3_gadget_interrupt(struct dwc3 *dwc, |
2382 | const struct dwc3_event_devt *event) | 2406 | const struct dwc3_event_devt *event) |
2383 | { | 2407 | { |
@@ -2394,6 +2418,13 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, | |||
2394 | case DWC3_DEVICE_EVENT_WAKEUP: | 2418 | case DWC3_DEVICE_EVENT_WAKEUP: |
2395 | dwc3_gadget_wakeup_interrupt(dwc); | 2419 | dwc3_gadget_wakeup_interrupt(dwc); |
2396 | break; | 2420 | break; |
2421 | case DWC3_DEVICE_EVENT_HIBER_REQ: | ||
2422 | if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation, | ||
2423 | "unexpected hibernation event\n")) | ||
2424 | break; | ||
2425 | |||
2426 | dwc3_gadget_hibernation_interrupt(dwc, event->event_info); | ||
2427 | break; | ||
2397 | case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: | 2428 | case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: |
2398 | dwc3_gadget_linksts_change_interrupt(dwc, event->event_info); | 2429 | dwc3_gadget_linksts_change_interrupt(dwc, event->event_info); |
2399 | break; | 2430 | break; |