usb: gadget: Introduce qdss function driver

The QDSS function driver supports high throughput debug information
delivery from the QDSS core to the host via the USB port.

Change-Id: Ia9397944d39d767c1200ad87aac67d5627233282
Signed-off-by: Shimrit Malichi <smalichi@codeaurora.org>
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 136c6d9..522e3a4 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -43,27 +43,29 @@
  *  USB DBM Hardware registers.
  *
  */
-#define DBM_EP_CFG(n)		(0x00 + 4 * (n))
-#define DBM_DATA_FIFO(n)	(0x10 + 4 * (n))
-#define DBM_DATA_FIFO_SIZE(n)	(0x20 + 4 * (n))
-#define DBM_DATA_FIFO_EN	(0x30)
-#define DBM_GEVNTADR		(0x34)
-#define DBM_GEVNTSIZ		(0x38)
-#define DBM_DBG_CNFG		(0x3C)
-#define DBM_HW_TRB0_EP(n)	(0x40 + 4 * (n))
-#define DBM_HW_TRB1_EP(n)	(0x50 + 4 * (n))
-#define DBM_HW_TRB2_EP(n)	(0x60 + 4 * (n))
-#define DBM_HW_TRB3_EP(n)	(0x70 + 4 * (n))
-#define DBM_PIPE_CFG		(0x80)
-#define DBM_SOFT_RESET		(0x84)
+#define DBM_BASE		0x000F8000
+#define DBM_EP_CFG(n)		(DBM_BASE + (0x00 + 4 * (n)))
+#define DBM_DATA_FIFO(n)	(DBM_BASE + (0x10 + 4 * (n)))
+#define DBM_DATA_FIFO_SIZE(n)	(DBM_BASE + (0x20 + 4 * (n)))
+#define DBM_DATA_FIFO_EN	(DBM_BASE + (0x30))
+#define DBM_GEVNTADR		(DBM_BASE + (0x34))
+#define DBM_GEVNTSIZ		(DBM_BASE + (0x38))
+#define DBM_DBG_CNFG		(DBM_BASE + (0x3C))
+#define DBM_HW_TRB0_EP(n)	(DBM_BASE + (0x40 + 4 * (n)))
+#define DBM_HW_TRB1_EP(n)	(DBM_BASE + (0x50 + 4 * (n)))
+#define DBM_HW_TRB2_EP(n)	(DBM_BASE + (0x60 + 4 * (n)))
+#define DBM_HW_TRB3_EP(n)	(DBM_BASE + (0x70 + 4 * (n)))
+#define DBM_PIPE_CFG		(DBM_BASE + (0x80))
+#define DBM_SOFT_RESET		(DBM_BASE + (0x84))
+#define DBM_GEN_CFG		(DBM_BASE + (0x88))
 
 /**
  *  USB DBM  Hardware registers bitmask.
  *
  */
 /* DBM_EP_CFG */
-#define DBM_EN_EP		0x00000000
-#define DBM_USB3_EP_NUM		0x0000003E
+#define DBM_EN_EP		0x00000001
+#define USB3_EPNUM		0x0000003E
 #define DBM_BAM_PIPE_NUM	0x000000C0
 #define DBM_PRODUCER		0x00000100
 #define DBM_DISABLE_WB		0x00000200
@@ -83,8 +85,9 @@
 #define DBM_SFT_RST_EP1		0x00000002
 #define DBM_SFT_RST_EP2		0x00000004
 #define DBM_SFT_RST_EP3		0x00000008
-#define DBM_SFT_RST_EPS		0x0000000F
-#define DBM_SFT_RST		0x80000000
+#define DBM_SFT_RST_EPS_MASK	0x0000000F
+#define DBM_SFT_RST_MASK	0x80000000
+#define DBM_EN_MASK		0x00000002
 
 #define DBM_MAX_EPS		4
 
@@ -93,17 +96,18 @@
 #define DBM_TRB_DATA_SRC	0x40000000
 #define DBM_TRB_DMA		0x20000000
 #define DBM_TRB_EP_NUM(ep)	(ep<<24)
+
 /**
  *  USB QSCRATCH Hardware registers
  *
  */
 #define QSCRATCH_REG_OFFSET	(0x000F8800)
+#define QSCRATCH_GENERAL_CFG	(QSCRATCH_REG_OFFSET + 0x08)
 #define CHARGING_DET_CTRL_REG	(QSCRATCH_REG_OFFSET + 0x18)
 #define CHARGING_DET_OUTPUT_REG	(QSCRATCH_REG_OFFSET + 0x1C)
 #define ALT_INTERRUPT_EN_REG	(QSCRATCH_REG_OFFSET + 0x20)
 #define HS_PHY_IRQ_STAT_REG	(QSCRATCH_REG_OFFSET + 0x24)
 
-
 struct dwc3_msm_req_complete {
 	struct list_head list_item;
 	struct usb_request *req;
@@ -271,21 +275,6 @@
 }
 
 /**
- * Return DBM EP number which is not already configured.
- *
- */
-static int dwc3_msm_find_avail_dbm_ep(void)
-{
-	int i;
-
-	for (i = 0; i < context->dbm_num_eps; i++)
-		if (!context->ep_num_mapping[i])
-			return i;
-
-	return -ENODEV; /* Not found */
-}
-
-/**
  * Return DBM EP number according to usb endpoint number.
  *
  */
@@ -339,12 +328,21 @@
  * Reset the DBM registers upon initialization.
  *
  */
-static int dwc3_msm_dbm_soft_reset(void)
+static int dwc3_msm_dbm_soft_reset(int enter_reset)
 {
 	dev_dbg(context->dev, "%s\n", __func__);
-
-	dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
-		DBM_SFT_RST, 1);
+	if (enter_reset) {
+		dev_dbg(context->dev, "enter DBM reset\n");
+		dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
+			DBM_SFT_RST_MASK, 1);
+	} else {
+		dev_dbg(context->dev, "exit DBM reset\n");
+		dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
+			DBM_SFT_RST_MASK, 0);
+		/*enable DBM*/
+		dwc3_msm_write_reg_field(context->base, QSCRATCH_GENERAL_CFG,
+			DBM_EN_MASK, 0x1);
+	}
 
 	return 0;
 }
@@ -371,10 +369,10 @@
 
 	if (enter_reset) {
 		dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
-			DBM_SFT_RST_EPS, 1 << dbm_ep);
+			DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 1);
 	} else {
 		dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
-			DBM_SFT_RST_EPS, 0);
+			DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 0);
 	}
 
 	return 0;
@@ -397,36 +395,39 @@
 				  bool internal_mem, bool ioc)
 {
 	u8 dbm_ep;
-	u8 ioc_mask;
+	u32 ep_cfg;
 
 	dev_dbg(context->dev, "%s\n", __func__);
 
-	dbm_ep = dwc3_msm_find_avail_dbm_ep();
+	dbm_ep = dwc3_msm_find_matching_dbm_ep(usb_ep);
+
 	if (dbm_ep < 0) {
-		dev_err(context->dev, "%s: No more DBM eps\n", __func__);
+		dev_err(context->dev,
+				"%s: Invalid usb ep index\n", __func__);
 		return -ENODEV;
 	}
-
-	context->ep_num_mapping[dbm_ep] = usb_ep;
-
 	/* First, reset the dbm endpoint */
-	dwc3_msm_dbm_ep_soft_reset(dbm_ep, false);
+	dwc3_msm_dbm_ep_soft_reset(dbm_ep, 0);
 
-	ioc_mask = dwc3_msm_read_reg_field(context->base, DBM_DBG_CNFG,
-		DBM_ENABLE_IOC_MASK);
-	ioc_mask &= ~(ioc << dbm_ep); /* Clear ioc bit for dbm_ep */
 	/* Set ioc bit for dbm_ep if needed */
 	dwc3_msm_write_reg_field(context->base, DBM_DBG_CNFG,
-		DBM_ENABLE_IOC_MASK, ioc_mask | (ioc << dbm_ep));
+		DBM_ENABLE_IOC_MASK & 1 << dbm_ep, ioc ? 1 : 0);
 
-	dwc3_msm_write_reg(context->base, DBM_EP_CFG(dbm_ep),
-		producer | disable_wb | internal_mem);
+	ep_cfg = (producer ? DBM_PRODUCER : 0) |
+		(disable_wb ? DBM_DISABLE_WB : 0) |
+		(internal_mem ? DBM_INT_RAM_ACC : 0);
+
 	dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep),
-		DBM_USB3_EP_NUM, usb_ep);
+		DBM_PRODUCER | DBM_DISABLE_WB | DBM_INT_RAM_ACC, ep_cfg >> 8);
+
+	dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep), USB3_EPNUM,
+		usb_ep);
 	dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep),
 		DBM_BAM_PIPE_NUM, bam_pipe);
-	dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep),
-		DBM_EN_EP, 1);
+	dwc3_msm_write_reg_field(context->base, DBM_PIPE_CFG, 0x000000ff,
+		0xe4);
+	dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep), DBM_EN_EP,
+		1);
 
 	return dbm_ep;
 }
@@ -471,20 +472,16 @@
  * @size - size of data fifo.
  *
  */
-int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size)
+int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size, u8 dst_pipe_idx)
 {
 	u8 dbm_ep;
 	struct dwc3_ep *dep = to_dwc3_ep(ep);
+	u8 bam_pipe = dst_pipe_idx;
 
 	dev_dbg(context->dev, "%s\n", __func__);
 
-	dbm_ep = dwc3_msm_find_matching_dbm_ep(dep->number);
-
-	if (dbm_ep >= context->dbm_num_eps) {
-		dev_err(context->dev,
-				"%s: Invalid DBM ep index\n", __func__);
-		return -ENODEV;
-	}
+	dbm_ep = bam_pipe;
+	context->ep_num_mapping[dbm_ep] = dep->number;
 
 	dwc3_msm_write_reg(context->base, DBM_DATA_FIFO(dbm_ep), addr);
 	dwc3_msm_write_reg_field(context->base, DBM_DATA_FIFO_SIZE(dbm_ep),
@@ -547,7 +544,8 @@
 	 * taken by the caller of this function (dwc3_gadget_giveback()).
 	 */
 	request->complete = req_complete->orig_complete;
-	request->complete(ep, request);
+	if (request->complete)
+		request->complete(ep, request);
 
 	kfree(req_complete);
 }
@@ -585,18 +583,18 @@
 	memset(trb, 0, sizeof(*trb));
 
 	req->trb = trb;
-	req->trb_dma = dwc3_trb_dma_offset(dep, trb);
-	trb->bph = DBM_TRB_BIT | DBM_TRB_DATA_SRC |
-		   DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
+	trb->bph = DBM_TRB_BIT | DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
 	trb->size = DWC3_TRB_SIZE_LENGTH(req->request.length);
 	trb->ctrl = DWC3_TRBCTL_NORMAL | DWC3_TRB_CTRL_HWO | DWC3_TRB_CTRL_CHN;
+	req->trb_dma = dwc3_trb_dma_offset(dep, trb);
 
 	/* Second, prepare a Link TRB that points to the first TRB*/
 	trb_link = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
 	dep->free_slot++;
+	memset(trb_link, 0, sizeof *trb_link);
 
 	trb_link->bpl = lower_32_bits(req->trb_dma);
-	trb_link->bph = DBM_TRB_BIT | DBM_TRB_DATA_SRC |
+	trb_link->bph = DBM_TRB_BIT |
 			DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
 	trb_link->size = 0;
 	trb_link->ctrl = DWC3_TRBCTL_LINK_TRB | DWC3_TRB_CTRL_HWO;
@@ -605,8 +603,9 @@
 	 * Now start the transfer
 	 */
 	memset(&params, 0, sizeof(params));
-	params.param0 = upper_32_bits(req->trb_dma);
-	params.param1 = lower_32_bits(req->trb_dma);
+	params.param0 = 0; /* TDAddr High */
+	params.param1 = lower_32_bits(req->trb_dma); /* DAddr Low */
+
 	cmd = DWC3_DEPCMD_STARTTRANSFER;
 	ret = dwc3_send_gadget_ep_cmd(dep->dwc, dep->number, cmd, &params);
 	if (ret < 0) {
@@ -657,6 +656,7 @@
 	bool disable_wb;
 	bool internal_mem;
 	bool ioc;
+	u8 speed;
 
 	if (!(request->udc_priv & MSM_SPS_MODE)) {
 		/* Not SPS mode, call original queue */
@@ -707,17 +707,9 @@
 	request->complete = dwc3_msm_req_complete_func;
 
 	/*
-	 * Configure dbm event buffers if this is the first
-	 * dbm endpoint we about to configure.
-	 */
-	if (0 == dwc3_msm_configured_dbm_ep_num())
-		dwc3_msm_event_buffer_config(dwc->ev_buffs[0]->dma,
-					     dwc->ev_buffs[0]->length);
-
-	/*
 	 * Configure the DBM endpoint
 	 */
-	bam_pipe = (request->udc_priv & MSM_PIPE_ID_MASK);
+	bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK;
 	producer = ((request->udc_priv & MSM_PRODUCER) ? true : false);
 	disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false);
 	internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false);
@@ -752,6 +744,9 @@
 		return ret;
 	}
 
+	speed = dwc3_readl(dwc->regs, DWC3_DSTS) & DWC3_DSTS_CONNECTSPD;
+	dwc3_msm_write_reg(context->base, DBM_GEN_CFG, speed >> 2);
+
 	return 0;
 }
 
@@ -1551,7 +1546,12 @@
 	}
 
 	/* Reset the DBM */
-	dwc3_msm_dbm_soft_reset();
+	dwc3_msm_dbm_soft_reset(1);
+	usleep_range(1000, 1200);
+	dwc3_msm_dbm_soft_reset(0);
+
+	dwc3_msm_event_buffer_config(dwc3_readl(msm->base, DWC3_GEVNTADRLO(0)),
+		dwc3_readl(msm->base, DWC3_GEVNTSIZ(0)));
 
 	msm->otg_xceiv = usb_get_transceiver();
 	if (msm->otg_xceiv) {