Add some fixes and new feature for SPRD DMA
Subsystems (2)
PATCH RESEND 1/7 dmaengine: sprd: Remove direction usage from struct dma_slave_config
In reply to Baolin WangThe direction field of struct dma_slave_config was marked deprecated, thus remove the usage.
--- drivers/dma/sprd-dma.c | 3 --- 1 file changed, 3 deletions(-)
drivers/dma/sprd-dma.c +0 -3
@@ -847,9 +847,6 @@ static int sprd_dma_slave_config(struct dma_chan *chan,struct sprd_dma_chn *schan =to_sprd_dma_chan (chan);struct dma_slave_config *slave_cfg = &schan->slave_cfg; -if (!is_slave_direction (config->direction)) -return -EINVAL ; -memcpy (slave_cfg, config,sizeof (*config));return 0 ; }
PATCH RESEND 2/7 dmaengine: sprd: Get transfer residue depending on the transfer direction
In reply to Baolin WangFrom: Eric Long <[email protected]>
Add one field to save the transfer direction for struct sprd_dma_desc, which is used to get correct transfer residue depending on the transfer direction.
--- drivers/dma/sprd-dma.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
drivers/dma/sprd-dma.c +20 -1
@@ -159,6 +159,7 @@ struct sprd_dma_chn_hw {struct sprd_dma_desc {struct virt_dma_desc vd;struct sprd_dma_chn_hw chn_hw; +enum dma_transfer_direction dir; };/* dma channel description */
@@ -331,6 +332,17 @@ static void sprd_dma_stop_and_disable(struct sprd_dma_chn *schan)sprd_dma_disable_chn (schan); } +static unsigned long sprd_dma_get_src_addr (struct sprd_dma_chn *schan) +{ +unsigned long addr, addr_high; + + addr =readl (schan->chn_base +SPRD_DMA_CHN_SRC_ADDR ); + addr_high =readl (schan->chn_base +SPRD_DMA_CHN_WARP_PTR ) & +SPRD_DMA_HIGH_ADDR_MASK ; + +return addr | (addr_high <<SPRD_DMA_HIGH_ADDR_OFFSET ); +} +static unsigned long sprd_dma_get_dst_addr (struct sprd_dma_chn *schan) {unsigned long addr, addr_high;
@@ -534,7 +546,12 @@ static enum dma_status sprd_dma_tx_status(struct dma_chan *chan,else pos =0 ; }else if (schan->cur_desc && schan->cur_desc->vd.tx.cookie == cookie) { - pos =sprd_dma_get_dst_addr (schan); +struct sprd_dma_desc *sdesc =to_sprd_dma_desc (vd); + +if (sdesc->dir ==DMA_DEV_TO_MEM ) + pos =sprd_dma_get_dst_addr (schan); +else + pos =sprd_dma_get_src_addr (schan); }else { pos =0 ; }
@@ -804,6 +821,8 @@ static int sprd_dma_fill_linklist_desc(struct dma_chan *chan,if (!sdesc)return NULL ; + sdesc->dir = dir; +for_each_sg (sgl, sg, sglen, i) { len =sg_dma_len (sg);
PATCH RESEND 3/7 dmaengine: sprd: Fix the last link-list configuration
In reply to Baolin WangFrom: Eric Long <[email protected]>
We will pass sglen as 0 configure the last link-list configuration when filling the descriptor, which will cause the incorrect link-list configuration. Thus we should check if the sglen is 0 to configure the correct link-list configuration.
--- drivers/dma/sprd-dma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/dma/sprd-dma.c +2 -1
@@ -697,7 +697,8 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, hw->cfg |=SPRD_DMA_LINKLIST_EN ;/* link-list index */ - temp = (sg_index +1 ) % sglen; + temp = sglen ? (sg_index +1 ) % sglen :0 ; +/* Next link-list configuration's physical address offset */ temp = temp *sizeof (*hw) +SPRD_DMA_CHN_SRC_ADDR ;/*
PATCH RESEND 4/7 dmaengine: sprd: Set cur_desc as NULL when free or terminate one dma channel
In reply to Baolin WangFrom: Eric Long <[email protected]>
It will be failed to start one new transfer if the channel started one none interrupt transfer before, since we will only set the schan->cur_desc as NULL depending on the transfer interrupt now. Thus we should set schan->cur_desc as NULL when free or terminate one dma channel to avoid this issue.
--- drivers/dma/sprd-dma.c | 1 + 1 file changed, 1 insertion(+)
drivers/dma/sprd-dma.c +1 -0
@@ -439,6 +439,7 @@ static void sprd_dma_stop(struct sprd_dma_chn *schan)sprd_dma_stop_and_disable (schan);sprd_dma_unset_uid (schan);sprd_dma_clear_int (schan); + schan->cur_desc =NULL ; } static bool sprd_dma_check_trans_done(struct sprd_dma_desc *sdesc,
PATCH RESEND 5/7 dmaengine: sprd: Support DMA link-list cyclic callback
In reply to Baolin WangFrom: Eric Long <[email protected]>
The Spreadtrum DMA link-list mode is always one cyclic transfer, so we should clear the SPRD_DMA_LLIST_END flag for the link-list configuration. Moreover add cyclic callback support for the cyclic transfer.
--- drivers/dma/sprd-dma.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-)
drivers/dma/sprd-dma.c +14 -11
@@ -463,7 +463,7 @@ static irqreturn_t dma_irq_handle(int irq, void *dev_id)struct sprd_dma_desc *sdesc;enum sprd_dma_req_mode req_type;enum sprd_dma_int_type int_type; -bool trans_done = false; +bool trans_done = false, cyclic = false;u32 i;while (irq_status) {
@@ -478,13 +478,19 @@ static irqreturn_t dma_irq_handle(int irq, void *dev_id) sdesc = schan->cur_desc; -/* Check if the dma request descriptor is done. */ - trans_done =sprd_dma_check_trans_done (sdesc, int_type, - req_type); -if (trans_done == true) { -vchan_cookie_complete (&sdesc->vd); - schan->cur_desc =NULL ; -sprd_dma_start (schan); +/* cyclic mode schedule callback */ + cyclic = schan->linklist.phy_addr ? true : false; +if (cyclic == true) { +vchan_cyclic_callback (&sdesc->vd); + }else { +/* Check if the dma request descriptor is done. */ + trans_done =sprd_dma_check_trans_done (sdesc, int_type, + req_type); +if (trans_done == true) { +vchan_cookie_complete (&sdesc->vd); + schan->cur_desc =NULL ; +sprd_dma_start (schan); + } }spin_unlock (&schan->vc.lock); }
@@ -692,9 +698,6 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,/* link-list configuration */ if (schan->linklist.phy_addr) { -if (sg_index == sglen -1 ) - hw->frg_len |=SPRD_DMA_LLIST_END ; - hw->cfg |=SPRD_DMA_LINKLIST_EN ;/* link-list index */
PATCH RESEND 6/7 dmaengine: sprd: Support DMA 2-stage transfer mode
In reply to Baolin WangFrom: Eric Long <[email protected]>
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.
--- drivers/dma/sprd-dma.c | 98 +++++++++++++++++++++++++++++++++++++++++- include/linux/dma/sprd-dma.h | 62 ++++++++++++++++++++++++-- 2 files changed, 156 insertions(+), 4 deletions(-)
drivers/dma/sprd-dma.c +97 -1
@@ -36,6 +36,8 @@#define SPRD_DMA_GLB_CHN_EN_STS 0x1c#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_OFFSET 0x2000
@@ -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_TRG BIT(18) +#define SPRD_DMA_GLB_BLOCK_DONE_TRG BIT(17) +#define SPRD_DMA_GLB_FRAG_DONE_TRG BIT(16) +#define SPRD_DMA_GLB_TRG_OFFSET 16 +#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_OFFSET 24
@@ -118,6 +132,10 @@#define SPRD_DMA_SRC_TRSF_STEP_OFFSET 0#define SPRD_DMA_TRSF_STEP_MASK GENMASK(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 (&schan->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 ; + } + +return 0 ; +} +static void sprd_dma_set_chn_config (struct sprd_dma_chn *schan,struct sprd_dma_desc *sdesc) {
@@ -423,6 +496,13 @@ static void sprd_dma_start(struct sprd_dma_chn *schan) schan->cur_desc =to_sprd_dma_desc (vd);/* +* Set 2-stage configuration if the channel starts one 2-stage +* transfer. +*/ +if (schan->chn_mode &&sprd_dma_set_2stage_config (schan)) +return ; + +/* * Copy the DMA configuration from DMA descriptor to this hardware * channel. */
@@ -617,6 +697,7 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, {struct sprd_dma_dev *sdev =to_sprd_dma_dev (chan);struct sprd_dma_chn *schan =to_sprd_dma_chan (chan); +enum sprd_dma_chn_mode chn_mode = schan->chn_mode;u32 req_mode = (flags >>SPRD_DMA_REQ_SHIFT ) &SPRD_DMA_REQ_MODE_MASK ;u32 int_mode = flags &SPRD_DMA_INT_MASK ;int src_datawidth, dst_datawidth, src_step, dst_step;
@@ -628,7 +709,16 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,dev_err (sdev->dma_dev.dev,"invalid source step\n" );return src_step; } - dst_step =SPRD_DMA_NONE_STEP ; + +/* +* For 2-stage transfer, destination channel step can not be 0, +* since destination device is AON IRAM. +*/ +if (chn_mode ==SPRD_DMA_DST_CHN0 || + chn_mode ==SPRD_DMA_DST_CHN1 ) + dst_step = src_step; +else + dst_step =SPRD_DMA_NONE_STEP ; }else { dst_step =sprd_dma_get_step (slave_cfg->dst_addr_width);if (dst_step <0 ) {
@@ -855,6 +945,12 @@ static int sprd_dma_fill_linklist_desc(struct dma_chan *chan, } } +/* Set channel mode and trigger mode for 2-stage transfer */ + schan->chn_mode = + (flags >>SPRD_DMA_CHN_MODE_SHIFT ) &SPRD_DMA_CHN_MODE_MASK ; + schan->trg_mode = + (flags >>SPRD_DMA_TRG_MODE_SHIFT ) &SPRD_DMA_TRG_MODE_MASK ; + ret =sprd_dma_fill_desc (chan, &sdesc->chn_hw,0 ,0 , src, dst, len, dir, flags, slave_cfg);if (ret) {
include/linux/dma/sprd-dma.h +59 -3
68 lines not on this page · raw message
PATCH RESEND 7/7 dmaengine: sprd: Add me as one of the module authors
In reply to Baolin WangFrom: Eric Long <[email protected]>
Add me as one of the module authors.
--- drivers/dma/sprd-dma.c | 1 + 1 file changed, 1 insertion(+)
drivers/dma/sprd-dma.c +1 -0
@@ -1226,4 +1226,5 @@ static int __maybe_unused sprd_dma_runtime_resume(struct device *dev)MODULE_LICENSE ("GPL v2" );MODULE_DESCRIPTION ("DMA driver for Spreadtrum" );MODULE_AUTHOR ("Baolin Wang <[email protected]>" ); +MODULE_AUTHOR ("Eric Long <[email protected]>" );MODULE_ALIAS ("platform:sprd-dma" );
cover Add some fixes and new feature for SPRD DMA
This patchset removes the direction usage from struct dma_slave_config, and add one new field to save the direction. It also fixes some issues for link-list transfer. Moreover this patchset adds new 2-stage transfer support for our DMA.
Baolin Wang (1):
dmaengine: sprd: Remove direction usage from struct dma_slave_config
Eric Long (6):
dmaengine: sprd: Get transfer residue depending on the transfer
direction
dmaengine: sprd: Fix the last link-list configuration
dmaengine: sprd: Set cur_desc as NULL when free or terminate one dma
channel
dmaengine: sprd: Support DMA link-list cyclic callback
dmaengine: sprd: Support DMA 2-stage transfer mode
dmaengine: sprd: Add me as one of the module authors
drivers/dma/sprd-dma.c | 152 +++++++++++++++++++++++++++++++++++++----- include/linux/dma/sprd-dma.h | 62 ++++++++++++++++- 2 files changed, 194 insertions(+), 20 deletions(-)
Signature · 1 line
1.7.9.5
Hi Vinod,
Quoted 5 lines · Baolin Wang
This patchset removes the direction usage from struct
dma_slave_config, and add one new field to save the direction. It also fixes some issues for link-list transfer. Moreover this patchset adds new 2-stage transfer support for our DMA.
Any comments for this patch set? Thanks.
Quoted 14 lines
Baolin Wang (1):
dmaengine: sprd: Remove direction usage from structdma_slave_configEric Long (6):
dmaengine: sprd: Get transfer residue depending on the transfer
direction
dmaengine: sprd: Fix the last link-list configuration
dmaengine: sprd: Setcur_descas NULL when free or terminate one dma
channel
dmaengine: sprd: Support DMA link-list cyclic callback
dmaengine: sprd: Support DMA 2-stage transfer mode
dmaengine: sprd: Add me as one of the module authors
Quoted 7 lines
drivers/dma/sprd-dma.c | 152 +++++++++++++++++++++++++++++++++++++----- include/linux/dma/sprd-dma.h | 62 ++++++++++++++++- 2 files changed, 194 insertions(+), 20 deletions(-)--
1.7.9.5
--
Baolin Wang
Best Regards
Quoted 4 lines · Baolin Wang
This patchset removes the direction usage from struct
dma_slave_config, and add one new field to save the direction. It also fixes some issues for link-list transfer. Moreover this patchset adds new 2-stage transfer support for our DMA.
Applied, thanks
Signature · 1 line
~Vinod