[RESEND PATCH 6/7] dmaengine: sprd: Support DMA 2-stage transfer mode

2018-11-05 Thread Baolin Wang
From: Eric Long 

The Spreadtrum DMA controller supports channel 2-stage tansfer mode,
that means we can request 2 dma channels, one for source channel, and
another one for destination channel. Once the source channel's transaction
is done, it will trigger the destination channel's transaction automatically
by hardware signal.

Signed-off-by: Eric Long 
Signed-off-by: Baolin Wang 
---
 drivers/dma/sprd-dma.c   |   98 +-
 include/linux/dma/sprd-dma.h |   62 --
 2 files changed, 156 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c
index cefe42f..50d6569 100644
--- a/drivers/dma/sprd-dma.c
+++ b/drivers/dma/sprd-dma.c
@@ -36,6 +36,8 @@
 #define SPRD_DMA_GLB_CHN_EN_STS0x1c
 #define SPRD_DMA_GLB_DEBUG_STS 0x20
 #define SPRD_DMA_GLB_ARB_SEL_STS   0x24
+#define SPRD_DMA_GLB_2STAGE_GRP1   0x28
+#define SPRD_DMA_GLB_2STAGE_GRP2   0x2c
 #define SPRD_DMA_GLB_REQ_UID(uid)  (0x4 * ((uid) - 1))
 #define SPRD_DMA_GLB_REQ_UID_OFFSET0x2000
 
@@ -57,6 +59,18 @@
 #define SPRD_DMA_CHN_SRC_BLK_STEP  0x38
 #define SPRD_DMA_CHN_DES_BLK_STEP  0x3c
 
+/* SPRD_DMA_GLB_2STAGE_GRP register definition */
+#define SPRD_DMA_GLB_2STAGE_EN BIT(24)
+#define SPRD_DMA_GLB_CHN_INT_MASK  GENMASK(23, 20)
+#define SPRD_DMA_GLB_LIST_DONE_TRG BIT(19)
+#define SPRD_DMA_GLB_TRANS_DONE_TRGBIT(18)
+#define SPRD_DMA_GLB_BLOCK_DONE_TRGBIT(17)
+#define SPRD_DMA_GLB_FRAG_DONE_TRG BIT(16)
+#define SPRD_DMA_GLB_TRG_OFFSET16
+#define SPRD_DMA_GLB_DEST_CHN_MASK GENMASK(13, 8)
+#define SPRD_DMA_GLB_DEST_CHN_OFFSET   8
+#define SPRD_DMA_GLB_SRC_CHN_MASK  GENMASK(5, 0)
+
 /* SPRD_DMA_CHN_INTC register definition */
 #define SPRD_DMA_INT_MASK  GENMASK(4, 0)
 #define SPRD_DMA_INT_CLR_OFFSET24
@@ -118,6 +132,10 @@
 #define SPRD_DMA_SRC_TRSF_STEP_OFFSET  0
 #define SPRD_DMA_TRSF_STEP_MASKGENMASK(15, 0)
 
+/* define DMA channel mode & trigger mode mask */
+#define SPRD_DMA_CHN_MODE_MASK GENMASK(7, 0)
+#define SPRD_DMA_TRG_MODE_MASK GENMASK(7, 0)
+
 /* define the DMA transfer step type */
 #define SPRD_DMA_NONE_STEP 0
 #define SPRD_DMA_BYTE_STEP 1
@@ -170,6 +188,8 @@ struct sprd_dma_chn {
struct dma_slave_config slave_cfg;
u32 chn_num;
u32 dev_id;
+   enum sprd_dma_chn_mode  chn_mode;
+   enum sprd_dma_trg_mode  trg_mode;
struct sprd_dma_desc*cur_desc;
 };
 
@@ -206,6 +226,16 @@ static inline struct sprd_dma_desc 
*to_sprd_dma_desc(struct virt_dma_desc *vd)
return container_of(vd, struct sprd_dma_desc, vd);
 }
 
+static void sprd_dma_glb_update(struct sprd_dma_dev *sdev, u32 reg,
+   u32 mask, u32 val)
+{
+   u32 orig = readl(sdev->glb_base + reg);
+   u32 tmp;
+
+   tmp = (orig & ~mask) | val;
+   writel(tmp, sdev->glb_base + reg);
+}
+
 static void sprd_dma_chn_update(struct sprd_dma_chn *schan, u32 reg,
u32 mask, u32 val)
 {
@@ -389,6 +419,49 @@ static enum sprd_dma_req_mode sprd_dma_get_req_type(struct 
sprd_dma_chn *schan)
return (frag_reg >> SPRD_DMA_REQ_MODE_OFFSET) & SPRD_DMA_REQ_MODE_MASK;
 }
 
+static int sprd_dma_set_2stage_config(struct sprd_dma_chn *schan)
+{
+   struct sprd_dma_dev *sdev = to_sprd_dma_dev(>vc.chan);
+   u32 val, chn = schan->chn_num + 1;
+
+   switch (schan->chn_mode) {
+   case SPRD_DMA_SRC_CHN0:
+   val = chn & SPRD_DMA_GLB_SRC_CHN_MASK;
+   val |= BIT(schan->trg_mode - 1) << SPRD_DMA_GLB_TRG_OFFSET;
+   val |= SPRD_DMA_GLB_2STAGE_EN;
+   sprd_dma_glb_update(sdev, SPRD_DMA_GLB_2STAGE_GRP1, val, val);
+   break;
+
+   case SPRD_DMA_SRC_CHN1:
+   val = chn & SPRD_DMA_GLB_SRC_CHN_MASK;
+   val |= BIT(schan->trg_mode - 1) << SPRD_DMA_GLB_TRG_OFFSET;
+   val |= SPRD_DMA_GLB_2STAGE_EN;
+   sprd_dma_glb_update(sdev, SPRD_DMA_GLB_2STAGE_GRP2, val, val);
+   break;
+
+   case SPRD_DMA_DST_CHN0:
+   val = (chn << SPRD_DMA_GLB_DEST_CHN_OFFSET) &
+   SPRD_DMA_GLB_DEST_CHN_MASK;
+   val |= SPRD_DMA_GLB_2STAGE_EN;
+   sprd_dma_glb_update(sdev, SPRD_DMA_GLB_2STAGE_GRP1, val, val);
+   break;
+
+   case SPRD_DMA_DST_CHN1:
+   val = (chn << SPRD_DMA_GLB_DEST_CHN_OFFSET) &
+   SPRD_DMA_GLB_DEST_CHN_MASK;
+   val |= SPRD_DMA_GLB_2STAGE_EN;
+   sprd_dma_glb_update(sdev, SPRD_DMA_GLB_2STAGE_GRP2, val, val);
+   break;
+
+   default:
+   dev_err(sdev->dma_dev.dev, "invalid channel mode setting %d\n",
+   schan->chn_mode);
+   return -EINVAL;
+   }
+
+   

[RESEND PATCH 6/7] dmaengine: sprd: Support DMA 2-stage transfer mode

2018-11-05 Thread Baolin Wang
From: Eric Long 

The Spreadtrum DMA controller supports channel 2-stage tansfer mode,
that means we can request 2 dma channels, one for source channel, and
another one for destination channel. Once the source channel's transaction
is done, it will trigger the destination channel's transaction automatically
by hardware signal.

Signed-off-by: Eric Long 
Signed-off-by: Baolin Wang 
---
 drivers/dma/sprd-dma.c   |   98 +-
 include/linux/dma/sprd-dma.h |   62 --
 2 files changed, 156 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c
index cefe42f..50d6569 100644
--- a/drivers/dma/sprd-dma.c
+++ b/drivers/dma/sprd-dma.c
@@ -36,6 +36,8 @@
 #define SPRD_DMA_GLB_CHN_EN_STS0x1c
 #define SPRD_DMA_GLB_DEBUG_STS 0x20
 #define SPRD_DMA_GLB_ARB_SEL_STS   0x24
+#define SPRD_DMA_GLB_2STAGE_GRP1   0x28
+#define SPRD_DMA_GLB_2STAGE_GRP2   0x2c
 #define SPRD_DMA_GLB_REQ_UID(uid)  (0x4 * ((uid) - 1))
 #define SPRD_DMA_GLB_REQ_UID_OFFSET0x2000
 
@@ -57,6 +59,18 @@
 #define SPRD_DMA_CHN_SRC_BLK_STEP  0x38
 #define SPRD_DMA_CHN_DES_BLK_STEP  0x3c
 
+/* SPRD_DMA_GLB_2STAGE_GRP register definition */
+#define SPRD_DMA_GLB_2STAGE_EN BIT(24)
+#define SPRD_DMA_GLB_CHN_INT_MASK  GENMASK(23, 20)
+#define SPRD_DMA_GLB_LIST_DONE_TRG BIT(19)
+#define SPRD_DMA_GLB_TRANS_DONE_TRGBIT(18)
+#define SPRD_DMA_GLB_BLOCK_DONE_TRGBIT(17)
+#define SPRD_DMA_GLB_FRAG_DONE_TRG BIT(16)
+#define SPRD_DMA_GLB_TRG_OFFSET16
+#define SPRD_DMA_GLB_DEST_CHN_MASK GENMASK(13, 8)
+#define SPRD_DMA_GLB_DEST_CHN_OFFSET   8
+#define SPRD_DMA_GLB_SRC_CHN_MASK  GENMASK(5, 0)
+
 /* SPRD_DMA_CHN_INTC register definition */
 #define SPRD_DMA_INT_MASK  GENMASK(4, 0)
 #define SPRD_DMA_INT_CLR_OFFSET24
@@ -118,6 +132,10 @@
 #define SPRD_DMA_SRC_TRSF_STEP_OFFSET  0
 #define SPRD_DMA_TRSF_STEP_MASKGENMASK(15, 0)
 
+/* define DMA channel mode & trigger mode mask */
+#define SPRD_DMA_CHN_MODE_MASK GENMASK(7, 0)
+#define SPRD_DMA_TRG_MODE_MASK GENMASK(7, 0)
+
 /* define the DMA transfer step type */
 #define SPRD_DMA_NONE_STEP 0
 #define SPRD_DMA_BYTE_STEP 1
@@ -170,6 +188,8 @@ struct sprd_dma_chn {
struct dma_slave_config slave_cfg;
u32 chn_num;
u32 dev_id;
+   enum sprd_dma_chn_mode  chn_mode;
+   enum sprd_dma_trg_mode  trg_mode;
struct sprd_dma_desc*cur_desc;
 };
 
@@ -206,6 +226,16 @@ static inline struct sprd_dma_desc 
*to_sprd_dma_desc(struct virt_dma_desc *vd)
return container_of(vd, struct sprd_dma_desc, vd);
 }
 
+static void sprd_dma_glb_update(struct sprd_dma_dev *sdev, u32 reg,
+   u32 mask, u32 val)
+{
+   u32 orig = readl(sdev->glb_base + reg);
+   u32 tmp;
+
+   tmp = (orig & ~mask) | val;
+   writel(tmp, sdev->glb_base + reg);
+}
+
 static void sprd_dma_chn_update(struct sprd_dma_chn *schan, u32 reg,
u32 mask, u32 val)
 {
@@ -389,6 +419,49 @@ static enum sprd_dma_req_mode sprd_dma_get_req_type(struct 
sprd_dma_chn *schan)
return (frag_reg >> SPRD_DMA_REQ_MODE_OFFSET) & SPRD_DMA_REQ_MODE_MASK;
 }
 
+static int sprd_dma_set_2stage_config(struct sprd_dma_chn *schan)
+{
+   struct sprd_dma_dev *sdev = to_sprd_dma_dev(>vc.chan);
+   u32 val, chn = schan->chn_num + 1;
+
+   switch (schan->chn_mode) {
+   case SPRD_DMA_SRC_CHN0:
+   val = chn & SPRD_DMA_GLB_SRC_CHN_MASK;
+   val |= BIT(schan->trg_mode - 1) << SPRD_DMA_GLB_TRG_OFFSET;
+   val |= SPRD_DMA_GLB_2STAGE_EN;
+   sprd_dma_glb_update(sdev, SPRD_DMA_GLB_2STAGE_GRP1, val, val);
+   break;
+
+   case SPRD_DMA_SRC_CHN1:
+   val = chn & SPRD_DMA_GLB_SRC_CHN_MASK;
+   val |= BIT(schan->trg_mode - 1) << SPRD_DMA_GLB_TRG_OFFSET;
+   val |= SPRD_DMA_GLB_2STAGE_EN;
+   sprd_dma_glb_update(sdev, SPRD_DMA_GLB_2STAGE_GRP2, val, val);
+   break;
+
+   case SPRD_DMA_DST_CHN0:
+   val = (chn << SPRD_DMA_GLB_DEST_CHN_OFFSET) &
+   SPRD_DMA_GLB_DEST_CHN_MASK;
+   val |= SPRD_DMA_GLB_2STAGE_EN;
+   sprd_dma_glb_update(sdev, SPRD_DMA_GLB_2STAGE_GRP1, val, val);
+   break;
+
+   case SPRD_DMA_DST_CHN1:
+   val = (chn << SPRD_DMA_GLB_DEST_CHN_OFFSET) &
+   SPRD_DMA_GLB_DEST_CHN_MASK;
+   val |= SPRD_DMA_GLB_2STAGE_EN;
+   sprd_dma_glb_update(sdev, SPRD_DMA_GLB_2STAGE_GRP2, val, val);
+   break;
+
+   default:
+   dev_err(sdev->dma_dev.dev, "invalid channel mode setting %d\n",
+   schan->chn_mode);
+   return -EINVAL;
+   }
+
+