| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2014 Emilio López |
|---|
| 3 | 4 | * Emilio López <emilio@elopez.com.ar> |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 6 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 7 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 8 | | - * (at your option) any later version. |
|---|
| 9 | 5 | */ |
|---|
| 10 | 6 | |
|---|
| 11 | 7 | #include <linux/bitmap.h> |
|---|
| .. | .. |
|---|
| 311 | 307 | spin_unlock_irqrestore(&priv->lock, flags); |
|---|
| 312 | 308 | } |
|---|
| 313 | 309 | |
|---|
| 314 | | -/** |
|---|
| 310 | +/* |
|---|
| 315 | 311 | * Execute pending operations on a vchan |
|---|
| 316 | 312 | * |
|---|
| 317 | 313 | * When given a vchan, this function will try to acquire a suitable |
|---|
| .. | .. |
|---|
| 423 | 419 | return 0; |
|---|
| 424 | 420 | } |
|---|
| 425 | 421 | |
|---|
| 426 | | -/** |
|---|
| 422 | +/* |
|---|
| 427 | 423 | * Generate a promise, to be used in a normal DMA contract. |
|---|
| 428 | 424 | * |
|---|
| 429 | 425 | * A NDMA promise contains all the information required to program the |
|---|
| .. | .. |
|---|
| 490 | 486 | return NULL; |
|---|
| 491 | 487 | } |
|---|
| 492 | 488 | |
|---|
| 493 | | -/** |
|---|
| 489 | +/* |
|---|
| 494 | 490 | * Generate a promise, to be used in a dedicated DMA contract. |
|---|
| 495 | 491 | * |
|---|
| 496 | 492 | * A DDMA promise contains all the information required to program the |
|---|
| .. | .. |
|---|
| 547 | 543 | return NULL; |
|---|
| 548 | 544 | } |
|---|
| 549 | 545 | |
|---|
| 550 | | -/** |
|---|
| 546 | +/* |
|---|
| 551 | 547 | * Generate a contract |
|---|
| 552 | 548 | * |
|---|
| 553 | 549 | * Contracts function as DMA descriptors. As our hardware does not support |
|---|
| .. | .. |
|---|
| 569 | 565 | return contract; |
|---|
| 570 | 566 | } |
|---|
| 571 | 567 | |
|---|
| 572 | | -/** |
|---|
| 568 | +/* |
|---|
| 573 | 569 | * Get next promise on a cyclic transfer |
|---|
| 574 | 570 | * |
|---|
| 575 | 571 | * Cyclic contracts contain a series of promises which are executed on a |
|---|
| .. | .. |
|---|
| 593 | 589 | return promise; |
|---|
| 594 | 590 | } |
|---|
| 595 | 591 | |
|---|
| 596 | | -/** |
|---|
| 592 | +/* |
|---|
| 597 | 593 | * Free a contract and all its associated promises |
|---|
| 598 | 594 | */ |
|---|
| 599 | 595 | static void sun4i_dma_free_contract(struct virt_dma_desc *vd) |
|---|
| .. | .. |
|---|
| 673 | 669 | dma_addr_t src, dest; |
|---|
| 674 | 670 | u32 endpoints; |
|---|
| 675 | 671 | int nr_periods, offset, plength, i; |
|---|
| 672 | + u8 ram_type, io_mode, linear_mode; |
|---|
| 676 | 673 | |
|---|
| 677 | 674 | if (!is_slave_direction(dir)) { |
|---|
| 678 | 675 | dev_err(chan2dev(chan), "Invalid DMA direction\n"); |
|---|
| 679 | | - return NULL; |
|---|
| 680 | | - } |
|---|
| 681 | | - |
|---|
| 682 | | - if (vchan->is_dedicated) { |
|---|
| 683 | | - /* |
|---|
| 684 | | - * As we are using this just for audio data, we need to use |
|---|
| 685 | | - * normal DMA. There is nothing stopping us from supporting |
|---|
| 686 | | - * dedicated DMA here as well, so if a client comes up and |
|---|
| 687 | | - * requires it, it will be simple to implement it. |
|---|
| 688 | | - */ |
|---|
| 689 | | - dev_err(chan2dev(chan), |
|---|
| 690 | | - "Cyclic transfers are only supported on Normal DMA\n"); |
|---|
| 691 | 676 | return NULL; |
|---|
| 692 | 677 | } |
|---|
| 693 | 678 | |
|---|
| .. | .. |
|---|
| 697 | 682 | |
|---|
| 698 | 683 | contract->is_cyclic = 1; |
|---|
| 699 | 684 | |
|---|
| 700 | | - /* Figure out the endpoints and the address we need */ |
|---|
| 685 | + if (vchan->is_dedicated) { |
|---|
| 686 | + io_mode = SUN4I_DDMA_ADDR_MODE_IO; |
|---|
| 687 | + linear_mode = SUN4I_DDMA_ADDR_MODE_LINEAR; |
|---|
| 688 | + ram_type = SUN4I_DDMA_DRQ_TYPE_SDRAM; |
|---|
| 689 | + } else { |
|---|
| 690 | + io_mode = SUN4I_NDMA_ADDR_MODE_IO; |
|---|
| 691 | + linear_mode = SUN4I_NDMA_ADDR_MODE_LINEAR; |
|---|
| 692 | + ram_type = SUN4I_NDMA_DRQ_TYPE_SDRAM; |
|---|
| 693 | + } |
|---|
| 694 | + |
|---|
| 701 | 695 | if (dir == DMA_MEM_TO_DEV) { |
|---|
| 702 | 696 | src = buf; |
|---|
| 703 | 697 | dest = sconfig->dst_addr; |
|---|
| 704 | | - endpoints = SUN4I_DMA_CFG_SRC_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM) | |
|---|
| 705 | | - SUN4I_DMA_CFG_DST_DRQ_TYPE(vchan->endpoint) | |
|---|
| 706 | | - SUN4I_DMA_CFG_DST_ADDR_MODE(SUN4I_NDMA_ADDR_MODE_IO); |
|---|
| 698 | + endpoints = SUN4I_DMA_CFG_DST_DRQ_TYPE(vchan->endpoint) | |
|---|
| 699 | + SUN4I_DMA_CFG_DST_ADDR_MODE(io_mode) | |
|---|
| 700 | + SUN4I_DMA_CFG_SRC_DRQ_TYPE(ram_type) | |
|---|
| 701 | + SUN4I_DMA_CFG_SRC_ADDR_MODE(linear_mode); |
|---|
| 707 | 702 | } else { |
|---|
| 708 | 703 | src = sconfig->src_addr; |
|---|
| 709 | 704 | dest = buf; |
|---|
| 710 | | - endpoints = SUN4I_DMA_CFG_SRC_DRQ_TYPE(vchan->endpoint) | |
|---|
| 711 | | - SUN4I_DMA_CFG_SRC_ADDR_MODE(SUN4I_NDMA_ADDR_MODE_IO) | |
|---|
| 712 | | - SUN4I_DMA_CFG_DST_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM); |
|---|
| 705 | + endpoints = SUN4I_DMA_CFG_DST_DRQ_TYPE(ram_type) | |
|---|
| 706 | + SUN4I_DMA_CFG_DST_ADDR_MODE(linear_mode) | |
|---|
| 707 | + SUN4I_DMA_CFG_SRC_DRQ_TYPE(vchan->endpoint) | |
|---|
| 708 | + SUN4I_DMA_CFG_SRC_ADDR_MODE(io_mode); |
|---|
| 713 | 709 | } |
|---|
| 714 | 710 | |
|---|
| 715 | 711 | /* |
|---|
| .. | .. |
|---|
| 751 | 747 | dest = buf + offset; |
|---|
| 752 | 748 | |
|---|
| 753 | 749 | /* Make the promise */ |
|---|
| 754 | | - promise = generate_ndma_promise(chan, src, dest, |
|---|
| 755 | | - plength, sconfig, dir); |
|---|
| 750 | + if (vchan->is_dedicated) |
|---|
| 751 | + promise = generate_ddma_promise(chan, src, dest, |
|---|
| 752 | + plength, sconfig); |
|---|
| 753 | + else |
|---|
| 754 | + promise = generate_ndma_promise(chan, src, dest, |
|---|
| 755 | + plength, sconfig, dir); |
|---|
| 756 | + |
|---|
| 756 | 757 | if (!promise) { |
|---|
| 757 | 758 | /* TODO: should we free everything? */ |
|---|
| 758 | 759 | return NULL; |
|---|
| .. | .. |
|---|
| 889 | 890 | } |
|---|
| 890 | 891 | |
|---|
| 891 | 892 | spin_lock_irqsave(&vchan->vc.lock, flags); |
|---|
| 892 | | - vchan_dma_desc_free_list(&vchan->vc, &head); |
|---|
| 893 | 893 | /* Clear these so the vchan is usable again */ |
|---|
| 894 | 894 | vchan->processing = NULL; |
|---|
| 895 | 895 | vchan->pchan = NULL; |
|---|
| 896 | 896 | spin_unlock_irqrestore(&vchan->vc.lock, flags); |
|---|
| 897 | + |
|---|
| 898 | + vchan_dma_desc_free_list(&vchan->vc, &head); |
|---|
| 897 | 899 | |
|---|
| 898 | 900 | return 0; |
|---|
| 899 | 901 | } |
|---|
| .. | .. |
|---|
| 1136 | 1138 | return PTR_ERR(priv->base); |
|---|
| 1137 | 1139 | |
|---|
| 1138 | 1140 | priv->irq = platform_get_irq(pdev, 0); |
|---|
| 1139 | | - if (priv->irq < 0) { |
|---|
| 1140 | | - dev_err(&pdev->dev, "Cannot claim IRQ\n"); |
|---|
| 1141 | + if (priv->irq < 0) |
|---|
| 1141 | 1142 | return priv->irq; |
|---|
| 1142 | | - } |
|---|
| 1143 | 1143 | |
|---|
| 1144 | 1144 | priv->clk = devm_clk_get(&pdev->dev, NULL); |
|---|
| 1145 | 1145 | if (IS_ERR(priv->clk)) { |
|---|