From: Vahram Aharonyan <vahr...@synopsys.com>

Add dwc2_gadget_get_desc_params() function to define descriptor entry
parameters based on the endpoint type.

Add dwc2_gadget_config_nonisoc_xfer_ddma() function, which programs DDMA
chain entries with corresponding values based on the received DMA buffer
and transfer length in case of non-isochronous endpoint. Isochronous
endpoints' DMA descriptors will be filled separately.

Add dwc2_gadget_get_xfersize_ddma() function to iterate over DDMA chain
and get info on bytes remaining in descriptor status field after
transfer complete.

Signed-off-by: Vahram Aharonyan <vahr...@synopsys.com>
Signed-off-by: John Youn <johny...@synopsys.com>
---
 drivers/usb/dwc2/gadget.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 138 insertions(+)

diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 3264375..40a6c57 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -627,6 +627,114 @@ static unsigned int dwc2_gadget_get_chain_limit(struct 
dwc2_hsotg_ep *hs_ep)
        return maxsize;
 }
 
+/*
+ * dwc2_gadget_get_desc_params - get DMA descriptor parameters.
+ * @hs_ep: The endpoint
+ * @mask: RX/TX bytes mask to be defined
+ *
+ * Returns maximum data payload for one descriptor after analyzing endpoint
+ * characteristics.
+ * DMA descriptor transfer bytes limit depends on EP type:
+ * Control out - MPS,
+ * Isochronous - descriptor rx/tx bytes bitfield limit,
+ * Control In/Bulk/Interrupt - multiple of mps. This will allow to not
+ * have concatenations from various descriptors within one packet.
+ *
+ * Selects corresponding mask for RX/TX bytes as well.
+ */
+static u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask)
+{
+       u32 mps = hs_ep->ep.maxpacket;
+       int dir_in = hs_ep->dir_in;
+       u32 desc_size = 0;
+
+       if (!hs_ep->index && !dir_in) {
+               desc_size = mps;
+               *mask = DEV_DMA_NBYTES_MASK;
+       } else if (hs_ep->isochronous) {
+               if (dir_in) {
+                       desc_size = DEV_DMA_ISOC_TX_NBYTES_LIMIT;
+                       *mask = DEV_DMA_ISOC_TX_NBYTES_MASK;
+               } else {
+                       desc_size = DEV_DMA_ISOC_RX_NBYTES_LIMIT;
+                       *mask = DEV_DMA_ISOC_RX_NBYTES_MASK;
+               }
+       } else {
+               desc_size = DEV_DMA_NBYTES_LIMIT;
+               *mask = DEV_DMA_NBYTES_MASK;
+
+               /* Round down desc_size to be mps multiple */
+               desc_size -= desc_size % mps;
+       }
+
+       return desc_size;
+}
+
+/*
+ * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain.
+ * @hs_ep: The endpoint
+ * @dma_buff: DMA address to use
+ * @len: Length of the transfer
+ *
+ * This function will iterate over descriptor chain and fill its entries
+ * with corresponding information based on transfer data.
+ */
+static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep,
+                                                dma_addr_t dma_buff,
+                                                unsigned int len)
+{
+       struct dwc2_hsotg *hsotg = hs_ep->parent;
+       int dir_in = hs_ep->dir_in;
+       struct dwc2_dma_desc *desc = hs_ep->desc_list;
+       u32 mps = hs_ep->ep.maxpacket;
+       u32 maxsize = 0;
+       u32 offset = 0;
+       u32 mask = 0;
+       int i;
+
+       maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask);
+
+       hs_ep->desc_count = (len / maxsize) +
+                               ((len % maxsize) ? 1 : 0);
+       if (len == 0)
+               hs_ep->desc_count = 1;
+
+       for (i = 0; i < hs_ep->desc_count; ++i) {
+               desc->status = 0;
+               desc->status |= (DEV_DMA_BUFF_STS_HBUSY
+                                << DEV_DMA_BUFF_STS_SHIFT);
+
+               if (len > maxsize) {
+                       if (!hs_ep->index && !dir_in)
+                               desc->status |= (DEV_DMA_L | DEV_DMA_IOC);
+
+                       desc->status |= (maxsize <<
+                                               DEV_DMA_NBYTES_SHIFT & mask);
+                       desc->buf = dma_buff + offset;
+
+                       len -= maxsize;
+                       offset += maxsize;
+               } else {
+                       desc->status |= (DEV_DMA_L | DEV_DMA_IOC);
+
+                       if (dir_in)
+                               desc->status |= (len % mps) ? DEV_DMA_SHORT :
+                                       ((hs_ep->send_zlp) ? DEV_DMA_SHORT : 0);
+                       if (len > maxsize)
+                               dev_err(hsotg->dev, "wrong len %d\n", len);
+
+                       desc->status |=
+                               len << DEV_DMA_NBYTES_SHIFT & mask;
+                       desc->buf = dma_buff + offset;
+               }
+
+               desc->status &= ~DEV_DMA_BUFF_STS_MASK;
+               desc->status |= (DEV_DMA_BUFF_STS_HREADY
+                                << DEV_DMA_BUFF_STS_SHIFT);
+               desc++;
+       }
+}
+
 /**
  * dwc2_hsotg_start_req - start a USB request from an endpoint's queue
  * @hsotg: The controller state.
@@ -1707,6 +1815,36 @@ static void dwc2_hsotg_change_ep_iso_parity(struct 
dwc2_hsotg *hsotg,
        dwc2_writel(ctrl, hsotg->regs + epctl_reg);
 }
 
+/*
+ * dwc2_gadget_get_xfersize_ddma - get transferred bytes amount from desc
+ * @hs_ep - The endpoint on which transfer went
+ *
+ * Iterate over endpoints descriptor chain and get info on bytes remained
+ * in DMA descriptors after transfer has completed. Used for non isoc EPs.
+ */
+static unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep)
+{
+       struct dwc2_hsotg *hsotg = hs_ep->parent;
+       unsigned int bytes_rem = 0;
+       struct dwc2_dma_desc *desc = hs_ep->desc_list;
+       int i;
+       u32 status;
+
+       if (!desc)
+               return -EINVAL;
+
+       for (i = 0; i < hs_ep->desc_count; ++i) {
+               status = desc->status;
+               bytes_rem += status & DEV_DMA_NBYTES_MASK;
+
+               if (status & DEV_DMA_STS_MASK)
+                       dev_err(hsotg->dev, "descriptor %d closed with %x\n",
+                               i, status & DEV_DMA_STS_MASK);
+       }
+
+       return bytes_rem;
+}
+
 /**
  * dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO
  * @hsotg: The device instance
-- 
2.10.0

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to