18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * DMA driver for Xilinx ZynqMP DMA Engine 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016 Xilinx, Inc. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/bitops.h> 98c2ecf20Sopenharmony_ci#include <linux/dmapool.h> 108c2ecf20Sopenharmony_ci#include <linux/dma/xilinx_dma.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/of_address.h> 168c2ecf20Sopenharmony_ci#include <linux/of_dma.h> 178c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 188c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/clk.h> 218c2ecf20Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h> 228c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "../dmaengine.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* Register Offsets */ 278c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_ISR 0x100 288c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_IMR 0x104 298c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_IER 0x108 308c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_IDS 0x10C 318c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_CTRL0 0x110 328c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_CTRL1 0x114 338c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DATA_ATTR 0x120 348c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DSCR_ATTR 0x124 358c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_SRC_DSCR_WRD0 0x128 368c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_SRC_DSCR_WRD1 0x12C 378c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_SRC_DSCR_WRD2 0x130 388c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_SRC_DSCR_WRD3 0x134 398c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DST_DSCR_WRD0 0x138 408c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DST_DSCR_WRD1 0x13C 418c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DST_DSCR_WRD2 0x140 428c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DST_DSCR_WRD3 0x144 438c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_SRC_START_LSB 0x158 448c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_SRC_START_MSB 0x15C 458c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DST_START_LSB 0x160 468c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DST_START_MSB 0x164 478c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_TOTAL_BYTE 0x188 488c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_RATE_CTRL 0x18C 498c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_IRQ_SRC_ACCT 0x190 508c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_IRQ_DST_ACCT 0x194 518c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_CTRL2 0x200 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* Interrupt registers bit field definitions */ 548c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DONE BIT(10) 558c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AXI_WR_DATA BIT(9) 568c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AXI_RD_DATA BIT(8) 578c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AXI_RD_DST_DSCR BIT(7) 588c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AXI_RD_SRC_DSCR BIT(6) 598c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_IRQ_DST_ACCT_ERR BIT(5) 608c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_IRQ_SRC_ACCT_ERR BIT(4) 618c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_BYTE_CNT_OVRFL BIT(3) 628c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DST_DSCR_DONE BIT(2) 638c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_INV_APB BIT(0) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* Control 0 register bit field definitions */ 668c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_OVR_FETCH BIT(7) 678c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_POINT_TYPE_SG BIT(6) 688c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_RATE_CTRL_EN BIT(3) 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* Control 1 register bit field definitions */ 718c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_SRC_ISSUE GENMASK(4, 0) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* Data Attribute register bit field definitions */ 748c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_ARBURST GENMASK(27, 26) 758c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_ARCACHE GENMASK(25, 22) 768c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_ARCACHE_OFST 22 778c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_ARQOS GENMASK(21, 18) 788c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_ARQOS_OFST 18 798c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_ARLEN GENMASK(17, 14) 808c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_ARLEN_OFST 14 818c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AWBURST GENMASK(13, 12) 828c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AWCACHE GENMASK(11, 8) 838c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AWCACHE_OFST 8 848c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AWQOS GENMASK(7, 4) 858c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AWQOS_OFST 4 868c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AWLEN GENMASK(3, 0) 878c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AWLEN_OFST 0 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* Descriptor Attribute register bit field definitions */ 908c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AXCOHRNT BIT(8) 918c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AXCACHE GENMASK(7, 4) 928c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AXCACHE_OFST 4 938c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AXQOS GENMASK(3, 0) 948c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AXQOS_OFST 0 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* Control register 2 bit field definitions */ 978c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_ENABLE BIT(0) 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* Buffer Descriptor definitions */ 1008c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DESC_CTRL_STOP 0x10 1018c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DESC_CTRL_COMP_INT 0x4 1028c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DESC_CTRL_SIZE_256 0x2 1038c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DESC_CTRL_COHRNT 0x1 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* Interrupt Mask specific definitions */ 1068c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_INT_ERR (ZYNQMP_DMA_AXI_RD_DATA | \ 1078c2ecf20Sopenharmony_ci ZYNQMP_DMA_AXI_WR_DATA | \ 1088c2ecf20Sopenharmony_ci ZYNQMP_DMA_AXI_RD_DST_DSCR | \ 1098c2ecf20Sopenharmony_ci ZYNQMP_DMA_AXI_RD_SRC_DSCR | \ 1108c2ecf20Sopenharmony_ci ZYNQMP_DMA_INV_APB) 1118c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_INT_OVRFL (ZYNQMP_DMA_BYTE_CNT_OVRFL | \ 1128c2ecf20Sopenharmony_ci ZYNQMP_DMA_IRQ_SRC_ACCT_ERR | \ 1138c2ecf20Sopenharmony_ci ZYNQMP_DMA_IRQ_DST_ACCT_ERR) 1148c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_INT_DONE (ZYNQMP_DMA_DONE | ZYNQMP_DMA_DST_DSCR_DONE) 1158c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_INT_EN_DEFAULT_MASK (ZYNQMP_DMA_INT_DONE | \ 1168c2ecf20Sopenharmony_ci ZYNQMP_DMA_INT_ERR | \ 1178c2ecf20Sopenharmony_ci ZYNQMP_DMA_INT_OVRFL | \ 1188c2ecf20Sopenharmony_ci ZYNQMP_DMA_DST_DSCR_DONE) 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* Max number of descriptors per channel */ 1218c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_NUM_DESCS 32 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* Max transfer size per descriptor */ 1248c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_MAX_TRANS_LEN 0x40000000 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/* Max burst lengths */ 1278c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_MAX_DST_BURST_LEN 32768U 1288c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_MAX_SRC_BURST_LEN 32768U 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* Reset values for data attributes */ 1318c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_AXCACHE_VAL 0xF 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_SRC_ISSUE_RST_VAL 0x1F 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_IDS_DEFAULT_MASK 0xFFF 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* Bus width in bits */ 1388c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_BUS_WIDTH_64 64 1398c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_BUS_WIDTH_128 128 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci#define ZDMA_PM_TIMEOUT 100 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_DESC_SIZE(chan) (chan->desc_size) 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci#define to_chan(chan) container_of(chan, struct zynqmp_dma_chan, \ 1468c2ecf20Sopenharmony_ci common) 1478c2ecf20Sopenharmony_ci#define tx_to_desc(tx) container_of(tx, struct zynqmp_dma_desc_sw, \ 1488c2ecf20Sopenharmony_ci async_tx) 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/** 1518c2ecf20Sopenharmony_ci * struct zynqmp_dma_desc_ll - Hw linked list descriptor 1528c2ecf20Sopenharmony_ci * @addr: Buffer address 1538c2ecf20Sopenharmony_ci * @size: Size of the buffer 1548c2ecf20Sopenharmony_ci * @ctrl: Control word 1558c2ecf20Sopenharmony_ci * @nxtdscraddr: Next descriptor base address 1568c2ecf20Sopenharmony_ci * @rsvd: Reserved field and for Hw internal use. 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_cistruct zynqmp_dma_desc_ll { 1598c2ecf20Sopenharmony_ci u64 addr; 1608c2ecf20Sopenharmony_ci u32 size; 1618c2ecf20Sopenharmony_ci u32 ctrl; 1628c2ecf20Sopenharmony_ci u64 nxtdscraddr; 1638c2ecf20Sopenharmony_ci u64 rsvd; 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/** 1678c2ecf20Sopenharmony_ci * struct zynqmp_dma_desc_sw - Per Transaction structure 1688c2ecf20Sopenharmony_ci * @src: Source address for simple mode dma 1698c2ecf20Sopenharmony_ci * @dst: Destination address for simple mode dma 1708c2ecf20Sopenharmony_ci * @len: Transfer length for simple mode dma 1718c2ecf20Sopenharmony_ci * @node: Node in the channel descriptor list 1728c2ecf20Sopenharmony_ci * @tx_list: List head for the current transfer 1738c2ecf20Sopenharmony_ci * @async_tx: Async transaction descriptor 1748c2ecf20Sopenharmony_ci * @src_v: Virtual address of the src descriptor 1758c2ecf20Sopenharmony_ci * @src_p: Physical address of the src descriptor 1768c2ecf20Sopenharmony_ci * @dst_v: Virtual address of the dst descriptor 1778c2ecf20Sopenharmony_ci * @dst_p: Physical address of the dst descriptor 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_cistruct zynqmp_dma_desc_sw { 1808c2ecf20Sopenharmony_ci u64 src; 1818c2ecf20Sopenharmony_ci u64 dst; 1828c2ecf20Sopenharmony_ci u32 len; 1838c2ecf20Sopenharmony_ci struct list_head node; 1848c2ecf20Sopenharmony_ci struct list_head tx_list; 1858c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor async_tx; 1868c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_ll *src_v; 1878c2ecf20Sopenharmony_ci dma_addr_t src_p; 1888c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_ll *dst_v; 1898c2ecf20Sopenharmony_ci dma_addr_t dst_p; 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/** 1938c2ecf20Sopenharmony_ci * struct zynqmp_dma_chan - Driver specific DMA channel structure 1948c2ecf20Sopenharmony_ci * @zdev: Driver specific device structure 1958c2ecf20Sopenharmony_ci * @regs: Control registers offset 1968c2ecf20Sopenharmony_ci * @lock: Descriptor operation lock 1978c2ecf20Sopenharmony_ci * @pending_list: Descriptors waiting 1988c2ecf20Sopenharmony_ci * @free_list: Descriptors free 1998c2ecf20Sopenharmony_ci * @active_list: Descriptors active 2008c2ecf20Sopenharmony_ci * @sw_desc_pool: SW descriptor pool 2018c2ecf20Sopenharmony_ci * @done_list: Complete descriptors 2028c2ecf20Sopenharmony_ci * @common: DMA common channel 2038c2ecf20Sopenharmony_ci * @desc_pool_v: Statically allocated descriptor base 2048c2ecf20Sopenharmony_ci * @desc_pool_p: Physical allocated descriptor base 2058c2ecf20Sopenharmony_ci * @desc_free_cnt: Descriptor available count 2068c2ecf20Sopenharmony_ci * @dev: The dma device 2078c2ecf20Sopenharmony_ci * @irq: Channel IRQ 2088c2ecf20Sopenharmony_ci * @is_dmacoherent: Tells whether dma operations are coherent or not 2098c2ecf20Sopenharmony_ci * @tasklet: Cleanup work after irq 2108c2ecf20Sopenharmony_ci * @idle : Channel status; 2118c2ecf20Sopenharmony_ci * @desc_size: Size of the low level descriptor 2128c2ecf20Sopenharmony_ci * @err: Channel has errors 2138c2ecf20Sopenharmony_ci * @bus_width: Bus width 2148c2ecf20Sopenharmony_ci * @src_burst_len: Source burst length 2158c2ecf20Sopenharmony_ci * @dst_burst_len: Dest burst length 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_cistruct zynqmp_dma_chan { 2188c2ecf20Sopenharmony_ci struct zynqmp_dma_device *zdev; 2198c2ecf20Sopenharmony_ci void __iomem *regs; 2208c2ecf20Sopenharmony_ci spinlock_t lock; 2218c2ecf20Sopenharmony_ci struct list_head pending_list; 2228c2ecf20Sopenharmony_ci struct list_head free_list; 2238c2ecf20Sopenharmony_ci struct list_head active_list; 2248c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw *sw_desc_pool; 2258c2ecf20Sopenharmony_ci struct list_head done_list; 2268c2ecf20Sopenharmony_ci struct dma_chan common; 2278c2ecf20Sopenharmony_ci void *desc_pool_v; 2288c2ecf20Sopenharmony_ci dma_addr_t desc_pool_p; 2298c2ecf20Sopenharmony_ci u32 desc_free_cnt; 2308c2ecf20Sopenharmony_ci struct device *dev; 2318c2ecf20Sopenharmony_ci int irq; 2328c2ecf20Sopenharmony_ci bool is_dmacoherent; 2338c2ecf20Sopenharmony_ci struct tasklet_struct tasklet; 2348c2ecf20Sopenharmony_ci bool idle; 2358c2ecf20Sopenharmony_ci size_t desc_size; 2368c2ecf20Sopenharmony_ci bool err; 2378c2ecf20Sopenharmony_ci u32 bus_width; 2388c2ecf20Sopenharmony_ci u32 src_burst_len; 2398c2ecf20Sopenharmony_ci u32 dst_burst_len; 2408c2ecf20Sopenharmony_ci}; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/** 2438c2ecf20Sopenharmony_ci * struct zynqmp_dma_device - DMA device structure 2448c2ecf20Sopenharmony_ci * @dev: Device Structure 2458c2ecf20Sopenharmony_ci * @common: DMA device structure 2468c2ecf20Sopenharmony_ci * @chan: Driver specific DMA channel 2478c2ecf20Sopenharmony_ci * @clk_main: Pointer to main clock 2488c2ecf20Sopenharmony_ci * @clk_apb: Pointer to apb clock 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_cistruct zynqmp_dma_device { 2518c2ecf20Sopenharmony_ci struct device *dev; 2528c2ecf20Sopenharmony_ci struct dma_device common; 2538c2ecf20Sopenharmony_ci struct zynqmp_dma_chan *chan; 2548c2ecf20Sopenharmony_ci struct clk *clk_main; 2558c2ecf20Sopenharmony_ci struct clk *clk_apb; 2568c2ecf20Sopenharmony_ci}; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic inline void zynqmp_dma_writeq(struct zynqmp_dma_chan *chan, u32 reg, 2598c2ecf20Sopenharmony_ci u64 value) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci lo_hi_writeq(value, chan->regs + reg); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci/** 2658c2ecf20Sopenharmony_ci * zynqmp_dma_update_desc_to_ctrlr - Updates descriptor to the controller 2668c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA DMA channel pointer 2678c2ecf20Sopenharmony_ci * @desc: Transaction descriptor pointer 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_cistatic void zynqmp_dma_update_desc_to_ctrlr(struct zynqmp_dma_chan *chan, 2708c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw *desc) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci dma_addr_t addr; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci addr = desc->src_p; 2758c2ecf20Sopenharmony_ci zynqmp_dma_writeq(chan, ZYNQMP_DMA_SRC_START_LSB, addr); 2768c2ecf20Sopenharmony_ci addr = desc->dst_p; 2778c2ecf20Sopenharmony_ci zynqmp_dma_writeq(chan, ZYNQMP_DMA_DST_START_LSB, addr); 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci/** 2818c2ecf20Sopenharmony_ci * zynqmp_dma_desc_config_eod - Mark the descriptor as end descriptor 2828c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel pointer 2838c2ecf20Sopenharmony_ci * @desc: Hw descriptor pointer 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistatic void zynqmp_dma_desc_config_eod(struct zynqmp_dma_chan *chan, 2868c2ecf20Sopenharmony_ci void *desc) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_ll *hw = (struct zynqmp_dma_desc_ll *)desc; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci hw->ctrl |= ZYNQMP_DMA_DESC_CTRL_STOP; 2918c2ecf20Sopenharmony_ci hw++; 2928c2ecf20Sopenharmony_ci hw->ctrl |= ZYNQMP_DMA_DESC_CTRL_COMP_INT | ZYNQMP_DMA_DESC_CTRL_STOP; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/** 2968c2ecf20Sopenharmony_ci * zynqmp_dma_config_sg_ll_desc - Configure the linked list descriptor 2978c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel pointer 2988c2ecf20Sopenharmony_ci * @sdesc: Hw descriptor pointer 2998c2ecf20Sopenharmony_ci * @src: Source buffer address 3008c2ecf20Sopenharmony_ci * @dst: Destination buffer address 3018c2ecf20Sopenharmony_ci * @len: Transfer length 3028c2ecf20Sopenharmony_ci * @prev: Previous hw descriptor pointer 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_cistatic void zynqmp_dma_config_sg_ll_desc(struct zynqmp_dma_chan *chan, 3058c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_ll *sdesc, 3068c2ecf20Sopenharmony_ci dma_addr_t src, dma_addr_t dst, size_t len, 3078c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_ll *prev) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_ll *ddesc = sdesc + 1; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci sdesc->size = ddesc->size = len; 3128c2ecf20Sopenharmony_ci sdesc->addr = src; 3138c2ecf20Sopenharmony_ci ddesc->addr = dst; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci sdesc->ctrl = ddesc->ctrl = ZYNQMP_DMA_DESC_CTRL_SIZE_256; 3168c2ecf20Sopenharmony_ci if (chan->is_dmacoherent) { 3178c2ecf20Sopenharmony_ci sdesc->ctrl |= ZYNQMP_DMA_DESC_CTRL_COHRNT; 3188c2ecf20Sopenharmony_ci ddesc->ctrl |= ZYNQMP_DMA_DESC_CTRL_COHRNT; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (prev) { 3228c2ecf20Sopenharmony_ci dma_addr_t addr = chan->desc_pool_p + 3238c2ecf20Sopenharmony_ci ((uintptr_t)sdesc - (uintptr_t)chan->desc_pool_v); 3248c2ecf20Sopenharmony_ci ddesc = prev + 1; 3258c2ecf20Sopenharmony_ci prev->nxtdscraddr = addr; 3268c2ecf20Sopenharmony_ci ddesc->nxtdscraddr = addr + ZYNQMP_DMA_DESC_SIZE(chan); 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci/** 3318c2ecf20Sopenharmony_ci * zynqmp_dma_init - Initialize the channel 3328c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel pointer 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_cistatic void zynqmp_dma_init(struct zynqmp_dma_chan *chan) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci u32 val; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci writel(ZYNQMP_DMA_IDS_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IDS); 3398c2ecf20Sopenharmony_ci val = readl(chan->regs + ZYNQMP_DMA_ISR); 3408c2ecf20Sopenharmony_ci writel(val, chan->regs + ZYNQMP_DMA_ISR); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (chan->is_dmacoherent) { 3438c2ecf20Sopenharmony_ci val = ZYNQMP_DMA_AXCOHRNT; 3448c2ecf20Sopenharmony_ci val = (val & ~ZYNQMP_DMA_AXCACHE) | 3458c2ecf20Sopenharmony_ci (ZYNQMP_DMA_AXCACHE_VAL << ZYNQMP_DMA_AXCACHE_OFST); 3468c2ecf20Sopenharmony_ci writel(val, chan->regs + ZYNQMP_DMA_DSCR_ATTR); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci val = readl(chan->regs + ZYNQMP_DMA_DATA_ATTR); 3508c2ecf20Sopenharmony_ci if (chan->is_dmacoherent) { 3518c2ecf20Sopenharmony_ci val = (val & ~ZYNQMP_DMA_ARCACHE) | 3528c2ecf20Sopenharmony_ci (ZYNQMP_DMA_AXCACHE_VAL << ZYNQMP_DMA_ARCACHE_OFST); 3538c2ecf20Sopenharmony_ci val = (val & ~ZYNQMP_DMA_AWCACHE) | 3548c2ecf20Sopenharmony_ci (ZYNQMP_DMA_AXCACHE_VAL << ZYNQMP_DMA_AWCACHE_OFST); 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci writel(val, chan->regs + ZYNQMP_DMA_DATA_ATTR); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* Clearing the interrupt account rgisters */ 3598c2ecf20Sopenharmony_ci val = readl(chan->regs + ZYNQMP_DMA_IRQ_SRC_ACCT); 3608c2ecf20Sopenharmony_ci val = readl(chan->regs + ZYNQMP_DMA_IRQ_DST_ACCT); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci chan->idle = true; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci/** 3668c2ecf20Sopenharmony_ci * zynqmp_dma_tx_submit - Submit DMA transaction 3678c2ecf20Sopenharmony_ci * @tx: Async transaction descriptor pointer 3688c2ecf20Sopenharmony_ci * 3698c2ecf20Sopenharmony_ci * Return: cookie value 3708c2ecf20Sopenharmony_ci */ 3718c2ecf20Sopenharmony_cistatic dma_cookie_t zynqmp_dma_tx_submit(struct dma_async_tx_descriptor *tx) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct zynqmp_dma_chan *chan = to_chan(tx->chan); 3748c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw *desc, *new; 3758c2ecf20Sopenharmony_ci dma_cookie_t cookie; 3768c2ecf20Sopenharmony_ci unsigned long irqflags; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci new = tx_to_desc(tx); 3798c2ecf20Sopenharmony_ci spin_lock_irqsave(&chan->lock, irqflags); 3808c2ecf20Sopenharmony_ci cookie = dma_cookie_assign(tx); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (!list_empty(&chan->pending_list)) { 3838c2ecf20Sopenharmony_ci desc = list_last_entry(&chan->pending_list, 3848c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw, node); 3858c2ecf20Sopenharmony_ci if (!list_empty(&desc->tx_list)) 3868c2ecf20Sopenharmony_ci desc = list_last_entry(&desc->tx_list, 3878c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw, node); 3888c2ecf20Sopenharmony_ci desc->src_v->nxtdscraddr = new->src_p; 3898c2ecf20Sopenharmony_ci desc->src_v->ctrl &= ~ZYNQMP_DMA_DESC_CTRL_STOP; 3908c2ecf20Sopenharmony_ci desc->dst_v->nxtdscraddr = new->dst_p; 3918c2ecf20Sopenharmony_ci desc->dst_v->ctrl &= ~ZYNQMP_DMA_DESC_CTRL_STOP; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci list_add_tail(&new->node, &chan->pending_list); 3958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chan->lock, irqflags); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return cookie; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci/** 4018c2ecf20Sopenharmony_ci * zynqmp_dma_get_descriptor - Get the sw descriptor from the pool 4028c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel pointer 4038c2ecf20Sopenharmony_ci * 4048c2ecf20Sopenharmony_ci * Return: The sw descriptor 4058c2ecf20Sopenharmony_ci */ 4068c2ecf20Sopenharmony_cistatic struct zynqmp_dma_desc_sw * 4078c2ecf20Sopenharmony_cizynqmp_dma_get_descriptor(struct zynqmp_dma_chan *chan) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw *desc; 4108c2ecf20Sopenharmony_ci unsigned long irqflags; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci spin_lock_irqsave(&chan->lock, irqflags); 4138c2ecf20Sopenharmony_ci desc = list_first_entry(&chan->free_list, 4148c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw, node); 4158c2ecf20Sopenharmony_ci list_del(&desc->node); 4168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chan->lock, irqflags); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&desc->tx_list); 4198c2ecf20Sopenharmony_ci /* Clear the src and dst descriptor memory */ 4208c2ecf20Sopenharmony_ci memset((void *)desc->src_v, 0, ZYNQMP_DMA_DESC_SIZE(chan)); 4218c2ecf20Sopenharmony_ci memset((void *)desc->dst_v, 0, ZYNQMP_DMA_DESC_SIZE(chan)); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return desc; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci/** 4278c2ecf20Sopenharmony_ci * zynqmp_dma_free_descriptor - Issue pending transactions 4288c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel pointer 4298c2ecf20Sopenharmony_ci * @sdesc: Transaction descriptor pointer 4308c2ecf20Sopenharmony_ci */ 4318c2ecf20Sopenharmony_cistatic void zynqmp_dma_free_descriptor(struct zynqmp_dma_chan *chan, 4328c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw *sdesc) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw *child, *next; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci chan->desc_free_cnt++; 4378c2ecf20Sopenharmony_ci list_del(&sdesc->node); 4388c2ecf20Sopenharmony_ci list_add_tail(&sdesc->node, &chan->free_list); 4398c2ecf20Sopenharmony_ci list_for_each_entry_safe(child, next, &sdesc->tx_list, node) { 4408c2ecf20Sopenharmony_ci chan->desc_free_cnt++; 4418c2ecf20Sopenharmony_ci list_move_tail(&child->node, &chan->free_list); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci/** 4468c2ecf20Sopenharmony_ci * zynqmp_dma_free_desc_list - Free descriptors list 4478c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel pointer 4488c2ecf20Sopenharmony_ci * @list: List to parse and delete the descriptor 4498c2ecf20Sopenharmony_ci */ 4508c2ecf20Sopenharmony_cistatic void zynqmp_dma_free_desc_list(struct zynqmp_dma_chan *chan, 4518c2ecf20Sopenharmony_ci struct list_head *list) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw *desc, *next; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci list_for_each_entry_safe(desc, next, list, node) 4568c2ecf20Sopenharmony_ci zynqmp_dma_free_descriptor(chan, desc); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci/** 4608c2ecf20Sopenharmony_ci * zynqmp_dma_alloc_chan_resources - Allocate channel resources 4618c2ecf20Sopenharmony_ci * @dchan: DMA channel 4628c2ecf20Sopenharmony_ci * 4638c2ecf20Sopenharmony_ci * Return: Number of descriptors on success and failure value on error 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_cistatic int zynqmp_dma_alloc_chan_resources(struct dma_chan *dchan) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct zynqmp_dma_chan *chan = to_chan(dchan); 4688c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw *desc; 4698c2ecf20Sopenharmony_ci int i, ret; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(chan->dev); 4728c2ecf20Sopenharmony_ci if (ret < 0) 4738c2ecf20Sopenharmony_ci return ret; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci chan->sw_desc_pool = kcalloc(ZYNQMP_DMA_NUM_DESCS, sizeof(*desc), 4768c2ecf20Sopenharmony_ci GFP_KERNEL); 4778c2ecf20Sopenharmony_ci if (!chan->sw_desc_pool) 4788c2ecf20Sopenharmony_ci return -ENOMEM; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci chan->idle = true; 4818c2ecf20Sopenharmony_ci chan->desc_free_cnt = ZYNQMP_DMA_NUM_DESCS; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&chan->free_list); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci for (i = 0; i < ZYNQMP_DMA_NUM_DESCS; i++) { 4868c2ecf20Sopenharmony_ci desc = chan->sw_desc_pool + i; 4878c2ecf20Sopenharmony_ci dma_async_tx_descriptor_init(&desc->async_tx, &chan->common); 4888c2ecf20Sopenharmony_ci desc->async_tx.tx_submit = zynqmp_dma_tx_submit; 4898c2ecf20Sopenharmony_ci list_add_tail(&desc->node, &chan->free_list); 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci chan->desc_pool_v = dma_alloc_coherent(chan->dev, 4938c2ecf20Sopenharmony_ci (2 * ZYNQMP_DMA_DESC_SIZE(chan) * 4948c2ecf20Sopenharmony_ci ZYNQMP_DMA_NUM_DESCS), 4958c2ecf20Sopenharmony_ci &chan->desc_pool_p, GFP_KERNEL); 4968c2ecf20Sopenharmony_ci if (!chan->desc_pool_v) 4978c2ecf20Sopenharmony_ci return -ENOMEM; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci for (i = 0; i < ZYNQMP_DMA_NUM_DESCS; i++) { 5008c2ecf20Sopenharmony_ci desc = chan->sw_desc_pool + i; 5018c2ecf20Sopenharmony_ci desc->src_v = (struct zynqmp_dma_desc_ll *) (chan->desc_pool_v + 5028c2ecf20Sopenharmony_ci (i * ZYNQMP_DMA_DESC_SIZE(chan) * 2)); 5038c2ecf20Sopenharmony_ci desc->dst_v = (struct zynqmp_dma_desc_ll *) (desc->src_v + 1); 5048c2ecf20Sopenharmony_ci desc->src_p = chan->desc_pool_p + 5058c2ecf20Sopenharmony_ci (i * ZYNQMP_DMA_DESC_SIZE(chan) * 2); 5068c2ecf20Sopenharmony_ci desc->dst_p = desc->src_p + ZYNQMP_DMA_DESC_SIZE(chan); 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return ZYNQMP_DMA_NUM_DESCS; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci/** 5138c2ecf20Sopenharmony_ci * zynqmp_dma_start - Start DMA channel 5148c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel pointer 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_cistatic void zynqmp_dma_start(struct zynqmp_dma_chan *chan) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci writel(ZYNQMP_DMA_INT_EN_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IER); 5198c2ecf20Sopenharmony_ci writel(0, chan->regs + ZYNQMP_DMA_TOTAL_BYTE); 5208c2ecf20Sopenharmony_ci chan->idle = false; 5218c2ecf20Sopenharmony_ci writel(ZYNQMP_DMA_ENABLE, chan->regs + ZYNQMP_DMA_CTRL2); 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci/** 5258c2ecf20Sopenharmony_ci * zynqmp_dma_handle_ovfl_int - Process the overflow interrupt 5268c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel pointer 5278c2ecf20Sopenharmony_ci * @status: Interrupt status value 5288c2ecf20Sopenharmony_ci */ 5298c2ecf20Sopenharmony_cistatic void zynqmp_dma_handle_ovfl_int(struct zynqmp_dma_chan *chan, u32 status) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci if (status & ZYNQMP_DMA_BYTE_CNT_OVRFL) 5328c2ecf20Sopenharmony_ci writel(0, chan->regs + ZYNQMP_DMA_TOTAL_BYTE); 5338c2ecf20Sopenharmony_ci if (status & ZYNQMP_DMA_IRQ_DST_ACCT_ERR) 5348c2ecf20Sopenharmony_ci readl(chan->regs + ZYNQMP_DMA_IRQ_DST_ACCT); 5358c2ecf20Sopenharmony_ci if (status & ZYNQMP_DMA_IRQ_SRC_ACCT_ERR) 5368c2ecf20Sopenharmony_ci readl(chan->regs + ZYNQMP_DMA_IRQ_SRC_ACCT); 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic void zynqmp_dma_config(struct zynqmp_dma_chan *chan) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci u32 val, burst_val; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci val = readl(chan->regs + ZYNQMP_DMA_CTRL0); 5448c2ecf20Sopenharmony_ci val |= ZYNQMP_DMA_POINT_TYPE_SG; 5458c2ecf20Sopenharmony_ci writel(val, chan->regs + ZYNQMP_DMA_CTRL0); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci val = readl(chan->regs + ZYNQMP_DMA_DATA_ATTR); 5488c2ecf20Sopenharmony_ci burst_val = __ilog2_u32(chan->src_burst_len); 5498c2ecf20Sopenharmony_ci val = (val & ~ZYNQMP_DMA_ARLEN) | 5508c2ecf20Sopenharmony_ci ((burst_val << ZYNQMP_DMA_ARLEN_OFST) & ZYNQMP_DMA_ARLEN); 5518c2ecf20Sopenharmony_ci burst_val = __ilog2_u32(chan->dst_burst_len); 5528c2ecf20Sopenharmony_ci val = (val & ~ZYNQMP_DMA_AWLEN) | 5538c2ecf20Sopenharmony_ci ((burst_val << ZYNQMP_DMA_AWLEN_OFST) & ZYNQMP_DMA_AWLEN); 5548c2ecf20Sopenharmony_ci writel(val, chan->regs + ZYNQMP_DMA_DATA_ATTR); 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci/** 5588c2ecf20Sopenharmony_ci * zynqmp_dma_device_config - Zynqmp dma device configuration 5598c2ecf20Sopenharmony_ci * @dchan: DMA channel 5608c2ecf20Sopenharmony_ci * @config: DMA device config 5618c2ecf20Sopenharmony_ci * 5628c2ecf20Sopenharmony_ci * Return: 0 always 5638c2ecf20Sopenharmony_ci */ 5648c2ecf20Sopenharmony_cistatic int zynqmp_dma_device_config(struct dma_chan *dchan, 5658c2ecf20Sopenharmony_ci struct dma_slave_config *config) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct zynqmp_dma_chan *chan = to_chan(dchan); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci chan->src_burst_len = clamp(config->src_maxburst, 1U, 5708c2ecf20Sopenharmony_ci ZYNQMP_DMA_MAX_SRC_BURST_LEN); 5718c2ecf20Sopenharmony_ci chan->dst_burst_len = clamp(config->dst_maxburst, 1U, 5728c2ecf20Sopenharmony_ci ZYNQMP_DMA_MAX_DST_BURST_LEN); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci return 0; 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci/** 5788c2ecf20Sopenharmony_ci * zynqmp_dma_start_transfer - Initiate the new transfer 5798c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel pointer 5808c2ecf20Sopenharmony_ci */ 5818c2ecf20Sopenharmony_cistatic void zynqmp_dma_start_transfer(struct zynqmp_dma_chan *chan) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw *desc; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (!chan->idle) 5868c2ecf20Sopenharmony_ci return; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci zynqmp_dma_config(chan); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci desc = list_first_entry_or_null(&chan->pending_list, 5918c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw, node); 5928c2ecf20Sopenharmony_ci if (!desc) 5938c2ecf20Sopenharmony_ci return; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci list_splice_tail_init(&chan->pending_list, &chan->active_list); 5968c2ecf20Sopenharmony_ci zynqmp_dma_update_desc_to_ctrlr(chan, desc); 5978c2ecf20Sopenharmony_ci zynqmp_dma_start(chan); 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/** 6028c2ecf20Sopenharmony_ci * zynqmp_dma_chan_desc_cleanup - Cleanup the completed descriptors 6038c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_cistatic void zynqmp_dma_chan_desc_cleanup(struct zynqmp_dma_chan *chan) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw *desc, *next; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci list_for_each_entry_safe(desc, next, &chan->done_list, node) { 6108c2ecf20Sopenharmony_ci dma_async_tx_callback callback; 6118c2ecf20Sopenharmony_ci void *callback_param; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci callback = desc->async_tx.callback; 6148c2ecf20Sopenharmony_ci callback_param = desc->async_tx.callback_param; 6158c2ecf20Sopenharmony_ci if (callback) { 6168c2ecf20Sopenharmony_ci spin_unlock(&chan->lock); 6178c2ecf20Sopenharmony_ci callback(callback_param); 6188c2ecf20Sopenharmony_ci spin_lock(&chan->lock); 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* Run any dependencies, then free the descriptor */ 6228c2ecf20Sopenharmony_ci zynqmp_dma_free_descriptor(chan, desc); 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci/** 6278c2ecf20Sopenharmony_ci * zynqmp_dma_complete_descriptor - Mark the active descriptor as complete 6288c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel pointer 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_cistatic void zynqmp_dma_complete_descriptor(struct zynqmp_dma_chan *chan) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw *desc; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci desc = list_first_entry_or_null(&chan->active_list, 6358c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw, node); 6368c2ecf20Sopenharmony_ci if (!desc) 6378c2ecf20Sopenharmony_ci return; 6388c2ecf20Sopenharmony_ci list_del(&desc->node); 6398c2ecf20Sopenharmony_ci dma_cookie_complete(&desc->async_tx); 6408c2ecf20Sopenharmony_ci list_add_tail(&desc->node, &chan->done_list); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/** 6448c2ecf20Sopenharmony_ci * zynqmp_dma_issue_pending - Issue pending transactions 6458c2ecf20Sopenharmony_ci * @dchan: DMA channel pointer 6468c2ecf20Sopenharmony_ci */ 6478c2ecf20Sopenharmony_cistatic void zynqmp_dma_issue_pending(struct dma_chan *dchan) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci struct zynqmp_dma_chan *chan = to_chan(dchan); 6508c2ecf20Sopenharmony_ci unsigned long irqflags; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci spin_lock_irqsave(&chan->lock, irqflags); 6538c2ecf20Sopenharmony_ci zynqmp_dma_start_transfer(chan); 6548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chan->lock, irqflags); 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci/** 6588c2ecf20Sopenharmony_ci * zynqmp_dma_free_descriptors - Free channel descriptors 6598c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel pointer 6608c2ecf20Sopenharmony_ci */ 6618c2ecf20Sopenharmony_cistatic void zynqmp_dma_free_descriptors(struct zynqmp_dma_chan *chan) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci zynqmp_dma_free_desc_list(chan, &chan->active_list); 6648c2ecf20Sopenharmony_ci zynqmp_dma_free_desc_list(chan, &chan->pending_list); 6658c2ecf20Sopenharmony_ci zynqmp_dma_free_desc_list(chan, &chan->done_list); 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci/** 6698c2ecf20Sopenharmony_ci * zynqmp_dma_free_chan_resources - Free channel resources 6708c2ecf20Sopenharmony_ci * @dchan: DMA channel pointer 6718c2ecf20Sopenharmony_ci */ 6728c2ecf20Sopenharmony_cistatic void zynqmp_dma_free_chan_resources(struct dma_chan *dchan) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci struct zynqmp_dma_chan *chan = to_chan(dchan); 6758c2ecf20Sopenharmony_ci unsigned long irqflags; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci spin_lock_irqsave(&chan->lock, irqflags); 6788c2ecf20Sopenharmony_ci zynqmp_dma_free_descriptors(chan); 6798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chan->lock, irqflags); 6808c2ecf20Sopenharmony_ci dma_free_coherent(chan->dev, 6818c2ecf20Sopenharmony_ci (2 * ZYNQMP_DMA_DESC_SIZE(chan) * ZYNQMP_DMA_NUM_DESCS), 6828c2ecf20Sopenharmony_ci chan->desc_pool_v, chan->desc_pool_p); 6838c2ecf20Sopenharmony_ci kfree(chan->sw_desc_pool); 6848c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(chan->dev); 6858c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(chan->dev); 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci/** 6898c2ecf20Sopenharmony_ci * zynqmp_dma_reset - Reset the channel 6908c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel pointer 6918c2ecf20Sopenharmony_ci */ 6928c2ecf20Sopenharmony_cistatic void zynqmp_dma_reset(struct zynqmp_dma_chan *chan) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci writel(ZYNQMP_DMA_IDS_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IDS); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci zynqmp_dma_complete_descriptor(chan); 6978c2ecf20Sopenharmony_ci zynqmp_dma_chan_desc_cleanup(chan); 6988c2ecf20Sopenharmony_ci zynqmp_dma_free_descriptors(chan); 6998c2ecf20Sopenharmony_ci zynqmp_dma_init(chan); 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci/** 7038c2ecf20Sopenharmony_ci * zynqmp_dma_irq_handler - ZynqMP DMA Interrupt handler 7048c2ecf20Sopenharmony_ci * @irq: IRQ number 7058c2ecf20Sopenharmony_ci * @data: Pointer to the ZynqMP DMA channel structure 7068c2ecf20Sopenharmony_ci * 7078c2ecf20Sopenharmony_ci * Return: IRQ_HANDLED/IRQ_NONE 7088c2ecf20Sopenharmony_ci */ 7098c2ecf20Sopenharmony_cistatic irqreturn_t zynqmp_dma_irq_handler(int irq, void *data) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci struct zynqmp_dma_chan *chan = (struct zynqmp_dma_chan *)data; 7128c2ecf20Sopenharmony_ci u32 isr, imr, status; 7138c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci isr = readl(chan->regs + ZYNQMP_DMA_ISR); 7168c2ecf20Sopenharmony_ci imr = readl(chan->regs + ZYNQMP_DMA_IMR); 7178c2ecf20Sopenharmony_ci status = isr & ~imr; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci writel(isr, chan->regs + ZYNQMP_DMA_ISR); 7208c2ecf20Sopenharmony_ci if (status & ZYNQMP_DMA_INT_DONE) { 7218c2ecf20Sopenharmony_ci tasklet_schedule(&chan->tasklet); 7228c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (status & ZYNQMP_DMA_DONE) 7268c2ecf20Sopenharmony_ci chan->idle = true; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (status & ZYNQMP_DMA_INT_ERR) { 7298c2ecf20Sopenharmony_ci chan->err = true; 7308c2ecf20Sopenharmony_ci tasklet_schedule(&chan->tasklet); 7318c2ecf20Sopenharmony_ci dev_err(chan->dev, "Channel %p has errors\n", chan); 7328c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (status & ZYNQMP_DMA_INT_OVRFL) { 7368c2ecf20Sopenharmony_ci zynqmp_dma_handle_ovfl_int(chan, status); 7378c2ecf20Sopenharmony_ci dev_dbg(chan->dev, "Channel %p overflow interrupt\n", chan); 7388c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return ret; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci/** 7458c2ecf20Sopenharmony_ci * zynqmp_dma_do_tasklet - Schedule completion tasklet 7468c2ecf20Sopenharmony_ci * @t: Pointer to the ZynqMP DMA channel structure 7478c2ecf20Sopenharmony_ci */ 7488c2ecf20Sopenharmony_cistatic void zynqmp_dma_do_tasklet(struct tasklet_struct *t) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci struct zynqmp_dma_chan *chan = from_tasklet(chan, t, tasklet); 7518c2ecf20Sopenharmony_ci u32 count; 7528c2ecf20Sopenharmony_ci unsigned long irqflags; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci spin_lock_irqsave(&chan->lock, irqflags); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci if (chan->err) { 7578c2ecf20Sopenharmony_ci zynqmp_dma_reset(chan); 7588c2ecf20Sopenharmony_ci chan->err = false; 7598c2ecf20Sopenharmony_ci goto unlock; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci count = readl(chan->regs + ZYNQMP_DMA_IRQ_DST_ACCT); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci while (count) { 7658c2ecf20Sopenharmony_ci zynqmp_dma_complete_descriptor(chan); 7668c2ecf20Sopenharmony_ci zynqmp_dma_chan_desc_cleanup(chan); 7678c2ecf20Sopenharmony_ci count--; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (chan->idle) 7718c2ecf20Sopenharmony_ci zynqmp_dma_start_transfer(chan); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ciunlock: 7748c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chan->lock, irqflags); 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci/** 7788c2ecf20Sopenharmony_ci * zynqmp_dma_device_terminate_all - Aborts all transfers on a channel 7798c2ecf20Sopenharmony_ci * @dchan: DMA channel pointer 7808c2ecf20Sopenharmony_ci * 7818c2ecf20Sopenharmony_ci * Return: Always '0' 7828c2ecf20Sopenharmony_ci */ 7838c2ecf20Sopenharmony_cistatic int zynqmp_dma_device_terminate_all(struct dma_chan *dchan) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci struct zynqmp_dma_chan *chan = to_chan(dchan); 7868c2ecf20Sopenharmony_ci unsigned long irqflags; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci spin_lock_irqsave(&chan->lock, irqflags); 7898c2ecf20Sopenharmony_ci writel(ZYNQMP_DMA_IDS_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IDS); 7908c2ecf20Sopenharmony_ci zynqmp_dma_free_descriptors(chan); 7918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chan->lock, irqflags); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci return 0; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci/** 7978c2ecf20Sopenharmony_ci * zynqmp_dma_prep_memcpy - prepare descriptors for memcpy transaction 7988c2ecf20Sopenharmony_ci * @dchan: DMA channel 7998c2ecf20Sopenharmony_ci * @dma_dst: Destination buffer address 8008c2ecf20Sopenharmony_ci * @dma_src: Source buffer address 8018c2ecf20Sopenharmony_ci * @len: Transfer length 8028c2ecf20Sopenharmony_ci * @flags: transfer ack flags 8038c2ecf20Sopenharmony_ci * 8048c2ecf20Sopenharmony_ci * Return: Async transaction descriptor on success and NULL on failure 8058c2ecf20Sopenharmony_ci */ 8068c2ecf20Sopenharmony_cistatic struct dma_async_tx_descriptor *zynqmp_dma_prep_memcpy( 8078c2ecf20Sopenharmony_ci struct dma_chan *dchan, dma_addr_t dma_dst, 8088c2ecf20Sopenharmony_ci dma_addr_t dma_src, size_t len, ulong flags) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci struct zynqmp_dma_chan *chan; 8118c2ecf20Sopenharmony_ci struct zynqmp_dma_desc_sw *new, *first = NULL; 8128c2ecf20Sopenharmony_ci void *desc = NULL, *prev = NULL; 8138c2ecf20Sopenharmony_ci size_t copy; 8148c2ecf20Sopenharmony_ci u32 desc_cnt; 8158c2ecf20Sopenharmony_ci unsigned long irqflags; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci chan = to_chan(dchan); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci desc_cnt = DIV_ROUND_UP(len, ZYNQMP_DMA_MAX_TRANS_LEN); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci spin_lock_irqsave(&chan->lock, irqflags); 8228c2ecf20Sopenharmony_ci if (desc_cnt > chan->desc_free_cnt) { 8238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chan->lock, irqflags); 8248c2ecf20Sopenharmony_ci dev_dbg(chan->dev, "chan %p descs are not available\n", chan); 8258c2ecf20Sopenharmony_ci return NULL; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci chan->desc_free_cnt = chan->desc_free_cnt - desc_cnt; 8288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chan->lock, irqflags); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci do { 8318c2ecf20Sopenharmony_ci /* Allocate and populate the descriptor */ 8328c2ecf20Sopenharmony_ci new = zynqmp_dma_get_descriptor(chan); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci copy = min_t(size_t, len, ZYNQMP_DMA_MAX_TRANS_LEN); 8358c2ecf20Sopenharmony_ci desc = (struct zynqmp_dma_desc_ll *)new->src_v; 8368c2ecf20Sopenharmony_ci zynqmp_dma_config_sg_ll_desc(chan, desc, dma_src, 8378c2ecf20Sopenharmony_ci dma_dst, copy, prev); 8388c2ecf20Sopenharmony_ci prev = desc; 8398c2ecf20Sopenharmony_ci len -= copy; 8408c2ecf20Sopenharmony_ci dma_src += copy; 8418c2ecf20Sopenharmony_ci dma_dst += copy; 8428c2ecf20Sopenharmony_ci if (!first) 8438c2ecf20Sopenharmony_ci first = new; 8448c2ecf20Sopenharmony_ci else 8458c2ecf20Sopenharmony_ci list_add_tail(&new->node, &first->tx_list); 8468c2ecf20Sopenharmony_ci } while (len); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci zynqmp_dma_desc_config_eod(chan, desc); 8498c2ecf20Sopenharmony_ci async_tx_ack(&first->async_tx); 8508c2ecf20Sopenharmony_ci first->async_tx.flags = flags; 8518c2ecf20Sopenharmony_ci return &first->async_tx; 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci/** 8558c2ecf20Sopenharmony_ci * zynqmp_dma_chan_remove - Channel remove function 8568c2ecf20Sopenharmony_ci * @chan: ZynqMP DMA channel pointer 8578c2ecf20Sopenharmony_ci */ 8588c2ecf20Sopenharmony_cistatic void zynqmp_dma_chan_remove(struct zynqmp_dma_chan *chan) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci if (!chan) 8618c2ecf20Sopenharmony_ci return; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci if (chan->irq) 8648c2ecf20Sopenharmony_ci devm_free_irq(chan->zdev->dev, chan->irq, chan); 8658c2ecf20Sopenharmony_ci tasklet_kill(&chan->tasklet); 8668c2ecf20Sopenharmony_ci list_del(&chan->common.device_node); 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci/** 8708c2ecf20Sopenharmony_ci * zynqmp_dma_chan_probe - Per Channel Probing 8718c2ecf20Sopenharmony_ci * @zdev: Driver specific device structure 8728c2ecf20Sopenharmony_ci * @pdev: Pointer to the platform_device structure 8738c2ecf20Sopenharmony_ci * 8748c2ecf20Sopenharmony_ci * Return: '0' on success and failure value on error 8758c2ecf20Sopenharmony_ci */ 8768c2ecf20Sopenharmony_cistatic int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev, 8778c2ecf20Sopenharmony_ci struct platform_device *pdev) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci struct zynqmp_dma_chan *chan; 8808c2ecf20Sopenharmony_ci struct resource *res; 8818c2ecf20Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 8828c2ecf20Sopenharmony_ci int err; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci chan = devm_kzalloc(zdev->dev, sizeof(*chan), GFP_KERNEL); 8858c2ecf20Sopenharmony_ci if (!chan) 8868c2ecf20Sopenharmony_ci return -ENOMEM; 8878c2ecf20Sopenharmony_ci chan->dev = zdev->dev; 8888c2ecf20Sopenharmony_ci chan->zdev = zdev; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 8918c2ecf20Sopenharmony_ci chan->regs = devm_ioremap_resource(&pdev->dev, res); 8928c2ecf20Sopenharmony_ci if (IS_ERR(chan->regs)) 8938c2ecf20Sopenharmony_ci return PTR_ERR(chan->regs); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci chan->bus_width = ZYNQMP_DMA_BUS_WIDTH_64; 8968c2ecf20Sopenharmony_ci chan->dst_burst_len = ZYNQMP_DMA_MAX_DST_BURST_LEN; 8978c2ecf20Sopenharmony_ci chan->src_burst_len = ZYNQMP_DMA_MAX_SRC_BURST_LEN; 8988c2ecf20Sopenharmony_ci err = of_property_read_u32(node, "xlnx,bus-width", &chan->bus_width); 8998c2ecf20Sopenharmony_ci if (err < 0) { 9008c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "missing xlnx,bus-width property\n"); 9018c2ecf20Sopenharmony_ci return err; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if (chan->bus_width != ZYNQMP_DMA_BUS_WIDTH_64 && 9058c2ecf20Sopenharmony_ci chan->bus_width != ZYNQMP_DMA_BUS_WIDTH_128) { 9068c2ecf20Sopenharmony_ci dev_err(zdev->dev, "invalid bus-width value"); 9078c2ecf20Sopenharmony_ci return -EINVAL; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci chan->is_dmacoherent = of_property_read_bool(node, "dma-coherent"); 9118c2ecf20Sopenharmony_ci zdev->chan = chan; 9128c2ecf20Sopenharmony_ci tasklet_setup(&chan->tasklet, zynqmp_dma_do_tasklet); 9138c2ecf20Sopenharmony_ci spin_lock_init(&chan->lock); 9148c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&chan->active_list); 9158c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&chan->pending_list); 9168c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&chan->done_list); 9178c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&chan->free_list); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci dma_cookie_init(&chan->common); 9208c2ecf20Sopenharmony_ci chan->common.device = &zdev->common; 9218c2ecf20Sopenharmony_ci list_add_tail(&chan->common.device_node, &zdev->common.channels); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci zynqmp_dma_init(chan); 9248c2ecf20Sopenharmony_ci chan->irq = platform_get_irq(pdev, 0); 9258c2ecf20Sopenharmony_ci if (chan->irq < 0) 9268c2ecf20Sopenharmony_ci return -ENXIO; 9278c2ecf20Sopenharmony_ci err = devm_request_irq(&pdev->dev, chan->irq, zynqmp_dma_irq_handler, 0, 9288c2ecf20Sopenharmony_ci "zynqmp-dma", chan); 9298c2ecf20Sopenharmony_ci if (err) 9308c2ecf20Sopenharmony_ci return err; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci chan->desc_size = sizeof(struct zynqmp_dma_desc_ll); 9338c2ecf20Sopenharmony_ci chan->idle = true; 9348c2ecf20Sopenharmony_ci return 0; 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci/** 9388c2ecf20Sopenharmony_ci * of_zynqmp_dma_xlate - Translation function 9398c2ecf20Sopenharmony_ci * @dma_spec: Pointer to DMA specifier as found in the device tree 9408c2ecf20Sopenharmony_ci * @ofdma: Pointer to DMA controller data 9418c2ecf20Sopenharmony_ci * 9428c2ecf20Sopenharmony_ci * Return: DMA channel pointer on success and NULL on error 9438c2ecf20Sopenharmony_ci */ 9448c2ecf20Sopenharmony_cistatic struct dma_chan *of_zynqmp_dma_xlate(struct of_phandle_args *dma_spec, 9458c2ecf20Sopenharmony_ci struct of_dma *ofdma) 9468c2ecf20Sopenharmony_ci{ 9478c2ecf20Sopenharmony_ci struct zynqmp_dma_device *zdev = ofdma->of_dma_data; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci return dma_get_slave_channel(&zdev->chan->common); 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci/** 9538c2ecf20Sopenharmony_ci * zynqmp_dma_suspend - Suspend method for the driver 9548c2ecf20Sopenharmony_ci * @dev: Address of the device structure 9558c2ecf20Sopenharmony_ci * 9568c2ecf20Sopenharmony_ci * Put the driver into low power mode. 9578c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error 9588c2ecf20Sopenharmony_ci */ 9598c2ecf20Sopenharmony_cistatic int __maybe_unused zynqmp_dma_suspend(struct device *dev) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci if (!device_may_wakeup(dev)) 9628c2ecf20Sopenharmony_ci return pm_runtime_force_suspend(dev); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci return 0; 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci/** 9688c2ecf20Sopenharmony_ci * zynqmp_dma_resume - Resume from suspend 9698c2ecf20Sopenharmony_ci * @dev: Address of the device structure 9708c2ecf20Sopenharmony_ci * 9718c2ecf20Sopenharmony_ci * Resume operation after suspend. 9728c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error 9738c2ecf20Sopenharmony_ci */ 9748c2ecf20Sopenharmony_cistatic int __maybe_unused zynqmp_dma_resume(struct device *dev) 9758c2ecf20Sopenharmony_ci{ 9768c2ecf20Sopenharmony_ci if (!device_may_wakeup(dev)) 9778c2ecf20Sopenharmony_ci return pm_runtime_force_resume(dev); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci return 0; 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci/** 9838c2ecf20Sopenharmony_ci * zynqmp_dma_runtime_suspend - Runtime suspend method for the driver 9848c2ecf20Sopenharmony_ci * @dev: Address of the device structure 9858c2ecf20Sopenharmony_ci * 9868c2ecf20Sopenharmony_ci * Put the driver into low power mode. 9878c2ecf20Sopenharmony_ci * Return: 0 always 9888c2ecf20Sopenharmony_ci */ 9898c2ecf20Sopenharmony_cistatic int __maybe_unused zynqmp_dma_runtime_suspend(struct device *dev) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci struct zynqmp_dma_device *zdev = dev_get_drvdata(dev); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci clk_disable_unprepare(zdev->clk_main); 9948c2ecf20Sopenharmony_ci clk_disable_unprepare(zdev->clk_apb); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci return 0; 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci/** 10008c2ecf20Sopenharmony_ci * zynqmp_dma_runtime_resume - Runtime suspend method for the driver 10018c2ecf20Sopenharmony_ci * @dev: Address of the device structure 10028c2ecf20Sopenharmony_ci * 10038c2ecf20Sopenharmony_ci * Put the driver into low power mode. 10048c2ecf20Sopenharmony_ci * Return: 0 always 10058c2ecf20Sopenharmony_ci */ 10068c2ecf20Sopenharmony_cistatic int __maybe_unused zynqmp_dma_runtime_resume(struct device *dev) 10078c2ecf20Sopenharmony_ci{ 10088c2ecf20Sopenharmony_ci struct zynqmp_dma_device *zdev = dev_get_drvdata(dev); 10098c2ecf20Sopenharmony_ci int err; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci err = clk_prepare_enable(zdev->clk_main); 10128c2ecf20Sopenharmony_ci if (err) { 10138c2ecf20Sopenharmony_ci dev_err(dev, "Unable to enable main clock.\n"); 10148c2ecf20Sopenharmony_ci return err; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci err = clk_prepare_enable(zdev->clk_apb); 10188c2ecf20Sopenharmony_ci if (err) { 10198c2ecf20Sopenharmony_ci dev_err(dev, "Unable to enable apb clock.\n"); 10208c2ecf20Sopenharmony_ci clk_disable_unprepare(zdev->clk_main); 10218c2ecf20Sopenharmony_ci return err; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci return 0; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic const struct dev_pm_ops zynqmp_dma_dev_pm_ops = { 10288c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(zynqmp_dma_suspend, zynqmp_dma_resume) 10298c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(zynqmp_dma_runtime_suspend, 10308c2ecf20Sopenharmony_ci zynqmp_dma_runtime_resume, NULL) 10318c2ecf20Sopenharmony_ci}; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci/** 10348c2ecf20Sopenharmony_ci * zynqmp_dma_probe - Driver probe function 10358c2ecf20Sopenharmony_ci * @pdev: Pointer to the platform_device structure 10368c2ecf20Sopenharmony_ci * 10378c2ecf20Sopenharmony_ci * Return: '0' on success and failure value on error 10388c2ecf20Sopenharmony_ci */ 10398c2ecf20Sopenharmony_cistatic int zynqmp_dma_probe(struct platform_device *pdev) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci struct zynqmp_dma_device *zdev; 10428c2ecf20Sopenharmony_ci struct dma_device *p; 10438c2ecf20Sopenharmony_ci int ret; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci zdev = devm_kzalloc(&pdev->dev, sizeof(*zdev), GFP_KERNEL); 10468c2ecf20Sopenharmony_ci if (!zdev) 10478c2ecf20Sopenharmony_ci return -ENOMEM; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci zdev->dev = &pdev->dev; 10508c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&zdev->common.channels); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); 10538c2ecf20Sopenharmony_ci dma_cap_set(DMA_MEMCPY, zdev->common.cap_mask); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci p = &zdev->common; 10568c2ecf20Sopenharmony_ci p->device_prep_dma_memcpy = zynqmp_dma_prep_memcpy; 10578c2ecf20Sopenharmony_ci p->device_terminate_all = zynqmp_dma_device_terminate_all; 10588c2ecf20Sopenharmony_ci p->device_issue_pending = zynqmp_dma_issue_pending; 10598c2ecf20Sopenharmony_ci p->device_alloc_chan_resources = zynqmp_dma_alloc_chan_resources; 10608c2ecf20Sopenharmony_ci p->device_free_chan_resources = zynqmp_dma_free_chan_resources; 10618c2ecf20Sopenharmony_ci p->device_tx_status = dma_cookie_status; 10628c2ecf20Sopenharmony_ci p->device_config = zynqmp_dma_device_config; 10638c2ecf20Sopenharmony_ci p->dev = &pdev->dev; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci zdev->clk_main = devm_clk_get(&pdev->dev, "clk_main"); 10668c2ecf20Sopenharmony_ci if (IS_ERR(zdev->clk_main)) { 10678c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "main clock not found.\n"); 10688c2ecf20Sopenharmony_ci return PTR_ERR(zdev->clk_main); 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci zdev->clk_apb = devm_clk_get(&pdev->dev, "clk_apb"); 10728c2ecf20Sopenharmony_ci if (IS_ERR(zdev->clk_apb)) { 10738c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "apb clock not found.\n"); 10748c2ecf20Sopenharmony_ci return PTR_ERR(zdev->clk_apb); 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, zdev); 10788c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(zdev->dev, ZDMA_PM_TIMEOUT); 10798c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(zdev->dev); 10808c2ecf20Sopenharmony_ci pm_runtime_enable(zdev->dev); 10818c2ecf20Sopenharmony_ci pm_runtime_get_sync(zdev->dev); 10828c2ecf20Sopenharmony_ci if (!pm_runtime_enabled(zdev->dev)) { 10838c2ecf20Sopenharmony_ci ret = zynqmp_dma_runtime_resume(zdev->dev); 10848c2ecf20Sopenharmony_ci if (ret) 10858c2ecf20Sopenharmony_ci return ret; 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci ret = zynqmp_dma_chan_probe(zdev, pdev); 10898c2ecf20Sopenharmony_ci if (ret) { 10908c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Probing channel failed\n"); 10918c2ecf20Sopenharmony_ci goto err_disable_pm; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci p->dst_addr_widths = BIT(zdev->chan->bus_width / 8); 10958c2ecf20Sopenharmony_ci p->src_addr_widths = BIT(zdev->chan->bus_width / 8); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci dma_async_device_register(&zdev->common); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci ret = of_dma_controller_register(pdev->dev.of_node, 11008c2ecf20Sopenharmony_ci of_zynqmp_dma_xlate, zdev); 11018c2ecf20Sopenharmony_ci if (ret) { 11028c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unable to register DMA to DT\n"); 11038c2ecf20Sopenharmony_ci dma_async_device_unregister(&zdev->common); 11048c2ecf20Sopenharmony_ci goto free_chan_resources; 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(zdev->dev); 11088c2ecf20Sopenharmony_ci pm_runtime_put_sync_autosuspend(zdev->dev); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "ZynqMP DMA driver Probe success\n"); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci return 0; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_cifree_chan_resources: 11158c2ecf20Sopenharmony_ci zynqmp_dma_chan_remove(zdev->chan); 11168c2ecf20Sopenharmony_cierr_disable_pm: 11178c2ecf20Sopenharmony_ci if (!pm_runtime_enabled(zdev->dev)) 11188c2ecf20Sopenharmony_ci zynqmp_dma_runtime_suspend(zdev->dev); 11198c2ecf20Sopenharmony_ci pm_runtime_disable(zdev->dev); 11208c2ecf20Sopenharmony_ci return ret; 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci/** 11248c2ecf20Sopenharmony_ci * zynqmp_dma_remove - Driver remove function 11258c2ecf20Sopenharmony_ci * @pdev: Pointer to the platform_device structure 11268c2ecf20Sopenharmony_ci * 11278c2ecf20Sopenharmony_ci * Return: Always '0' 11288c2ecf20Sopenharmony_ci */ 11298c2ecf20Sopenharmony_cistatic int zynqmp_dma_remove(struct platform_device *pdev) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci struct zynqmp_dma_device *zdev = platform_get_drvdata(pdev); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci of_dma_controller_free(pdev->dev.of_node); 11348c2ecf20Sopenharmony_ci dma_async_device_unregister(&zdev->common); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci zynqmp_dma_chan_remove(zdev->chan); 11378c2ecf20Sopenharmony_ci pm_runtime_disable(zdev->dev); 11388c2ecf20Sopenharmony_ci if (!pm_runtime_enabled(zdev->dev)) 11398c2ecf20Sopenharmony_ci zynqmp_dma_runtime_suspend(zdev->dev); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci return 0; 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_cistatic const struct of_device_id zynqmp_dma_of_match[] = { 11458c2ecf20Sopenharmony_ci { .compatible = "xlnx,zynqmp-dma-1.0", }, 11468c2ecf20Sopenharmony_ci {} 11478c2ecf20Sopenharmony_ci}; 11488c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, zynqmp_dma_of_match); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_cistatic struct platform_driver zynqmp_dma_driver = { 11518c2ecf20Sopenharmony_ci .driver = { 11528c2ecf20Sopenharmony_ci .name = "xilinx-zynqmp-dma", 11538c2ecf20Sopenharmony_ci .of_match_table = zynqmp_dma_of_match, 11548c2ecf20Sopenharmony_ci .pm = &zynqmp_dma_dev_pm_ops, 11558c2ecf20Sopenharmony_ci }, 11568c2ecf20Sopenharmony_ci .probe = zynqmp_dma_probe, 11578c2ecf20Sopenharmony_ci .remove = zynqmp_dma_remove, 11588c2ecf20Sopenharmony_ci}; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_cimodule_platform_driver(zynqmp_dma_driver); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 11638c2ecf20Sopenharmony_ciMODULE_AUTHOR("Xilinx, Inc."); 11648c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Xilinx ZynqMP DMA driver"); 1165