| .. | .. |
|---|
| 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"); |
|---|