diff options
author | Felipe Balbi <balbi@ti.com> | 2011-10-14 08:11:49 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2011-12-12 04:48:42 -0500 |
commit | df62df56e13d73cb0dd4c54649d4fe13557128f8 (patch) | |
tree | 1436686e851eb583433c98963496e53be1d3420b /drivers/usb/dwc3 | |
parent | 05870c5ba2002c7d49adf8875cca49ee062af894 (diff) |
usb: dwc3: workaround: missing disconnect event
DWC3 revisions <1.88a have an issue which would
case a missing Disconnect event if cable is
disconnected while there's a Setup packet
pending the FIFO.
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r-- | drivers/usb/dwc3/core.h | 2 | ||||
-rw-r--r-- | drivers/usb/dwc3/ep0.c | 3 | ||||
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 32 |
3 files changed, 37 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index b901a4d3b068..836cf9942a4f 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h | |||
@@ -578,6 +578,7 @@ struct dwc3_hwparams { | |||
578 | * @ep0_bounced: true when we used bounce buffer | 578 | * @ep0_bounced: true when we used bounce buffer |
579 | * @ep0_expect_in: true when we expect a DATA IN transfer | 579 | * @ep0_expect_in: true when we expect a DATA IN transfer |
580 | * @start_config_issued: true when StartConfig command has been issued | 580 | * @start_config_issued: true when StartConfig command has been issued |
581 | * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround | ||
581 | * @ep0_next_event: hold the next expected event | 582 | * @ep0_next_event: hold the next expected event |
582 | * @ep0state: state of endpoint zero | 583 | * @ep0state: state of endpoint zero |
583 | * @link_state: link state | 584 | * @link_state: link state |
@@ -633,6 +634,7 @@ struct dwc3 { | |||
633 | unsigned ep0_bounced:1; | 634 | unsigned ep0_bounced:1; |
634 | unsigned ep0_expect_in:1; | 635 | unsigned ep0_expect_in:1; |
635 | unsigned start_config_issued:1; | 636 | unsigned start_config_issued:1; |
637 | unsigned setup_packet_pending:1; | ||
636 | unsigned delayed_status:1; | 638 | unsigned delayed_status:1; |
637 | 639 | ||
638 | enum dwc3_ep0_next ep0_next_event; | 640 | enum dwc3_ep0_next ep0_next_event; |
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 314acb289d23..ed44525c8d62 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c | |||
@@ -625,6 +625,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, | |||
625 | struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; | 625 | struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; |
626 | 626 | ||
627 | dep->flags &= ~DWC3_EP_BUSY; | 627 | dep->flags &= ~DWC3_EP_BUSY; |
628 | dwc->setup_packet_pending = false; | ||
628 | 629 | ||
629 | switch (dwc->ep0state) { | 630 | switch (dwc->ep0state) { |
630 | case EP0_SETUP_PHASE: | 631 | case EP0_SETUP_PHASE: |
@@ -726,6 +727,8 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum) | |||
726 | static void dwc3_ep0_xfernotready(struct dwc3 *dwc, | 727 | static void dwc3_ep0_xfernotready(struct dwc3 *dwc, |
727 | const struct dwc3_event_depevt *event) | 728 | const struct dwc3_event_depevt *event) |
728 | { | 729 | { |
730 | dwc->setup_packet_pending = true; | ||
731 | |||
729 | /* | 732 | /* |
730 | * This part is very tricky: If we has just handled | 733 | * This part is very tricky: If we has just handled |
731 | * XferNotReady(Setup) and we're now expecting a | 734 | * XferNotReady(Setup) and we're now expecting a |
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 6704a52c9f12..7c98b3f2e6a7 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c | |||
@@ -1640,6 +1640,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) | |||
1640 | dwc->start_config_issued = false; | 1640 | dwc->start_config_issued = false; |
1641 | 1641 | ||
1642 | dwc->gadget.speed = USB_SPEED_UNKNOWN; | 1642 | dwc->gadget.speed = USB_SPEED_UNKNOWN; |
1643 | dwc->setup_packet_pending = false; | ||
1643 | } | 1644 | } |
1644 | 1645 | ||
1645 | static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on) | 1646 | static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on) |
@@ -1676,6 +1677,37 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) | |||
1676 | 1677 | ||
1677 | dev_vdbg(dwc->dev, "%s\n", __func__); | 1678 | dev_vdbg(dwc->dev, "%s\n", __func__); |
1678 | 1679 | ||
1680 | /* | ||
1681 | * WORKAROUND: DWC3 revisions <1.88a have an issue which | ||
1682 | * would cause a missing Disconnect Event if there's a | ||
1683 | * pending Setup Packet in the FIFO. | ||
1684 | * | ||
1685 | * There's no suggested workaround on the official Bug | ||
1686 | * report, which states that "unless the driver/application | ||
1687 | * is doing any special handling of a disconnect event, | ||
1688 | * there is no functional issue". | ||
1689 | * | ||
1690 | * Unfortunately, it turns out that we _do_ some special | ||
1691 | * handling of a disconnect event, namely complete all | ||
1692 | * pending transfers, notify gadget driver of the | ||
1693 | * disconnection, and so on. | ||
1694 | * | ||
1695 | * Our suggested workaround is to follow the Disconnect | ||
1696 | * Event steps here, instead, based on a setup_packet_pending | ||
1697 | * flag. Such flag gets set whenever we have a XferNotReady | ||
1698 | * event on EP0 and gets cleared on XferComplete for the | ||
1699 | * same endpoint. | ||
1700 | * | ||
1701 | * Refers to: | ||
1702 | * | ||
1703 | * STAR#9000466709: RTL: Device : Disconnect event not | ||
1704 | * generated if setup packet pending in FIFO | ||
1705 | */ | ||
1706 | if (dwc->revision < DWC3_REVISION_188A) { | ||
1707 | if (dwc->setup_packet_pending) | ||
1708 | dwc3_gadget_disconnect_interrupt(dwc); | ||
1709 | } | ||
1710 | |||
1679 | /* Enable PHYs */ | 1711 | /* Enable PHYs */ |
1680 | dwc3_gadget_usb2_phy_power(dwc, true); | 1712 | dwc3_gadget_usb2_phy_power(dwc, true); |
1681 | dwc3_gadget_usb3_phy_power(dwc, true); | 1713 | dwc3_gadget_usb3_phy_power(dwc, true); |