Skip to content

Commit 8243516

Browse files
pandithnvinodkoul
authored andcommitted
dmaengine: dw-axi-dmac: support DMAX_NUM_CHANNELS > 8
Added support for DMA controller with more than 8 channels. DMAC register map changes based on number of channels. Enabling DMAC channel: DMAC_CHENREG has to be used when number of channels <= 8 DMAC_CHENREG2 has to be used when number of channels > 8 Configuring DMA channel: CHx_CFG has to be used when number of channels <= 8 CHx_CFG2 has to be used when number of channels > 8 Suspending and resuming channel: DMAC_CHENREG has to be used when number of channels <= 8 DMAC_CHSUSPREG has to be used for suspending a channel > 8 Signed-off-by: Pandith N <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent af229d2 commit 8243516

File tree

2 files changed

+109
-31
lines changed

2 files changed

+109
-31
lines changed

drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c

Lines changed: 75 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,32 @@ axi_chan_iowrite64(struct axi_dma_chan *chan, u32 reg, u64 val)
7979
iowrite32(upper_32_bits(val), chan->chan_regs + reg + 4);
8080
}
8181

82+
static inline void axi_chan_config_write(struct axi_dma_chan *chan,
83+
struct axi_dma_chan_config *config)
84+
{
85+
u32 cfg_lo, cfg_hi;
86+
87+
cfg_lo = (config->dst_multblk_type << CH_CFG_L_DST_MULTBLK_TYPE_POS |
88+
config->src_multblk_type << CH_CFG_L_SRC_MULTBLK_TYPE_POS);
89+
if (chan->chip->dw->hdata->reg_map_8_channels) {
90+
cfg_hi = config->tt_fc << CH_CFG_H_TT_FC_POS |
91+
config->hs_sel_src << CH_CFG_H_HS_SEL_SRC_POS |
92+
config->hs_sel_dst << CH_CFG_H_HS_SEL_DST_POS |
93+
config->src_per << CH_CFG_H_SRC_PER_POS |
94+
config->dst_per << CH_CFG_H_DST_PER_POS |
95+
config->prior << CH_CFG_H_PRIORITY_POS;
96+
} else {
97+
cfg_lo |= config->src_per << CH_CFG2_L_SRC_PER_POS |
98+
config->dst_per << CH_CFG2_L_DST_PER_POS;
99+
cfg_hi = config->tt_fc << CH_CFG2_H_TT_FC_POS |
100+
config->hs_sel_src << CH_CFG2_H_HS_SEL_SRC_POS |
101+
config->hs_sel_dst << CH_CFG2_H_HS_SEL_DST_POS |
102+
config->prior << CH_CFG2_H_PRIORITY_POS;
103+
}
104+
axi_chan_iowrite32(chan, CH_CFG_L, cfg_lo);
105+
axi_chan_iowrite32(chan, CH_CFG_H, cfg_hi);
106+
}
107+
82108
static inline void axi_dma_disable(struct axi_dma_chip *chip)
83109
{
84110
u32 val;
@@ -154,7 +180,10 @@ static inline void axi_chan_disable(struct axi_dma_chan *chan)
154180

155181
val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
156182
val &= ~(BIT(chan->id) << DMAC_CHAN_EN_SHIFT);
157-
val |= BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT;
183+
if (chan->chip->dw->hdata->reg_map_8_channels)
184+
val |= BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT;
185+
else
186+
val |= BIT(chan->id) << DMAC_CHAN_EN2_WE_SHIFT;
158187
axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
159188
}
160189

@@ -163,8 +192,12 @@ static inline void axi_chan_enable(struct axi_dma_chan *chan)
163192
u32 val;
164193

165194
val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
166-
val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT |
167-
BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT;
195+
if (chan->chip->dw->hdata->reg_map_8_channels)
196+
val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT |
197+
BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT;
198+
else
199+
val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT |
200+
BIT(chan->id) << DMAC_CHAN_EN2_WE_SHIFT;
168201
axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
169202
}
170203

@@ -336,7 +369,8 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
336369
struct axi_dma_desc *first)
337370
{
338371
u32 priority = chan->chip->dw->hdata->priority[chan->id];
339-
u32 reg, irq_mask;
372+
struct axi_dma_chan_config config;
373+
u32 irq_mask;
340374
u8 lms = 0; /* Select AXI0 master for LLI fetching */
341375

342376
if (unlikely(axi_chan_is_hw_enable(chan))) {
@@ -348,36 +382,32 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
348382

349383
axi_dma_enable(chan->chip);
350384

351-
reg = (DWAXIDMAC_MBLK_TYPE_LL << CH_CFG_L_DST_MULTBLK_TYPE_POS |
352-
DWAXIDMAC_MBLK_TYPE_LL << CH_CFG_L_SRC_MULTBLK_TYPE_POS);
353-
axi_chan_iowrite32(chan, CH_CFG_L, reg);
354-
355-
reg = (DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC << CH_CFG_H_TT_FC_POS |
356-
priority << CH_CFG_H_PRIORITY_POS |
357-
DWAXIDMAC_HS_SEL_HW << CH_CFG_H_HS_SEL_DST_POS |
358-
DWAXIDMAC_HS_SEL_HW << CH_CFG_H_HS_SEL_SRC_POS);
385+
config.dst_multblk_type = DWAXIDMAC_MBLK_TYPE_LL;
386+
config.src_multblk_type = DWAXIDMAC_MBLK_TYPE_LL;
387+
config.tt_fc = DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC;
388+
config.prior = priority;
389+
config.hs_sel_dst = DWAXIDMAC_HS_SEL_HW;
390+
config.hs_sel_dst = DWAXIDMAC_HS_SEL_HW;
359391
switch (chan->direction) {
360392
case DMA_MEM_TO_DEV:
361393
dw_axi_dma_set_byte_halfword(chan, true);
362-
reg |= (chan->config.device_fc ?
363-
DWAXIDMAC_TT_FC_MEM_TO_PER_DST :
364-
DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC)
365-
<< CH_CFG_H_TT_FC_POS;
394+
config.tt_fc = chan->config.device_fc ?
395+
DWAXIDMAC_TT_FC_MEM_TO_PER_DST :
396+
DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC;
366397
if (chan->chip->apb_regs)
367-
reg |= (chan->id << CH_CFG_H_DST_PER_POS);
398+
config.dst_per = chan->id;
368399
break;
369400
case DMA_DEV_TO_MEM:
370-
reg |= (chan->config.device_fc ?
371-
DWAXIDMAC_TT_FC_PER_TO_MEM_SRC :
372-
DWAXIDMAC_TT_FC_PER_TO_MEM_DMAC)
373-
<< CH_CFG_H_TT_FC_POS;
401+
config.tt_fc = chan->config.device_fc ?
402+
DWAXIDMAC_TT_FC_PER_TO_MEM_SRC :
403+
DWAXIDMAC_TT_FC_PER_TO_MEM_DMAC;
374404
if (chan->chip->apb_regs)
375-
reg |= (chan->id << CH_CFG_H_SRC_PER_POS);
405+
config.src_per = chan->id;
376406
break;
377407
default:
378408
break;
379409
}
380-
axi_chan_iowrite32(chan, CH_CFG_H, reg);
410+
axi_chan_config_write(chan, &config);
381411

382412
write_chan_llp(chan, first->hw_desc[0].llp | lms);
383413

@@ -1120,10 +1150,17 @@ static int dma_chan_pause(struct dma_chan *dchan)
11201150

11211151
spin_lock_irqsave(&chan->vc.lock, flags);
11221152

1123-
val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
1124-
val |= BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT |
1125-
BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT;
1126-
axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
1153+
if (chan->chip->dw->hdata->reg_map_8_channels) {
1154+
val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
1155+
val |= BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT |
1156+
BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT;
1157+
axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
1158+
} else {
1159+
val = 0;
1160+
val |= BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT |
1161+
BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT;
1162+
axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, val);
1163+
}
11271164

11281165
do {
11291166
if (axi_chan_irq_read(chan) & DWAXIDMAC_IRQ_SUSPENDED)
@@ -1147,9 +1184,15 @@ static inline void axi_chan_resume(struct axi_dma_chan *chan)
11471184
u32 val;
11481185

11491186
val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
1150-
val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT);
1151-
val |= (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT);
1152-
axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
1187+
if (chan->chip->dw->hdata->reg_map_8_channels) {
1188+
val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT);
1189+
val |= (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT);
1190+
axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
1191+
} else {
1192+
val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT);
1193+
val |= (BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT);
1194+
axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, val);
1195+
}
11531196

11541197
chan->is_paused = false;
11551198
}
@@ -1241,6 +1284,8 @@ static int parse_device_properties(struct axi_dma_chip *chip)
12411284
return -EINVAL;
12421285

12431286
chip->dw->hdata->nr_channels = tmp;
1287+
if (tmp <= DMA_REG_MAP_CH_REF)
1288+
chip->dw->hdata->reg_map_8_channels = true;
12441289

12451290
ret = device_property_read_u32(dev, "snps,dma-masters", &tmp);
12461291
if (ret)

drivers/dma/dw-axi-dmac/dw-axi-dmac.h

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
#include "../virt-dma.h"
2020

21-
#define DMAC_MAX_CHANNELS 8
21+
#define DMAC_MAX_CHANNELS 16
2222
#define DMAC_MAX_MASTERS 2
2323
#define DMAC_MAX_BLK_SIZE 0x200000
2424

@@ -30,6 +30,8 @@ struct dw_axi_dma_hcfg {
3030
u32 priority[DMAC_MAX_CHANNELS];
3131
/* maximum supported axi burst length */
3232
u32 axi_rw_burst_len;
33+
/* Register map for DMAX_NUM_CHANNELS <= 8 */
34+
bool reg_map_8_channels;
3335
bool restrict_axi_burst_len;
3436
};
3537

@@ -103,6 +105,17 @@ struct axi_dma_desc {
103105
u32 period_len;
104106
};
105107

108+
struct axi_dma_chan_config {
109+
u8 dst_multblk_type;
110+
u8 src_multblk_type;
111+
u8 dst_per;
112+
u8 src_per;
113+
u8 tt_fc;
114+
u8 prior;
115+
u8 hs_sel_dst;
116+
u8 hs_sel_src;
117+
};
118+
106119
static inline struct device *dchan2dev(struct dma_chan *dchan)
107120
{
108121
return &dchan->dev->device;
@@ -139,6 +152,8 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan)
139152
#define DMAC_CHEN 0x018 /* R/W DMAC Channel Enable */
140153
#define DMAC_CHEN_L 0x018 /* R/W DMAC Channel Enable 00-31 */
141154
#define DMAC_CHEN_H 0x01C /* R/W DMAC Channel Enable 32-63 */
155+
#define DMAC_CHSUSPREG 0x020 /* R/W DMAC Channel Suspend */
156+
#define DMAC_CHABORTREG 0x028 /* R/W DMAC Channel Abort */
142157
#define DMAC_INTSTATUS 0x030 /* R DMAC Interrupt Status */
143158
#define DMAC_COMMON_INTCLEAR 0x038 /* W DMAC Interrupt Clear */
144159
#define DMAC_COMMON_INTSTATUS_ENA 0x040 /* R DMAC Interrupt Status Enable */
@@ -187,6 +202,7 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan)
187202
#define DMA_APB_HS_SEL_BIT_SIZE 0x08 /* HW handshake bits per channel */
188203
#define DMA_APB_HS_SEL_MASK 0xFF /* HW handshake select masks */
189204
#define MAX_BLOCK_SIZE 0x1000 /* 1024 blocks * 4 bytes data width */
205+
#define DMA_REG_MAP_CH_REF 0x08 /* Channel count to choose register map */
190206

191207
/* DMAC_CFG */
192208
#define DMAC_EN_POS 0
@@ -195,12 +211,20 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan)
195211
#define INT_EN_POS 1
196212
#define INT_EN_MASK BIT(INT_EN_POS)
197213

214+
/* DMAC_CHEN */
198215
#define DMAC_CHAN_EN_SHIFT 0
199216
#define DMAC_CHAN_EN_WE_SHIFT 8
200217

201218
#define DMAC_CHAN_SUSP_SHIFT 16
202219
#define DMAC_CHAN_SUSP_WE_SHIFT 24
203220

221+
/* DMAC_CHEN2 */
222+
#define DMAC_CHAN_EN2_WE_SHIFT 16
223+
224+
/* DMAC_CHSUSP */
225+
#define DMAC_CHAN_SUSP2_SHIFT 0
226+
#define DMAC_CHAN_SUSP2_WE_SHIFT 16
227+
204228
/* CH_CTL_H */
205229
#define CH_CTL_H_ARLEN_EN BIT(6)
206230
#define CH_CTL_H_ARLEN_POS 7
@@ -289,6 +313,15 @@ enum {
289313
DWAXIDMAC_MBLK_TYPE_LL
290314
};
291315

316+
/* CH_CFG2 */
317+
#define CH_CFG2_L_SRC_PER_POS 4
318+
#define CH_CFG2_L_DST_PER_POS 11
319+
320+
#define CH_CFG2_H_TT_FC_POS 0
321+
#define CH_CFG2_H_HS_SEL_SRC_POS 3
322+
#define CH_CFG2_H_HS_SEL_DST_POS 4
323+
#define CH_CFG2_H_PRIORITY_POS 20
324+
292325
/**
293326
* DW AXI DMA channel interrupts
294327
*

0 commit comments

Comments
 (0)