.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
---|
1 | 2 | /* |
---|
2 | 3 | * BCM2835 DMA engine support |
---|
3 | | - * |
---|
4 | | - * This driver only supports cyclic DMA transfers |
---|
5 | | - * as needed for the I2S module. |
---|
6 | 4 | * |
---|
7 | 5 | * Author: Florian Meier <florian.meier@koalo.de> |
---|
8 | 6 | * Copyright 2013 |
---|
.. | .. |
---|
18 | 16 | * |
---|
19 | 17 | * MARVELL MMP Peripheral DMA Driver |
---|
20 | 18 | * Copyright 2012 Marvell International Ltd. |
---|
21 | | - * |
---|
22 | | - * This program is free software; you can redistribute it and/or modify |
---|
23 | | - * it under the terms of the GNU General Public License as published by |
---|
24 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
25 | | - * (at your option) any later version. |
---|
26 | | - * |
---|
27 | | - * This program is distributed in the hope that it will be useful, |
---|
28 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
29 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
30 | | - * GNU General Public License for more details. |
---|
31 | 19 | */ |
---|
32 | 20 | #include <linux/dmaengine.h> |
---|
33 | 21 | #include <linux/dma-mapping.h> |
---|
.. | .. |
---|
49 | 37 | #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14 |
---|
50 | 38 | #define BCM2835_DMA_CHAN_NAME_SIZE 8 |
---|
51 | 39 | |
---|
| 40 | +/** |
---|
| 41 | + * struct bcm2835_dmadev - BCM2835 DMA controller |
---|
| 42 | + * @ddev: DMA device |
---|
| 43 | + * @base: base address of register map |
---|
| 44 | + * @zero_page: bus address of zero page (to detect transactions copying from |
---|
| 45 | + * zero page and avoid accessing memory if so) |
---|
| 46 | + */ |
---|
52 | 47 | struct bcm2835_dmadev { |
---|
53 | 48 | struct dma_device ddev; |
---|
54 | | - spinlock_t lock; |
---|
55 | 49 | void __iomem *base; |
---|
56 | | - struct device_dma_parameters dma_parms; |
---|
| 50 | + dma_addr_t zero_page; |
---|
57 | 51 | }; |
---|
58 | 52 | |
---|
59 | 53 | struct bcm2835_dma_cb { |
---|
.. | .. |
---|
73 | 67 | |
---|
74 | 68 | struct bcm2835_chan { |
---|
75 | 69 | struct virt_dma_chan vc; |
---|
76 | | - struct list_head node; |
---|
77 | 70 | |
---|
78 | 71 | struct dma_slave_config cfg; |
---|
79 | 72 | unsigned int dreq; |
---|
.. | .. |
---|
321 | 314 | return NULL; |
---|
322 | 315 | |
---|
323 | 316 | /* allocate and setup the descriptor. */ |
---|
324 | | - d = kzalloc(sizeof(*d) + frames * sizeof(struct bcm2835_cb_entry), |
---|
325 | | - gfp); |
---|
| 317 | + d = kzalloc(struct_size(d, cb_list, frames), gfp); |
---|
326 | 318 | if (!d) |
---|
327 | 319 | return NULL; |
---|
328 | 320 | |
---|
.. | .. |
---|
415 | 407 | } |
---|
416 | 408 | } |
---|
417 | 409 | |
---|
418 | | -static int bcm2835_dma_abort(struct bcm2835_chan *c) |
---|
| 410 | +static void bcm2835_dma_abort(struct bcm2835_chan *c) |
---|
419 | 411 | { |
---|
420 | 412 | void __iomem *chan_base = c->chan_base; |
---|
421 | 413 | long int timeout = 10000; |
---|
.. | .. |
---|
425 | 417 | * (The ACTIVE flag in the CS register is not a reliable indicator.) |
---|
426 | 418 | */ |
---|
427 | 419 | if (!readl(chan_base + BCM2835_DMA_ADDR)) |
---|
428 | | - return 0; |
---|
| 420 | + return; |
---|
429 | 421 | |
---|
430 | 422 | /* Write 0 to the active bit - Pause the DMA */ |
---|
431 | 423 | writel(0, chan_base + BCM2835_DMA_CS); |
---|
.. | .. |
---|
441 | 433 | "failed to complete outstanding writes\n"); |
---|
442 | 434 | |
---|
443 | 435 | writel(BCM2835_DMA_RESET, chan_base + BCM2835_DMA_CS); |
---|
444 | | - return 0; |
---|
445 | 436 | } |
---|
446 | 437 | |
---|
447 | 438 | static void bcm2835_dma_start_desc(struct bcm2835_chan *c) |
---|
.. | .. |
---|
513 | 504 | |
---|
514 | 505 | dev_dbg(dev, "Allocating DMA channel %d\n", c->ch); |
---|
515 | 506 | |
---|
| 507 | + /* |
---|
| 508 | + * Control blocks are 256 bit in length and must start at a 256 bit |
---|
| 509 | + * (32 byte) aligned address (BCM2835 ARM Peripherals, sec. 4.2.1.1). |
---|
| 510 | + */ |
---|
516 | 511 | c->cb_pool = dma_pool_create(dev_name(dev), dev, |
---|
517 | | - sizeof(struct bcm2835_dma_cb), 0, 0); |
---|
| 512 | + sizeof(struct bcm2835_dma_cb), 32, 0); |
---|
518 | 513 | if (!c->cb_pool) { |
---|
519 | 514 | dev_err(dev, "unable to allocate descriptor pool\n"); |
---|
520 | 515 | return -ENOMEM; |
---|
.. | .. |
---|
683 | 678 | d = bcm2835_dma_create_cb_chain(chan, direction, false, |
---|
684 | 679 | info, extra, |
---|
685 | 680 | frames, src, dst, 0, 0, |
---|
686 | | - GFP_KERNEL); |
---|
| 681 | + GFP_NOWAIT); |
---|
687 | 682 | if (!d) |
---|
688 | 683 | return NULL; |
---|
689 | 684 | |
---|
.. | .. |
---|
699 | 694 | size_t period_len, enum dma_transfer_direction direction, |
---|
700 | 695 | unsigned long flags) |
---|
701 | 696 | { |
---|
| 697 | + struct bcm2835_dmadev *od = to_bcm2835_dma_dev(chan->device); |
---|
702 | 698 | struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); |
---|
703 | 699 | struct bcm2835_desc *d; |
---|
704 | 700 | dma_addr_t src, dst; |
---|
705 | 701 | u32 info = BCM2835_DMA_WAIT_RESP; |
---|
706 | | - u32 extra = BCM2835_DMA_INT_EN; |
---|
| 702 | + u32 extra = 0; |
---|
707 | 703 | size_t max_len = bcm2835_dma_max_frame_length(c); |
---|
708 | 704 | size_t frames; |
---|
709 | 705 | |
---|
.. | .. |
---|
718 | 714 | "%s: bad buffer length (= 0)\n", __func__); |
---|
719 | 715 | return NULL; |
---|
720 | 716 | } |
---|
| 717 | + |
---|
| 718 | + if (flags & DMA_PREP_INTERRUPT) |
---|
| 719 | + extra |= BCM2835_DMA_INT_EN; |
---|
| 720 | + else |
---|
| 721 | + period_len = buf_len; |
---|
721 | 722 | |
---|
722 | 723 | /* |
---|
723 | 724 | * warn if buf_len is not a multiple of period_len - this may leed |
---|
.. | .. |
---|
744 | 745 | dst = c->cfg.dst_addr; |
---|
745 | 746 | src = buf_addr; |
---|
746 | 747 | info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; |
---|
| 748 | + |
---|
| 749 | + /* non-lite channels can write zeroes w/o accessing memory */ |
---|
| 750 | + if (buf_addr == od->zero_page && !c->is_lite_channel) |
---|
| 751 | + info |= BCM2835_DMA_S_IGNORE; |
---|
747 | 752 | } |
---|
748 | 753 | |
---|
749 | 754 | /* calculate number of frames */ |
---|
.. | .. |
---|
775 | 780 | { |
---|
776 | 781 | struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); |
---|
777 | 782 | |
---|
778 | | - if ((cfg->direction == DMA_DEV_TO_MEM && |
---|
779 | | - cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) || |
---|
780 | | - (cfg->direction == DMA_MEM_TO_DEV && |
---|
781 | | - cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) || |
---|
782 | | - !is_slave_direction(cfg->direction)) { |
---|
783 | | - return -EINVAL; |
---|
784 | | - } |
---|
785 | | - |
---|
786 | 783 | c->cfg = *cfg; |
---|
787 | 784 | |
---|
788 | 785 | return 0; |
---|
.. | .. |
---|
791 | 788 | static int bcm2835_dma_terminate_all(struct dma_chan *chan) |
---|
792 | 789 | { |
---|
793 | 790 | struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); |
---|
794 | | - struct bcm2835_dmadev *d = to_bcm2835_dma_dev(c->vc.chan.device); |
---|
795 | 791 | unsigned long flags; |
---|
796 | 792 | LIST_HEAD(head); |
---|
797 | 793 | |
---|
798 | 794 | spin_lock_irqsave(&c->vc.lock, flags); |
---|
799 | | - |
---|
800 | | - /* Prevent this channel being scheduled */ |
---|
801 | | - spin_lock(&d->lock); |
---|
802 | | - list_del_init(&c->node); |
---|
803 | | - spin_unlock(&d->lock); |
---|
804 | 795 | |
---|
805 | 796 | /* stop DMA activity */ |
---|
806 | 797 | if (c->desc) { |
---|
.. | .. |
---|
834 | 825 | |
---|
835 | 826 | c->vc.desc_free = bcm2835_dma_desc_free; |
---|
836 | 827 | vchan_init(&c->vc, &d->ddev); |
---|
837 | | - INIT_LIST_HEAD(&c->node); |
---|
838 | 828 | |
---|
839 | 829 | c->chan_base = BCM2835_DMA_CHANIO(d->base, chan_id); |
---|
840 | 830 | c->ch = chan_id; |
---|
.. | .. |
---|
858 | 848 | list_del(&c->vc.chan.device_node); |
---|
859 | 849 | tasklet_kill(&c->vc.task); |
---|
860 | 850 | } |
---|
| 851 | + |
---|
| 852 | + dma_unmap_page_attrs(od->ddev.dev, od->zero_page, PAGE_SIZE, |
---|
| 853 | + DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); |
---|
861 | 854 | } |
---|
862 | 855 | |
---|
863 | 856 | static const struct of_device_id bcm2835_dma_of_match[] = { |
---|
.. | .. |
---|
907 | 900 | if (!od) |
---|
908 | 901 | return -ENOMEM; |
---|
909 | 902 | |
---|
910 | | - pdev->dev.dma_parms = &od->dma_parms; |
---|
911 | 903 | dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF); |
---|
912 | 904 | |
---|
913 | 905 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
.. | .. |
---|
920 | 912 | dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); |
---|
921 | 913 | dma_cap_set(DMA_PRIVATE, od->ddev.cap_mask); |
---|
922 | 914 | dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask); |
---|
923 | | - dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); |
---|
924 | 915 | dma_cap_set(DMA_MEMCPY, od->ddev.cap_mask); |
---|
925 | 916 | od->ddev.device_alloc_chan_resources = bcm2835_dma_alloc_chan_resources; |
---|
926 | 917 | od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources; |
---|
.. | .. |
---|
937 | 928 | od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) | |
---|
938 | 929 | BIT(DMA_MEM_TO_MEM); |
---|
939 | 930 | od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; |
---|
| 931 | + od->ddev.descriptor_reuse = true; |
---|
940 | 932 | od->ddev.dev = &pdev->dev; |
---|
941 | 933 | INIT_LIST_HEAD(&od->ddev.channels); |
---|
942 | | - spin_lock_init(&od->lock); |
---|
943 | 934 | |
---|
944 | 935 | platform_set_drvdata(pdev, od); |
---|
| 936 | + |
---|
| 937 | + od->zero_page = dma_map_page_attrs(od->ddev.dev, ZERO_PAGE(0), 0, |
---|
| 938 | + PAGE_SIZE, DMA_TO_DEVICE, |
---|
| 939 | + DMA_ATTR_SKIP_CPU_SYNC); |
---|
| 940 | + if (dma_mapping_error(od->ddev.dev, od->zero_page)) { |
---|
| 941 | + dev_err(&pdev->dev, "Failed to map zero page\n"); |
---|
| 942 | + return -ENOMEM; |
---|
| 943 | + } |
---|
945 | 944 | |
---|
946 | 945 | /* Request DMA channel mask from device tree */ |
---|
947 | 946 | if (of_property_read_u32(pdev->dev.of_node, |
---|
.. | .. |
---|
1046 | 1045 | MODULE_ALIAS("platform:bcm2835-dma"); |
---|
1047 | 1046 | MODULE_DESCRIPTION("BCM2835 DMA engine driver"); |
---|
1048 | 1047 | MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>"); |
---|
1049 | | -MODULE_LICENSE("GPL v2"); |
---|
| 1048 | +MODULE_LICENSE("GPL"); |
---|