Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <mesihkilinc@gmail.com>
[ csokas.bence: Resolve conflict in `sun4i_dma_prep_dma_cyclic()`, fix whitespace ]
Signed-off-by: Csókás Bence <csokas.bence@prolan.hu>
Link: https://lore.kernel.org/r/20241122161128.2619172-2-csokas.bence@prolan.hu
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Mesih Kilinc and committed by
Vinod Koul
a2186c2c 23417899

+105 -32
+105 -32
drivers/dma/sun4i-dma.c
··· 13 13 #include <linux/interrupt.h> 14 14 #include <linux/module.h> 15 15 #include <linux/of_dma.h> 16 + #include <linux/of_device.h> 16 17 #include <linux/platform_device.h> 17 18 #include <linux/slab.h> 18 19 #include <linux/spinlock.h> ··· 31 30 #define SUN4I_DMA_CFG_SRC_BURST_LENGTH(len) ((len) << 7) 32 31 #define SUN4I_DMA_CFG_SRC_ADDR_MODE(mode) ((mode) << 5) 33 32 #define SUN4I_DMA_CFG_SRC_DRQ_TYPE(type) (type) 33 + 34 + #define SUN4I_MAX_BURST 8 34 35 35 36 /** Normal DMA register values **/ 36 37 ··· 135 132 #define SUN4I_DDMA_MAX_SEG_SIZE SZ_16M 136 133 #define SUN4I_DMA_MAX_SEG_SIZE SUN4I_NDMA_MAX_SEG_SIZE 137 134 135 + /* 136 + * Hardware channels / ports representation 137 + * 138 + * The hardware is used in several SoCs, with differing numbers 139 + * of channels and endpoints. This structure ties those numbers 140 + * to a certain compatible string. 141 + */ 142 + struct sun4i_dma_config { 143 + u32 ndma_nr_max_channels; 144 + u32 ndma_nr_max_vchans; 145 + 146 + u32 ddma_nr_max_channels; 147 + u32 ddma_nr_max_vchans; 148 + 149 + u32 dma_nr_max_channels; 150 + 151 + void (*set_dst_data_width)(u32 *p_cfg, s8 data_width); 152 + void (*set_src_data_width)(u32 *p_cfg, s8 data_width); 153 + int (*convert_burst)(u32 maxburst); 154 + 155 + u8 ndma_drq_sdram; 156 + u8 ddma_drq_sdram; 157 + 158 + u8 max_burst; 159 + }; 160 + 138 161 struct sun4i_dma_pchan { 139 162 /* Register base of channel */ 140 163 void __iomem *base; ··· 199 170 }; 200 171 201 172 struct sun4i_dma_dev { 202 - DECLARE_BITMAP(pchans_used, SUN4I_DMA_NR_MAX_CHANNELS); 173 + unsigned long *pchans_used; 203 174 struct dma_device slave; 204 175 struct sun4i_dma_pchan *pchans; 205 176 struct sun4i_dma_vchan *vchans; ··· 207 178 struct clk *clk; 208 179 int irq; 209 180 spinlock_t lock; 181 + const struct sun4i_dma_config *cfg; 210 182 }; 211 183 212 184 static struct sun4i_dma_dev *to_sun4i_dma_dev(struct dma_device *dev) ··· 230 200 return &chan->dev->device; 231 201 } 232 202 233 - static int convert_burst(u32 maxburst) 203 + static void set_dst_data_width_a10(u32 *p_cfg, s8 data_width) 204 + { 205 + *p_cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(data_width); 206 + } 207 + 208 + static void set_src_data_width_a10(u32 *p_cfg, s8 data_width) 209 + { 210 + *p_cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(data_width); 211 + } 212 + 213 + static int convert_burst_a10(u32 maxburst) 234 214 { 235 215 if (maxburst > 8) 236 216 return -EINVAL; ··· 273 233 int i, max; 274 234 275 235 /* 276 - * pchans 0-SUN4I_NDMA_NR_MAX_CHANNELS are normal, and 277 - * SUN4I_NDMA_NR_MAX_CHANNELS+ are dedicated ones 236 + * pchans 0-priv->cfg->ndma_nr_max_channels are normal, and 237 + * priv->cfg->ndma_nr_max_channels+ are dedicated ones 278 238 */ 279 239 if (vchan->is_dedicated) { 280 - i = SUN4I_NDMA_NR_MAX_CHANNELS; 281 - max = SUN4I_DMA_NR_MAX_CHANNELS; 240 + i = priv->cfg->ndma_nr_max_channels; 241 + max = priv->cfg->dma_nr_max_channels; 282 242 } else { 283 243 i = 0; 284 - max = SUN4I_NDMA_NR_MAX_CHANNELS; 244 + max = priv->cfg->ndma_nr_max_channels; 285 245 } 286 246 287 247 spin_lock_irqsave(&priv->lock, flags); ··· 484 444 size_t len, struct dma_slave_config *sconfig, 485 445 enum dma_transfer_direction direction) 486 446 { 447 + struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device); 487 448 struct sun4i_dma_promise *promise; 488 449 int ret; 489 450 ··· 508 467 sconfig->src_addr_width, sconfig->dst_addr_width); 509 468 510 469 /* Source burst */ 511 - ret = convert_burst(sconfig->src_maxburst); 470 + ret = priv->cfg->convert_burst(sconfig->src_maxburst); 512 471 if (ret < 0) 513 472 goto fail; 514 473 promise->cfg |= SUN4I_DMA_CFG_SRC_BURST_LENGTH(ret); 515 474 516 475 /* Destination burst */ 517 - ret = convert_burst(sconfig->dst_maxburst); 476 + ret = priv->cfg->convert_burst(sconfig->dst_maxburst); 518 477 if (ret < 0) 519 478 goto fail; 520 479 promise->cfg |= SUN4I_DMA_CFG_DST_BURST_LENGTH(ret); ··· 523 482 ret = convert_buswidth(sconfig->src_addr_width); 524 483 if (ret < 0) 525 484 goto fail; 526 - promise->cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(ret); 485 + priv->cfg->set_src_data_width(&promise->cfg, ret); 527 486 528 487 /* Destination bus width */ 529 488 ret = convert_buswidth(sconfig->dst_addr_width); 530 489 if (ret < 0) 531 490 goto fail; 532 - promise->cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(ret); 491 + priv->cfg->set_dst_data_width(&promise->cfg, ret); 533 492 534 493 return promise; 535 494 ··· 551 510 generate_ddma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest, 552 511 size_t len, struct dma_slave_config *sconfig) 553 512 { 513 + struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device); 554 514 struct sun4i_dma_promise *promise; 555 515 int ret; 556 516 ··· 566 524 SUN4I_DDMA_CFG_BYTE_COUNT_MODE_REMAIN; 567 525 568 526 /* Source burst */ 569 - ret = convert_burst(sconfig->src_maxburst); 527 + ret = priv->cfg->convert_burst(sconfig->src_maxburst); 570 528 if (ret < 0) 571 529 goto fail; 572 530 promise->cfg |= SUN4I_DMA_CFG_SRC_BURST_LENGTH(ret); 573 531 574 532 /* Destination burst */ 575 - ret = convert_burst(sconfig->dst_maxburst); 533 + ret = priv->cfg->convert_burst(sconfig->dst_maxburst); 576 534 if (ret < 0) 577 535 goto fail; 578 536 promise->cfg |= SUN4I_DMA_CFG_DST_BURST_LENGTH(ret); ··· 581 539 ret = convert_buswidth(sconfig->src_addr_width); 582 540 if (ret < 0) 583 541 goto fail; 584 - promise->cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(ret); 542 + priv->cfg->set_src_data_width(&promise->cfg, ret); 585 543 586 544 /* Destination bus width */ 587 545 ret = convert_buswidth(sconfig->dst_addr_width); 588 546 if (ret < 0) 589 547 goto fail; 590 - promise->cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(ret); 548 + priv->cfg->set_dst_data_width(&promise->cfg, ret); 591 549 592 550 return promise; 593 551 ··· 664 622 sun4i_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, 665 623 dma_addr_t src, size_t len, unsigned long flags) 666 624 { 625 + struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device); 667 626 struct sun4i_dma_vchan *vchan = to_sun4i_dma_vchan(chan); 668 627 struct dma_slave_config *sconfig = &vchan->cfg; 669 628 struct sun4i_dma_promise *promise; ··· 681 638 */ 682 639 sconfig->src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 683 640 sconfig->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 684 - sconfig->src_maxburst = 8; 685 - sconfig->dst_maxburst = 8; 641 + sconfig->src_maxburst = priv->cfg->max_burst; 642 + sconfig->dst_maxburst = priv->cfg->max_burst; 686 643 687 644 if (vchan->is_dedicated) 688 645 promise = generate_ddma_promise(chan, src, dest, len, sconfig); ··· 697 654 698 655 /* Configure memcpy mode */ 699 656 if (vchan->is_dedicated) { 700 - promise->cfg |= SUN4I_DMA_CFG_SRC_DRQ_TYPE(SUN4I_DDMA_DRQ_TYPE_SDRAM) | 701 - SUN4I_DMA_CFG_DST_DRQ_TYPE(SUN4I_DDMA_DRQ_TYPE_SDRAM); 657 + promise->cfg |= 658 + SUN4I_DMA_CFG_SRC_DRQ_TYPE(priv->cfg->ddma_drq_sdram) | 659 + SUN4I_DMA_CFG_DST_DRQ_TYPE(priv->cfg->ddma_drq_sdram); 702 660 } else { 703 - promise->cfg |= SUN4I_DMA_CFG_SRC_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM) | 704 - SUN4I_DMA_CFG_DST_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM); 661 + promise->cfg |= 662 + SUN4I_DMA_CFG_SRC_DRQ_TYPE(priv->cfg->ndma_drq_sdram) | 663 + SUN4I_DMA_CFG_DST_DRQ_TYPE(priv->cfg->ndma_drq_sdram); 705 664 } 706 665 707 666 /* Fill the contract with our only promise */ ··· 718 673 size_t period_len, enum dma_transfer_direction dir, 719 674 unsigned long flags) 720 675 { 676 + struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device); 721 677 struct sun4i_dma_vchan *vchan = to_sun4i_dma_vchan(chan); 722 678 struct dma_slave_config *sconfig = &vchan->cfg; 723 679 struct sun4i_dma_promise *promise; ··· 742 696 if (vchan->is_dedicated) { 743 697 io_mode = SUN4I_DDMA_ADDR_MODE_IO; 744 698 linear_mode = SUN4I_DDMA_ADDR_MODE_LINEAR; 745 - ram_type = SUN4I_DDMA_DRQ_TYPE_SDRAM; 699 + ram_type = priv->cfg->ddma_drq_sdram; 746 700 } else { 747 701 io_mode = SUN4I_NDMA_ADDR_MODE_IO; 748 702 linear_mode = SUN4I_NDMA_ADDR_MODE_LINEAR; 749 - ram_type = SUN4I_NDMA_DRQ_TYPE_SDRAM; 703 + ram_type = priv->cfg->ndma_drq_sdram; 750 704 } 751 705 752 706 if (dir == DMA_MEM_TO_DEV) { ··· 839 793 unsigned int sg_len, enum dma_transfer_direction dir, 840 794 unsigned long flags, void *context) 841 795 { 796 + struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device); 842 797 struct sun4i_dma_vchan *vchan = to_sun4i_dma_vchan(chan); 843 798 struct dma_slave_config *sconfig = &vchan->cfg; 844 799 struct sun4i_dma_promise *promise; ··· 865 818 if (vchan->is_dedicated) { 866 819 io_mode = SUN4I_DDMA_ADDR_MODE_IO; 867 820 linear_mode = SUN4I_DDMA_ADDR_MODE_LINEAR; 868 - ram_type = SUN4I_DDMA_DRQ_TYPE_SDRAM; 821 + ram_type = priv->cfg->ddma_drq_sdram; 869 822 } else { 870 823 io_mode = SUN4I_NDMA_ADDR_MODE_IO; 871 824 linear_mode = SUN4I_NDMA_ADDR_MODE_LINEAR; 872 - ram_type = SUN4I_NDMA_DRQ_TYPE_SDRAM; 825 + ram_type = priv->cfg->ndma_drq_sdram; 873 826 } 874 827 875 828 if (dir == DMA_MEM_TO_DEV) ··· 1197 1150 if (!priv) 1198 1151 return -ENOMEM; 1199 1152 1153 + priv->cfg = of_device_get_match_data(&pdev->dev); 1154 + if (!priv->cfg) 1155 + return -ENODEV; 1156 + 1200 1157 priv->base = devm_platform_ioremap_resource(pdev, 0); 1201 1158 if (IS_ERR(priv->base)) 1202 1159 return PTR_ERR(priv->base); ··· 1248 1197 1249 1198 priv->slave.dev = &pdev->dev; 1250 1199 1251 - priv->pchans = devm_kcalloc(&pdev->dev, SUN4I_DMA_NR_MAX_CHANNELS, 1200 + priv->pchans = devm_kcalloc(&pdev->dev, priv->cfg->dma_nr_max_channels, 1252 1201 sizeof(struct sun4i_dma_pchan), GFP_KERNEL); 1253 1202 priv->vchans = devm_kcalloc(&pdev->dev, SUN4I_DMA_NR_MAX_VCHANS, 1254 1203 sizeof(struct sun4i_dma_vchan), GFP_KERNEL); 1255 - if (!priv->vchans || !priv->pchans) 1204 + priv->pchans_used = devm_kcalloc(&pdev->dev, 1205 + BITS_TO_LONGS(priv->cfg->dma_nr_max_channels), 1206 + sizeof(unsigned long), GFP_KERNEL); 1207 + if (!priv->vchans || !priv->pchans || !priv->pchans_used) 1256 1208 return -ENOMEM; 1257 1209 1258 1210 /* 1259 - * [0..SUN4I_NDMA_NR_MAX_CHANNELS) are normal pchans, and 1260 - * [SUN4I_NDMA_NR_MAX_CHANNELS..SUN4I_DMA_NR_MAX_CHANNELS) are 1211 + * [0..priv->cfg->ndma_nr_max_channels) are normal pchans, and 1212 + * [priv->cfg->ndma_nr_max_channels..priv->cfg->dma_nr_max_channels) are 1261 1213 * dedicated ones 1262 1214 */ 1263 - for (i = 0; i < SUN4I_NDMA_NR_MAX_CHANNELS; i++) 1215 + for (i = 0; i < priv->cfg->ndma_nr_max_channels; i++) 1264 1216 priv->pchans[i].base = priv->base + 1265 1217 SUN4I_NDMA_CHANNEL_REG_BASE(i); 1266 1218 1267 - for (j = 0; i < SUN4I_DMA_NR_MAX_CHANNELS; i++, j++) { 1219 + for (j = 0; i < priv->cfg->dma_nr_max_channels; i++, j++) { 1268 1220 priv->pchans[i].base = priv->base + 1269 1221 SUN4I_DDMA_CHANNEL_REG_BASE(j); 1270 1222 priv->pchans[i].is_dedicated = 1; ··· 1338 1284 clk_disable_unprepare(priv->clk); 1339 1285 } 1340 1286 1287 + static struct sun4i_dma_config sun4i_a10_dma_cfg = { 1288 + .ndma_nr_max_channels = SUN4I_NDMA_NR_MAX_CHANNELS, 1289 + .ndma_nr_max_vchans = SUN4I_NDMA_NR_MAX_VCHANS, 1290 + 1291 + .ddma_nr_max_channels = SUN4I_DDMA_NR_MAX_CHANNELS, 1292 + .ddma_nr_max_vchans = SUN4I_DDMA_NR_MAX_VCHANS, 1293 + 1294 + .dma_nr_max_channels = SUN4I_DMA_NR_MAX_CHANNELS, 1295 + 1296 + .set_dst_data_width = set_dst_data_width_a10, 1297 + .set_src_data_width = set_src_data_width_a10, 1298 + .convert_burst = convert_burst_a10, 1299 + 1300 + .ndma_drq_sdram = SUN4I_NDMA_DRQ_TYPE_SDRAM, 1301 + .ddma_drq_sdram = SUN4I_DDMA_DRQ_TYPE_SDRAM, 1302 + 1303 + .max_burst = SUN4I_MAX_BURST, 1304 + }; 1305 + 1341 1306 static const struct of_device_id sun4i_dma_match[] = { 1342 - { .compatible = "allwinner,sun4i-a10-dma" }, 1307 + { .compatible = "allwinner,sun4i-a10-dma", .data = &sun4i_a10_dma_cfg }, 1343 1308 { /* sentinel */ }, 1344 1309 }; 1345 1310 MODULE_DEVICE_TABLE(of, sun4i_dma_match);