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(¶ms, 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, ¶ms);
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) {