dmaengine: qcom_hidma: introduce memset support
authorSinan Kaya <okaya@codeaurora.org>
Fri, 30 Jun 2017 02:30:57 +0000 (22:30 -0400)
committerVinod Koul <vinod.koul@intel.com>
Wed, 19 Jul 2017 04:03:21 +0000 (09:33 +0530)
HIDMA HW supports memset operation in addition to memcpy.
Since the memset API is present on the kernel now, bring the
memset feature into life.

The descriptor format is the same for both memcpy and memset.
Type of the descriptor is 4 when memset is requested.
The lowest 8 bits of the source DMA argument is used as a
fill pattern.

Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
drivers/dma/qcom/hidma.c
drivers/dma/qcom/hidma.h
drivers/dma/qcom/hidma_ll.c

index 34fb6afd229b1c61812aa9ccc50b9e6df5a29f0b..e3669850aef4ce78dbae0f97d03a87393a30c5fa 100644 (file)
@@ -411,7 +411,40 @@ hidma_prep_dma_memcpy(struct dma_chan *dmach, dma_addr_t dest, dma_addr_t src,
                return NULL;
 
        hidma_ll_set_transfer_params(mdma->lldev, mdesc->tre_ch,
-                                    src, dest, len, flags);
+                                    src, dest, len, flags,
+                                    HIDMA_TRE_MEMCPY);
+
+       /* Place descriptor in prepared list */
+       spin_lock_irqsave(&mchan->lock, irqflags);
+       list_add_tail(&mdesc->node, &mchan->prepared);
+       spin_unlock_irqrestore(&mchan->lock, irqflags);
+
+       return &mdesc->desc;
+}
+
+static struct dma_async_tx_descriptor *
+hidma_prep_dma_memset(struct dma_chan *dmach, dma_addr_t dest, int value,
+               size_t len, unsigned long flags)
+{
+       struct hidma_chan *mchan = to_hidma_chan(dmach);
+       struct hidma_desc *mdesc = NULL;
+       struct hidma_dev *mdma = mchan->dmadev;
+       unsigned long irqflags;
+
+       /* Get free descriptor */
+       spin_lock_irqsave(&mchan->lock, irqflags);
+       if (!list_empty(&mchan->free)) {
+               mdesc = list_first_entry(&mchan->free, struct hidma_desc, node);
+               list_del(&mdesc->node);
+       }
+       spin_unlock_irqrestore(&mchan->lock, irqflags);
+
+       if (!mdesc)
+               return NULL;
+
+       hidma_ll_set_transfer_params(mdma->lldev, mdesc->tre_ch,
+                                    value, dest, len, flags,
+                                    HIDMA_TRE_MEMSET);
 
        /* Place descriptor in prepared list */
        spin_lock_irqsave(&mchan->lock, irqflags);
@@ -776,6 +809,7 @@ static int hidma_probe(struct platform_device *pdev)
        pm_runtime_get_sync(dmadev->ddev.dev);
 
        dma_cap_set(DMA_MEMCPY, dmadev->ddev.cap_mask);
+       dma_cap_set(DMA_MEMSET, dmadev->ddev.cap_mask);
        if (WARN_ON(!pdev->dev.dma_mask)) {
                rc = -ENXIO;
                goto dmafree;
@@ -786,6 +820,7 @@ static int hidma_probe(struct platform_device *pdev)
        dmadev->dev_trca = trca;
        dmadev->trca_resource = trca_resource;
        dmadev->ddev.device_prep_dma_memcpy = hidma_prep_dma_memcpy;
+       dmadev->ddev.device_prep_dma_memset = hidma_prep_dma_memset;
        dmadev->ddev.device_alloc_chan_resources = hidma_alloc_chan_resources;
        dmadev->ddev.device_free_chan_resources = hidma_free_chan_resources;
        dmadev->ddev.device_tx_status = hidma_tx_status;
index 41e0aa283828e2e50f2b424eee45225a2ee40181..5f9966e82c0bc33dd0df45749190059322c097e9 100644 (file)
 #define HIDMA_TRE_DEST_LOW_IDX         4
 #define HIDMA_TRE_DEST_HI_IDX          5
 
+enum tre_type {
+       HIDMA_TRE_MEMCPY = 3,
+       HIDMA_TRE_MEMSET = 4,
+};
+
 struct hidma_tre {
        atomic_t allocated;             /* if this channel is allocated     */
        bool queued;                    /* flag whether this is pending     */
@@ -150,7 +155,7 @@ void hidma_ll_start(struct hidma_lldev *llhndl);
 int hidma_ll_disable(struct hidma_lldev *lldev);
 int hidma_ll_enable(struct hidma_lldev *llhndl);
 void hidma_ll_set_transfer_params(struct hidma_lldev *llhndl, u32 tre_ch,
-       dma_addr_t src, dma_addr_t dest, u32 len, u32 flags);
+       dma_addr_t src, dma_addr_t dest, u32 len, u32 flags, u32 txntype);
 void hidma_ll_setup_irq(struct hidma_lldev *lldev, bool msi);
 int hidma_ll_setup(struct hidma_lldev *lldev);
 struct hidma_lldev *hidma_ll_init(struct device *dev, u32 max_channels,
index 1530a661518d7f2d41b7fe029377384b09e71271..4999e266b2dec83ea3f98fccb28aa08e08595a9b 100644 (file)
@@ -105,10 +105,6 @@ enum ch_state {
        HIDMA_CH_STOPPED = 4,
 };
 
-enum tre_type {
-       HIDMA_TRE_MEMCPY = 3,
-};
-
 enum err_code {
        HIDMA_EVRE_STATUS_COMPLETE = 1,
        HIDMA_EVRE_STATUS_ERROR = 4,
@@ -174,8 +170,7 @@ int hidma_ll_request(struct hidma_lldev *lldev, u32 sig, const char *dev_name,
        tre->err_info = 0;
        tre->lldev = lldev;
        tre_local = &tre->tre_local[0];
-       tre_local[HIDMA_TRE_CFG_IDX] = HIDMA_TRE_MEMCPY;
-       tre_local[HIDMA_TRE_CFG_IDX] |= (lldev->chidx & 0xFF) << 8;
+       tre_local[HIDMA_TRE_CFG_IDX] = (lldev->chidx & 0xFF) << 8;
        tre_local[HIDMA_TRE_CFG_IDX] |= BIT(16);        /* set IEOB */
        *tre_ch = i;
        if (callback)
@@ -607,7 +602,7 @@ int hidma_ll_disable(struct hidma_lldev *lldev)
 
 void hidma_ll_set_transfer_params(struct hidma_lldev *lldev, u32 tre_ch,
                                  dma_addr_t src, dma_addr_t dest, u32 len,
-                                 u32 flags)
+                                 u32 flags, u32 txntype)
 {
        struct hidma_tre *tre;
        u32 *tre_local;
@@ -626,6 +621,8 @@ void hidma_ll_set_transfer_params(struct hidma_lldev *lldev, u32 tre_ch,
        }
 
        tre_local = &tre->tre_local[0];
+       tre_local[HIDMA_TRE_CFG_IDX] &= ~GENMASK(7, 0);
+       tre_local[HIDMA_TRE_CFG_IDX] |= txntype;
        tre_local[HIDMA_TRE_LEN_IDX] = len;
        tre_local[HIDMA_TRE_SRC_LOW_IDX] = lower_32_bits(src);
        tre_local[HIDMA_TRE_SRC_HI_IDX] = upper_32_bits(src);