usb: dwc3: gadget: implement streams support

The following patch adds support for streams
to dwc3 driver.

While at that, also fix one small issue on
endpoint disable where we should clear all
flags not only ENABLED.

Reviewied-by: Paul Zimmerman <paulz@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 502582c..c6de53c 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -329,6 +329,7 @@
  * @interval: the intervall on which the ISOC transfer is started
  * @name: a human readable name e.g. ep1out-bulk
  * @direction: true for TX, false for RX
+ * @stream_capable: true when streams are enabled
  */
 struct dwc3_ep {
 	struct usb_ep		endpoint;
@@ -362,6 +363,7 @@
 	char			name[20];
 
 	unsigned		direction:1;
+	unsigned		stream_capable:1;
 };
 
 enum dwc3_phy {
@@ -650,6 +652,10 @@
 #define DEPEVT_STATUS_IOC       (1 << 2)
 #define DEPEVT_STATUS_LST	(1 << 3)
 
+/* Stream event only */
+#define DEPEVT_STREAMEVT_FOUND		1
+#define DEPEVT_STREAMEVT_NOTFOUND	2
+
 /* Control-only Status */
 #define DEPEVT_STATUS_CONTROL_SETUP	0
 #define DEPEVT_STATUS_CONTROL_DATA	1
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 524ff91..8d85023 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -264,6 +264,12 @@
 	params.param1.depcfg.xfer_complete_enable = true;
 	params.param1.depcfg.xfer_not_ready_enable = true;
 
+	if (usb_endpoint_xfer_bulk(desc) && dep->endpoint.max_streams) {
+		params.param1.depcfg.stream_capable = true;
+		params.param1.depcfg.stream_event_enable = true;
+		dep->stream_capable = true;
+	}
+
 	if (usb_endpoint_xfer_isoc(desc))
 		params.param1.depcfg.xfer_in_progress_enable = true;
 
@@ -391,15 +397,16 @@
 	struct dwc3		*dwc = dep->dwc;
 	u32			reg;
 
-	dep->flags &= ~DWC3_EP_ENABLED;
 	dwc3_remove_requests(dwc, dep);
 
 	reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
 	reg &= ~DWC3_DALEPENA_EP(dep->number);
 	dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
 
+	dep->stream_capable = false;
 	dep->desc = NULL;
 	dep->type = 0;
+	dep->flags = 0;
 
 	return 0;
 }
@@ -633,6 +640,9 @@
 			trb.lst = last_one;
 		}
 
+		if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+			trb.sid_sofn = req->request.stream_id;
+
 		switch (usb_endpoint_type(dep->desc)) {
 		case USB_ENDPOINT_XFER_CONTROL:
 			trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
@@ -1505,12 +1515,28 @@
 		}
 
 		break;
+	case DWC3_DEPEVT_STREAMEVT:
+		if (!usb_endpoint_xfer_bulk(dep->desc)) {
+			dev_err(dwc->dev, "Stream event for non-Bulk %s\n",
+					dep->name);
+			return;
+		}
+
+		switch (event->status) {
+		case DEPEVT_STREAMEVT_FOUND:
+			dev_vdbg(dwc->dev, "Stream %d found and started\n",
+					event->parameters);
+
+			break;
+		case DEPEVT_STREAMEVT_NOTFOUND:
+			/* FALLTHROUGH */
+		default:
+			dev_dbg(dwc->dev, "Couldn't find suitable stream\n");
+		}
+		break;
 	case DWC3_DEPEVT_RXTXFIFOEVT:
 		dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
 		break;
-	case DWC3_DEPEVT_STREAMEVT:
-		dev_dbg(dwc->dev, "%s Stream Event\n", dep->name);
-		break;
 	case DWC3_DEPEVT_EPCMDCMPLT:
 		dwc3_ep_cmd_compl(dep, event);
 		break;