aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2014-02-25 15:47:54 -0500
committerFelipe Balbi <balbi@ti.com>2014-03-05 10:44:50 -0500
commite1dadd3b0f277e59847d6b7de86ff67306bee4b1 (patch)
tree32b8c2b41f6b57b8ff4aa5acc1b60525cf15dfb0
parent32a4a135847b1e600c64756b7c7c7a91eb2f0aa9 (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.c31
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
2381static 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
2381static void dwc3_gadget_interrupt(struct dwc3 *dwc, 2405static 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;