summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJia Wang <wangjia@ultrarisc.com>2026-09-02 17:26:14 +0800
committerVinod Koul <vkoul@kernel.org>2026-09-10 19:27:22 +0530
commita72f75e1f5552df8765920b678a9037b7f31a91c (patch)
treeb670c1ea376a387eaf1056243d50d89bf4027645
parent2a9013c20c46216b92ff09e2283b5244a91c59da (diff)
downloadlinux-next-a72f75e1f5552df8765920b678a9037b7f31a91c.tar.gz
linux-next-a72f75e1f5552df8765920b678a9037b7f31a91c.zip
dmaengine: dw-axi-dmac: Use bitfield helpers for registers
The driver open-codes several channel configuration and descriptor control bitfield writes with left shifts. Define masks for those fields and use FIELD_PREP() when programming the registers. Valid field values keep the same encoding. FIELD_PREP() confines values to their respective fields, but does not validate handshake numbers supplied through DMA specifiers. Suggested-by: Frank Li <Frank.Li@nxp.com> Signed-off-by: Jia Wang <wangjia@ultrarisc.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Link: https://patch.msgid.link/20260902-dma-fix-v3-4-414c6449fbcc@ultrarisc.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
-rw-r--r--drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c75
-rw-r--r--drivers/dma/dw-axi-dmac/dw-axi-dmac.h44
2 files changed, 61 insertions, 58 deletions
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index 2d7d49017002..8baf303a314d 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -7,6 +7,7 @@
* Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
*/
+#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -101,23 +102,25 @@ static inline void axi_chan_config_write(struct axi_dma_chan *chan,
{
u32 cfg_lo, cfg_hi;
- cfg_lo = (config->dst_multblk_type << CH_CFG_L_DST_MULTBLK_TYPE_POS |
- config->src_multblk_type << CH_CFG_L_SRC_MULTBLK_TYPE_POS);
if (chan->chip->dw->hdata->reg_map_8_channels &&
!chan->chip->dw->hdata->use_cfg2) {
- cfg_hi = config->tt_fc << CH_CFG_H_TT_FC_POS |
- config->hs_sel_src << CH_CFG_H_HS_SEL_SRC_POS |
- config->hs_sel_dst << CH_CFG_H_HS_SEL_DST_POS |
- config->src_per << CH_CFG_H_SRC_PER_POS |
- config->dst_per << CH_CFG_H_DST_PER_POS |
- config->prior << CH_CFG_H_PRIORITY_POS;
+ cfg_lo = FIELD_PREP(CH_CFG_L_DST_MULTBLK_TYPE, config->dst_multblk_type) |
+ FIELD_PREP(CH_CFG_L_SRC_MULTBLK_TYPE, config->src_multblk_type);
+ cfg_hi = FIELD_PREP(CH_CFG_H_TT_FC, config->tt_fc) |
+ FIELD_PREP(CH_CFG_H_HS_SEL_SRC, config->hs_sel_src) |
+ FIELD_PREP(CH_CFG_H_HS_SEL_DST, config->hs_sel_dst) |
+ FIELD_PREP(CH_CFG_H_SRC_PER, config->src_per) |
+ FIELD_PREP(CH_CFG_H_DST_PER, config->dst_per) |
+ FIELD_PREP(CH_CFG_H_PRIORITY, config->prior);
} else {
- cfg_lo |= config->src_per << CH_CFG2_L_SRC_PER_POS |
- config->dst_per << CH_CFG2_L_DST_PER_POS;
- cfg_hi = config->tt_fc << CH_CFG2_H_TT_FC_POS |
- config->hs_sel_src << CH_CFG2_H_HS_SEL_SRC_POS |
- config->hs_sel_dst << CH_CFG2_H_HS_SEL_DST_POS |
- config->prior << CH_CFG2_H_PRIORITY_POS;
+ cfg_lo = FIELD_PREP(CH_CFG_L_DST_MULTBLK_TYPE, config->dst_multblk_type) |
+ FIELD_PREP(CH_CFG_L_SRC_MULTBLK_TYPE, config->src_multblk_type) |
+ FIELD_PREP(CH_CFG2_L_SRC_PER, config->src_per) |
+ FIELD_PREP(CH_CFG2_L_DST_PER, config->dst_per);
+ cfg_hi = FIELD_PREP(CH_CFG2_H_TT_FC, config->tt_fc) |
+ FIELD_PREP(CH_CFG2_H_HS_SEL_SRC, config->hs_sel_src) |
+ FIELD_PREP(CH_CFG2_H_HS_SEL_DST, config->hs_sel_dst) |
+ FIELD_PREP(CH_CFG2_H_PRIORITY, config->prior);
}
axi_chan_iowrite32(chan, CH_CFG_L, cfg_lo);
axi_chan_iowrite32(chan, CH_CFG_H, cfg_hi);
@@ -677,19 +680,19 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
case DMA_MEM_TO_DEV:
reg_width = __ffs(chan->config.dst_addr_width);
device_addr = chan->config.dst_addr;
- ctllo = reg_width << CH_CTL_L_DST_WIDTH_POS |
- mem_width << CH_CTL_L_SRC_WIDTH_POS |
- DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_DST_INC_POS |
- DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS;
+ ctllo = FIELD_PREP(CH_CTL_L_DST_WIDTH, reg_width) |
+ FIELD_PREP(CH_CTL_L_SRC_WIDTH, mem_width) |
+ FIELD_PREP(CH_CTL_L_DST_INC, DWAXIDMAC_CH_CTL_L_NOINC) |
+ FIELD_PREP(CH_CTL_L_SRC_INC, DWAXIDMAC_CH_CTL_L_INC);
block_ts = len >> mem_width;
break;
case DMA_DEV_TO_MEM:
reg_width = __ffs(chan->config.src_addr_width);
device_addr = chan->config.src_addr;
- ctllo = reg_width << CH_CTL_L_SRC_WIDTH_POS |
- mem_width << CH_CTL_L_DST_WIDTH_POS |
- DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
- DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS;
+ ctllo = FIELD_PREP(CH_CTL_L_SRC_WIDTH, reg_width) |
+ FIELD_PREP(CH_CTL_L_DST_WIDTH, mem_width) |
+ FIELD_PREP(CH_CTL_L_DST_INC, DWAXIDMAC_CH_CTL_L_INC) |
+ FIELD_PREP(CH_CTL_L_SRC_INC, DWAXIDMAC_CH_CTL_L_NOINC);
block_ts = len >> reg_width;
break;
default:
@@ -708,8 +711,8 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
if (chan->chip->dw->hdata->restrict_axi_burst_len) {
burst_len = chan->chip->dw->hdata->axi_rw_burst_len - 1;
ctlhi |= CH_CTL_H_ARLEN_EN | CH_CTL_H_AWLEN_EN |
- burst_len << CH_CTL_H_ARLEN_POS |
- burst_len << CH_CTL_H_AWLEN_POS;
+ FIELD_PREP(CH_CTL_H_ARLEN, burst_len) |
+ FIELD_PREP(CH_CTL_H_AWLEN, burst_len);
}
hw_desc->lli->ctl_hi = cpu_to_le32(ctlhi);
@@ -724,8 +727,8 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1);
- ctllo |= DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
- DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS;
+ ctllo |= FIELD_PREP(CH_CTL_L_DST_MSIZE, DWAXIDMAC_BURST_TRANS_LEN_4) |
+ FIELD_PREP(CH_CTL_L_SRC_MSIZE, DWAXIDMAC_BURST_TRANS_LEN_4);
hw_desc->lli->ctl_lo = cpu_to_le32(ctllo);
set_desc_src_master(hw_desc);
@@ -977,19 +980,19 @@ dma_chan_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dst_adr,
if (chan->chip->dw->hdata->restrict_axi_burst_len) {
u32 burst_len = chan->chip->dw->hdata->axi_rw_burst_len - 1;
- reg |= (CH_CTL_H_ARLEN_EN |
- burst_len << CH_CTL_H_ARLEN_POS |
- CH_CTL_H_AWLEN_EN |
- burst_len << CH_CTL_H_AWLEN_POS);
+ reg |= CH_CTL_H_ARLEN_EN |
+ FIELD_PREP(CH_CTL_H_ARLEN, burst_len) |
+ CH_CTL_H_AWLEN_EN |
+ FIELD_PREP(CH_CTL_H_AWLEN, burst_len);
}
hw_desc->lli->ctl_hi = cpu_to_le32(reg);
- reg = (DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
- DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS |
- xfer_width << CH_CTL_L_DST_WIDTH_POS |
- xfer_width << CH_CTL_L_SRC_WIDTH_POS |
- DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
- DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS);
+ reg = FIELD_PREP(CH_CTL_L_DST_MSIZE, DWAXIDMAC_BURST_TRANS_LEN_4) |
+ FIELD_PREP(CH_CTL_L_SRC_MSIZE, DWAXIDMAC_BURST_TRANS_LEN_4) |
+ FIELD_PREP(CH_CTL_L_DST_WIDTH, xfer_width) |
+ FIELD_PREP(CH_CTL_L_SRC_WIDTH, xfer_width) |
+ FIELD_PREP(CH_CTL_L_DST_INC, DWAXIDMAC_CH_CTL_L_INC) |
+ FIELD_PREP(CH_CTL_L_SRC_INC, DWAXIDMAC_CH_CTL_L_INC);
hw_desc->lli->ctl_lo = cpu_to_le32(reg);
set_desc_src_master(hw_desc);
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
index da706bff3f12..ec83acd12a9b 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
@@ -233,9 +233,9 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan)
/* CH_CTL_H */
#define CH_CTL_H_ARLEN_EN BIT(6)
-#define CH_CTL_H_ARLEN_POS 7
+#define CH_CTL_H_ARLEN GENMASK(14, 7)
#define CH_CTL_H_AWLEN_EN BIT(15)
-#define CH_CTL_H_AWLEN_POS 16
+#define CH_CTL_H_AWLEN GENMASK(23, 16)
enum {
DWAXIDMAC_ARWLEN_1 = 0,
@@ -257,8 +257,8 @@ enum {
/* CH_CTL_L */
#define CH_CTL_L_LAST_WRITE_EN BIT(30)
-#define CH_CTL_L_DST_MSIZE_POS 18
-#define CH_CTL_L_SRC_MSIZE_POS 14
+#define CH_CTL_L_DST_MSIZE GENMASK(21, 18)
+#define CH_CTL_L_SRC_MSIZE GENMASK(17, 14)
enum {
DWAXIDMAC_BURST_TRANS_LEN_1 = 0,
@@ -273,11 +273,11 @@ enum {
DWAXIDMAC_BURST_TRANS_LEN_1024
};
-#define CH_CTL_L_DST_WIDTH_POS 11
-#define CH_CTL_L_SRC_WIDTH_POS 8
+#define CH_CTL_L_DST_WIDTH GENMASK(13, 11)
+#define CH_CTL_L_SRC_WIDTH GENMASK(10, 8)
-#define CH_CTL_L_DST_INC_POS 6
-#define CH_CTL_L_SRC_INC_POS 4
+#define CH_CTL_L_DST_INC BIT(6)
+#define CH_CTL_L_SRC_INC BIT(4)
enum {
DWAXIDMAC_CH_CTL_L_INC = 0,
DWAXIDMAC_CH_CTL_L_NOINC
@@ -287,17 +287,17 @@ enum {
#define CH_CTL_L_SRC_MAST BIT(0)
/* CH_CFG_H */
-#define CH_CFG_H_PRIORITY_POS 17
-#define CH_CFG_H_DST_PER_POS 12
-#define CH_CFG_H_SRC_PER_POS 7
-#define CH_CFG_H_HS_SEL_DST_POS 4
-#define CH_CFG_H_HS_SEL_SRC_POS 3
+#define CH_CFG_H_PRIORITY GENMASK(19, 17)
+#define CH_CFG_H_DST_PER GENMASK(15, 12)
+#define CH_CFG_H_SRC_PER GENMASK(10, 7)
+#define CH_CFG_H_HS_SEL_DST BIT(4)
+#define CH_CFG_H_HS_SEL_SRC BIT(3)
enum {
DWAXIDMAC_HS_SEL_HW = 0,
DWAXIDMAC_HS_SEL_SW
};
-#define CH_CFG_H_TT_FC_POS 0
+#define CH_CFG_H_TT_FC GENMASK(2, 0)
enum {
DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC = 0,
DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC,
@@ -310,8 +310,8 @@ enum {
};
/* CH_CFG_L */
-#define CH_CFG_L_DST_MULTBLK_TYPE_POS 2
-#define CH_CFG_L_SRC_MULTBLK_TYPE_POS 0
+#define CH_CFG_L_DST_MULTBLK_TYPE GENMASK(3, 2)
+#define CH_CFG_L_SRC_MULTBLK_TYPE GENMASK(1, 0)
enum {
DWAXIDMAC_MBLK_TYPE_CONTIGUOUS = 0,
DWAXIDMAC_MBLK_TYPE_RELOAD,
@@ -320,13 +320,13 @@ enum {
};
/* CH_CFG2 */
-#define CH_CFG2_L_SRC_PER_POS 4
-#define CH_CFG2_L_DST_PER_POS 11
+#define CH_CFG2_L_SRC_PER GENMASK(9, 4)
+#define CH_CFG2_L_DST_PER GENMASK(16, 11)
-#define CH_CFG2_H_TT_FC_POS 0
-#define CH_CFG2_H_HS_SEL_SRC_POS 3
-#define CH_CFG2_H_HS_SEL_DST_POS 4
-#define CH_CFG2_H_PRIORITY_POS 15
+#define CH_CFG2_H_TT_FC GENMASK(2, 0)
+#define CH_CFG2_H_HS_SEL_SRC BIT(3)
+#define CH_CFG2_H_HS_SEL_DST BIT(4)
+#define CH_CFG2_H_PRIORITY GENMASK(19, 15)
/**
* DW AXI DMA channel interrupts