Commit df62df56 authored by Felipe Balbi's avatar Felipe Balbi
Browse files

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: default avatarFelipe Balbi <balbi@ti.com>
parent 05870c5b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -578,6 +578,7 @@ struct dwc3_hwparams {
 * @ep0_bounced: true when we used bounce buffer
 * @ep0_expect_in: true when we expect a DATA IN transfer
 * @start_config_issued: true when StartConfig command has been issued
 * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
 * @ep0_next_event: hold the next expected event
 * @ep0state: state of endpoint zero
 * @link_state: link state
@@ -633,6 +634,7 @@ struct dwc3 {
	unsigned		ep0_bounced:1;
	unsigned		ep0_expect_in:1;
	unsigned		start_config_issued:1;
	unsigned		setup_packet_pending:1;
	unsigned		delayed_status:1;

	enum dwc3_ep0_next	ep0_next_event;
+3 −0
Original line number Diff line number Diff line
@@ -625,6 +625,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];

	dep->flags &= ~DWC3_EP_BUSY;
	dwc->setup_packet_pending = false;

	switch (dwc->ep0state) {
	case EP0_SETUP_PHASE:
@@ -726,6 +727,8 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
		const struct dwc3_event_depevt *event)
{
	dwc->setup_packet_pending = true;

	/*
	 * This part is very tricky: If we has just handled
	 * XferNotReady(Setup) and we're now expecting a
+32 −0
Original line number Diff line number Diff line
@@ -1640,6 +1640,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
	dwc->start_config_issued = false;

	dwc->gadget.speed = USB_SPEED_UNKNOWN;
	dwc->setup_packet_pending = false;
}

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)

	dev_vdbg(dwc->dev, "%s\n", __func__);

	/*
	 * WORKAROUND: DWC3 revisions <1.88a have an issue which
	 * would cause a missing Disconnect Event if there's a
	 * pending Setup Packet in the FIFO.
	 *
	 * There's no suggested workaround on the official Bug
	 * report, which states that "unless the driver/application
	 * is doing any special handling of a disconnect event,
	 * there is no functional issue".
	 *
	 * Unfortunately, it turns out that we _do_ some special
	 * handling of a disconnect event, namely complete all
	 * pending transfers, notify gadget driver of the
	 * disconnection, and so on.
	 *
	 * Our suggested workaround is to follow the Disconnect
	 * Event steps here, instead, based on a setup_packet_pending
	 * flag. Such flag gets set whenever we have a XferNotReady
	 * event on EP0 and gets cleared on XferComplete for the
	 * same endpoint.
	 *
	 * Refers to:
	 *
	 * STAR#9000466709: RTL: Device : Disconnect event not
	 * generated if setup packet pending in FIFO
	 */
	if (dwc->revision < DWC3_REVISION_188A) {
		if (dwc->setup_packet_pending)
			dwc3_gadget_disconnect_interrupt(dwc);
	}

	/* Enable PHYs */
	dwc3_gadget_usb2_phy_power(dwc, true);
	dwc3_gadget_usb3_phy_power(dwc, true);