Skip to content

Commit a2186c2

Browse files
MesihKvinodkoul
authored andcommitted
dma-engine: sun4i: Add a quirk to support different chips
Allwinner suniv F1C100s has similar DMA engine to sun4i. Several registers has different addresses. Total dma channels, endpoint counts and max burst counts are also different. In order to support F1C100s add a quirk structure to hold IC specific data. Signed-off-by: Mesih Kilinc <[email protected]> [ csokas.bence: Resolve conflict in `sun4i_dma_prep_dma_cyclic()`, fix whitespace ] Signed-off-by: Csókás Bence <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 2341789 commit a2186c2

File tree

1 file changed

+105
-32
lines changed

1 file changed

+105
-32
lines changed

drivers/dma/sun4i-dma.c

Lines changed: 105 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/interrupt.h>
1414
#include <linux/module.h>
1515
#include <linux/of_dma.h>
16+
#include <linux/of_device.h>
1617
#include <linux/platform_device.h>
1718
#include <linux/slab.h>
1819
#include <linux/spinlock.h>
@@ -31,6 +32,8 @@
3132
#define SUN4I_DMA_CFG_SRC_ADDR_MODE(mode) ((mode) << 5)
3233
#define SUN4I_DMA_CFG_SRC_DRQ_TYPE(type) (type)
3334

35+
#define SUN4I_MAX_BURST 8
36+
3437
/** Normal DMA register values **/
3538

3639
/* Normal DMA source/destination data request type values */
@@ -132,6 +135,32 @@
132135
#define SUN4I_DDMA_MAX_SEG_SIZE SZ_16M
133136
#define SUN4I_DMA_MAX_SEG_SIZE SUN4I_NDMA_MAX_SEG_SIZE
134137

138+
/*
139+
* Hardware channels / ports representation
140+
*
141+
* The hardware is used in several SoCs, with differing numbers
142+
* of channels and endpoints. This structure ties those numbers
143+
* to a certain compatible string.
144+
*/
145+
struct sun4i_dma_config {
146+
u32 ndma_nr_max_channels;
147+
u32 ndma_nr_max_vchans;
148+
149+
u32 ddma_nr_max_channels;
150+
u32 ddma_nr_max_vchans;
151+
152+
u32 dma_nr_max_channels;
153+
154+
void (*set_dst_data_width)(u32 *p_cfg, s8 data_width);
155+
void (*set_src_data_width)(u32 *p_cfg, s8 data_width);
156+
int (*convert_burst)(u32 maxburst);
157+
158+
u8 ndma_drq_sdram;
159+
u8 ddma_drq_sdram;
160+
161+
u8 max_burst;
162+
};
163+
135164
struct sun4i_dma_pchan {
136165
/* Register base of channel */
137166
void __iomem *base;
@@ -170,14 +199,15 @@ struct sun4i_dma_contract {
170199
};
171200

172201
struct sun4i_dma_dev {
173-
DECLARE_BITMAP(pchans_used, SUN4I_DMA_NR_MAX_CHANNELS);
202+
unsigned long *pchans_used;
174203
struct dma_device slave;
175204
struct sun4i_dma_pchan *pchans;
176205
struct sun4i_dma_vchan *vchans;
177206
void __iomem *base;
178207
struct clk *clk;
179208
int irq;
180209
spinlock_t lock;
210+
const struct sun4i_dma_config *cfg;
181211
};
182212

183213
static struct sun4i_dma_dev *to_sun4i_dma_dev(struct dma_device *dev)
@@ -200,7 +230,17 @@ static struct device *chan2dev(struct dma_chan *chan)
200230
return &chan->dev->device;
201231
}
202232

203-
static int convert_burst(u32 maxburst)
233+
static void set_dst_data_width_a10(u32 *p_cfg, s8 data_width)
234+
{
235+
*p_cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(data_width);
236+
}
237+
238+
static void set_src_data_width_a10(u32 *p_cfg, s8 data_width)
239+
{
240+
*p_cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(data_width);
241+
}
242+
243+
static int convert_burst_a10(u32 maxburst)
204244
{
205245
if (maxburst > 8)
206246
return -EINVAL;
@@ -233,15 +273,15 @@ static struct sun4i_dma_pchan *find_and_use_pchan(struct sun4i_dma_dev *priv,
233273
int i, max;
234274

235275
/*
236-
* pchans 0-SUN4I_NDMA_NR_MAX_CHANNELS are normal, and
237-
* SUN4I_NDMA_NR_MAX_CHANNELS+ are dedicated ones
276+
* pchans 0-priv->cfg->ndma_nr_max_channels are normal, and
277+
* priv->cfg->ndma_nr_max_channels+ are dedicated ones
238278
*/
239279
if (vchan->is_dedicated) {
240-
i = SUN4I_NDMA_NR_MAX_CHANNELS;
241-
max = SUN4I_DMA_NR_MAX_CHANNELS;
280+
i = priv->cfg->ndma_nr_max_channels;
281+
max = priv->cfg->dma_nr_max_channels;
242282
} else {
243283
i = 0;
244-
max = SUN4I_NDMA_NR_MAX_CHANNELS;
284+
max = priv->cfg->ndma_nr_max_channels;
245285
}
246286

247287
spin_lock_irqsave(&priv->lock, flags);
@@ -444,6 +484,7 @@ generate_ndma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
444484
size_t len, struct dma_slave_config *sconfig,
445485
enum dma_transfer_direction direction)
446486
{
487+
struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
447488
struct sun4i_dma_promise *promise;
448489
int ret;
449490

@@ -467,13 +508,13 @@ generate_ndma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
467508
sconfig->src_addr_width, sconfig->dst_addr_width);
468509

469510
/* Source burst */
470-
ret = convert_burst(sconfig->src_maxburst);
511+
ret = priv->cfg->convert_burst(sconfig->src_maxburst);
471512
if (ret < 0)
472513
goto fail;
473514
promise->cfg |= SUN4I_DMA_CFG_SRC_BURST_LENGTH(ret);
474515

475516
/* Destination burst */
476-
ret = convert_burst(sconfig->dst_maxburst);
517+
ret = priv->cfg->convert_burst(sconfig->dst_maxburst);
477518
if (ret < 0)
478519
goto fail;
479520
promise->cfg |= SUN4I_DMA_CFG_DST_BURST_LENGTH(ret);
@@ -482,13 +523,13 @@ generate_ndma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
482523
ret = convert_buswidth(sconfig->src_addr_width);
483524
if (ret < 0)
484525
goto fail;
485-
promise->cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(ret);
526+
priv->cfg->set_src_data_width(&promise->cfg, ret);
486527

487528
/* Destination bus width */
488529
ret = convert_buswidth(sconfig->dst_addr_width);
489530
if (ret < 0)
490531
goto fail;
491-
promise->cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(ret);
532+
priv->cfg->set_dst_data_width(&promise->cfg, ret);
492533

493534
return promise;
494535

@@ -510,6 +551,7 @@ static struct sun4i_dma_promise *
510551
generate_ddma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
511552
size_t len, struct dma_slave_config *sconfig)
512553
{
554+
struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
513555
struct sun4i_dma_promise *promise;
514556
int ret;
515557

@@ -524,13 +566,13 @@ generate_ddma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
524566
SUN4I_DDMA_CFG_BYTE_COUNT_MODE_REMAIN;
525567

526568
/* Source burst */
527-
ret = convert_burst(sconfig->src_maxburst);
569+
ret = priv->cfg->convert_burst(sconfig->src_maxburst);
528570
if (ret < 0)
529571
goto fail;
530572
promise->cfg |= SUN4I_DMA_CFG_SRC_BURST_LENGTH(ret);
531573

532574
/* Destination burst */
533-
ret = convert_burst(sconfig->dst_maxburst);
575+
ret = priv->cfg->convert_burst(sconfig->dst_maxburst);
534576
if (ret < 0)
535577
goto fail;
536578
promise->cfg |= SUN4I_DMA_CFG_DST_BURST_LENGTH(ret);
@@ -539,13 +581,13 @@ generate_ddma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
539581
ret = convert_buswidth(sconfig->src_addr_width);
540582
if (ret < 0)
541583
goto fail;
542-
promise->cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(ret);
584+
priv->cfg->set_src_data_width(&promise->cfg, ret);
543585

544586
/* Destination bus width */
545587
ret = convert_buswidth(sconfig->dst_addr_width);
546588
if (ret < 0)
547589
goto fail;
548-
promise->cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(ret);
590+
priv->cfg->set_dst_data_width(&promise->cfg, ret);
549591

550592
return promise;
551593

@@ -622,6 +664,7 @@ static struct dma_async_tx_descriptor *
622664
sun4i_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
623665
dma_addr_t src, size_t len, unsigned long flags)
624666
{
667+
struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
625668
struct sun4i_dma_vchan *vchan = to_sun4i_dma_vchan(chan);
626669
struct dma_slave_config *sconfig = &vchan->cfg;
627670
struct sun4i_dma_promise *promise;
@@ -638,8 +681,8 @@ sun4i_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
638681
*/
639682
sconfig->src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
640683
sconfig->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
641-
sconfig->src_maxburst = 8;
642-
sconfig->dst_maxburst = 8;
684+
sconfig->src_maxburst = priv->cfg->max_burst;
685+
sconfig->dst_maxburst = priv->cfg->max_burst;
643686

644687
if (vchan->is_dedicated)
645688
promise = generate_ddma_promise(chan, src, dest, len, sconfig);
@@ -654,11 +697,13 @@ sun4i_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
654697

655698
/* Configure memcpy mode */
656699
if (vchan->is_dedicated) {
657-
promise->cfg |= SUN4I_DMA_CFG_SRC_DRQ_TYPE(SUN4I_DDMA_DRQ_TYPE_SDRAM) |
658-
SUN4I_DMA_CFG_DST_DRQ_TYPE(SUN4I_DDMA_DRQ_TYPE_SDRAM);
700+
promise->cfg |=
701+
SUN4I_DMA_CFG_SRC_DRQ_TYPE(priv->cfg->ddma_drq_sdram) |
702+
SUN4I_DMA_CFG_DST_DRQ_TYPE(priv->cfg->ddma_drq_sdram);
659703
} else {
660-
promise->cfg |= SUN4I_DMA_CFG_SRC_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM) |
661-
SUN4I_DMA_CFG_DST_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM);
704+
promise->cfg |=
705+
SUN4I_DMA_CFG_SRC_DRQ_TYPE(priv->cfg->ndma_drq_sdram) |
706+
SUN4I_DMA_CFG_DST_DRQ_TYPE(priv->cfg->ndma_drq_sdram);
662707
}
663708

664709
/* Fill the contract with our only promise */
@@ -673,6 +718,7 @@ sun4i_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf, size_t len,
673718
size_t period_len, enum dma_transfer_direction dir,
674719
unsigned long flags)
675720
{
721+
struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
676722
struct sun4i_dma_vchan *vchan = to_sun4i_dma_vchan(chan);
677723
struct dma_slave_config *sconfig = &vchan->cfg;
678724
struct sun4i_dma_promise *promise;
@@ -696,11 +742,11 @@ sun4i_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf, size_t len,
696742
if (vchan->is_dedicated) {
697743
io_mode = SUN4I_DDMA_ADDR_MODE_IO;
698744
linear_mode = SUN4I_DDMA_ADDR_MODE_LINEAR;
699-
ram_type = SUN4I_DDMA_DRQ_TYPE_SDRAM;
745+
ram_type = priv->cfg->ddma_drq_sdram;
700746
} else {
701747
io_mode = SUN4I_NDMA_ADDR_MODE_IO;
702748
linear_mode = SUN4I_NDMA_ADDR_MODE_LINEAR;
703-
ram_type = SUN4I_NDMA_DRQ_TYPE_SDRAM;
749+
ram_type = priv->cfg->ndma_drq_sdram;
704750
}
705751

706752
if (dir == DMA_MEM_TO_DEV) {
@@ -793,6 +839,7 @@ sun4i_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
793839
unsigned int sg_len, enum dma_transfer_direction dir,
794840
unsigned long flags, void *context)
795841
{
842+
struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
796843
struct sun4i_dma_vchan *vchan = to_sun4i_dma_vchan(chan);
797844
struct dma_slave_config *sconfig = &vchan->cfg;
798845
struct sun4i_dma_promise *promise;
@@ -818,11 +865,11 @@ sun4i_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
818865
if (vchan->is_dedicated) {
819866
io_mode = SUN4I_DDMA_ADDR_MODE_IO;
820867
linear_mode = SUN4I_DDMA_ADDR_MODE_LINEAR;
821-
ram_type = SUN4I_DDMA_DRQ_TYPE_SDRAM;
868+
ram_type = priv->cfg->ddma_drq_sdram;
822869
} else {
823870
io_mode = SUN4I_NDMA_ADDR_MODE_IO;
824871
linear_mode = SUN4I_NDMA_ADDR_MODE_LINEAR;
825-
ram_type = SUN4I_NDMA_DRQ_TYPE_SDRAM;
872+
ram_type = priv->cfg->ndma_drq_sdram;
826873
}
827874

828875
if (dir == DMA_MEM_TO_DEV)
@@ -1150,6 +1197,10 @@ static int sun4i_dma_probe(struct platform_device *pdev)
11501197
if (!priv)
11511198
return -ENOMEM;
11521199

1200+
priv->cfg = of_device_get_match_data(&pdev->dev);
1201+
if (!priv->cfg)
1202+
return -ENODEV;
1203+
11531204
priv->base = devm_platform_ioremap_resource(pdev, 0);
11541205
if (IS_ERR(priv->base))
11551206
return PTR_ERR(priv->base);
@@ -1197,23 +1248,26 @@ static int sun4i_dma_probe(struct platform_device *pdev)
11971248

11981249
priv->slave.dev = &pdev->dev;
11991250

1200-
priv->pchans = devm_kcalloc(&pdev->dev, SUN4I_DMA_NR_MAX_CHANNELS,
1251+
priv->pchans = devm_kcalloc(&pdev->dev, priv->cfg->dma_nr_max_channels,
12011252
sizeof(struct sun4i_dma_pchan), GFP_KERNEL);
12021253
priv->vchans = devm_kcalloc(&pdev->dev, SUN4I_DMA_NR_MAX_VCHANS,
12031254
sizeof(struct sun4i_dma_vchan), GFP_KERNEL);
1204-
if (!priv->vchans || !priv->pchans)
1255+
priv->pchans_used = devm_kcalloc(&pdev->dev,
1256+
BITS_TO_LONGS(priv->cfg->dma_nr_max_channels),
1257+
sizeof(unsigned long), GFP_KERNEL);
1258+
if (!priv->vchans || !priv->pchans || !priv->pchans_used)
12051259
return -ENOMEM;
12061260

12071261
/*
1208-
* [0..SUN4I_NDMA_NR_MAX_CHANNELS) are normal pchans, and
1209-
* [SUN4I_NDMA_NR_MAX_CHANNELS..SUN4I_DMA_NR_MAX_CHANNELS) are
1262+
* [0..priv->cfg->ndma_nr_max_channels) are normal pchans, and
1263+
* [priv->cfg->ndma_nr_max_channels..priv->cfg->dma_nr_max_channels) are
12101264
* dedicated ones
12111265
*/
1212-
for (i = 0; i < SUN4I_NDMA_NR_MAX_CHANNELS; i++)
1266+
for (i = 0; i < priv->cfg->ndma_nr_max_channels; i++)
12131267
priv->pchans[i].base = priv->base +
12141268
SUN4I_NDMA_CHANNEL_REG_BASE(i);
12151269

1216-
for (j = 0; i < SUN4I_DMA_NR_MAX_CHANNELS; i++, j++) {
1270+
for (j = 0; i < priv->cfg->dma_nr_max_channels; i++, j++) {
12171271
priv->pchans[i].base = priv->base +
12181272
SUN4I_DDMA_CHANNEL_REG_BASE(j);
12191273
priv->pchans[i].is_dedicated = 1;
@@ -1284,8 +1338,27 @@ static void sun4i_dma_remove(struct platform_device *pdev)
12841338
clk_disable_unprepare(priv->clk);
12851339
}
12861340

1341+
static struct sun4i_dma_config sun4i_a10_dma_cfg = {
1342+
.ndma_nr_max_channels = SUN4I_NDMA_NR_MAX_CHANNELS,
1343+
.ndma_nr_max_vchans = SUN4I_NDMA_NR_MAX_VCHANS,
1344+
1345+
.ddma_nr_max_channels = SUN4I_DDMA_NR_MAX_CHANNELS,
1346+
.ddma_nr_max_vchans = SUN4I_DDMA_NR_MAX_VCHANS,
1347+
1348+
.dma_nr_max_channels = SUN4I_DMA_NR_MAX_CHANNELS,
1349+
1350+
.set_dst_data_width = set_dst_data_width_a10,
1351+
.set_src_data_width = set_src_data_width_a10,
1352+
.convert_burst = convert_burst_a10,
1353+
1354+
.ndma_drq_sdram = SUN4I_NDMA_DRQ_TYPE_SDRAM,
1355+
.ddma_drq_sdram = SUN4I_DDMA_DRQ_TYPE_SDRAM,
1356+
1357+
.max_burst = SUN4I_MAX_BURST,
1358+
};
1359+
12871360
static const struct of_device_id sun4i_dma_match[] = {
1288-
{ .compatible = "allwinner,sun4i-a10-dma" },
1361+
{ .compatible = "allwinner,sun4i-a10-dma", .data = &sun4i_a10_dma_cfg },
12891362
{ /* sentinel */ },
12901363
};
12911364
MODULE_DEVICE_TABLE(of, sun4i_dma_match);

0 commit comments

Comments
 (0)