aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2011-10-14 08:11:49 -0400
committerFelipe Balbi <balbi@ti.com>2011-12-12 04:48:42 -0500
commitdf62df56e13d73cb0dd4c54649d4fe13557128f8 (patch)
tree1436686e851eb583433c98963496e53be1d3420b /drivers/usb/dwc3
parent05870c5ba2002c7d49adf8875cca49ee062af894 (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.h2
-rw-r--r--drivers/usb/dwc3/ep0.c3
-rw-r--r--drivers/usb/dwc3/gadget.c32
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)
726static void dwc3_ep0_xfernotready(struct dwc3 *dwc, 727static 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
1645static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on) 1646static 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);