xref: /openbmc/linux/drivers/dma/qcom/bam_dma.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
197fb5e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2d9b31efcSSinan Kaya /*
3d9b31efcSSinan Kaya  * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
4d9b31efcSSinan Kaya  */
5d9b31efcSSinan Kaya /*
6d9b31efcSSinan Kaya  * QCOM BAM DMA engine driver
7d9b31efcSSinan Kaya  *
8d9b31efcSSinan Kaya  * QCOM BAM DMA blocks are distributed amongst a number of the on-chip
9d9b31efcSSinan Kaya  * peripherals on the MSM 8x74.  The configuration of the channels are dependent
10d9b31efcSSinan Kaya  * on the way they are hard wired to that specific peripheral.  The peripheral
11d9b31efcSSinan Kaya  * device tree entries specify the configuration of each channel.
12d9b31efcSSinan Kaya  *
13d9b31efcSSinan Kaya  * The DMA controller requires the use of external memory for storage of the
14d9b31efcSSinan Kaya  * hardware descriptors for each channel.  The descriptor FIFO is accessed as a
15d9b31efcSSinan Kaya  * circular buffer and operations are managed according to the offset within the
16d9b31efcSSinan Kaya  * FIFO.  After pipe/channel reset, all of the pipe registers and internal state
17d9b31efcSSinan Kaya  * are back to defaults.
18d9b31efcSSinan Kaya  *
19d9b31efcSSinan Kaya  * During DMA operations, we write descriptors to the FIFO, being careful to
20d9b31efcSSinan Kaya  * handle wrapping and then write the last FIFO offset to that channel's
21d9b31efcSSinan Kaya  * P_EVNT_REG register to kick off the transaction.  The P_SW_OFSTS register
22d9b31efcSSinan Kaya  * indicates the current FIFO offset that is being processed, so there is some
23d9b31efcSSinan Kaya  * indication of where the hardware is currently working.
24d9b31efcSSinan Kaya  */
25d9b31efcSSinan Kaya 
26d9b31efcSSinan Kaya #include <linux/kernel.h>
27d9b31efcSSinan Kaya #include <linux/io.h>
28d9b31efcSSinan Kaya #include <linux/init.h>
29d9b31efcSSinan Kaya #include <linux/slab.h>
30d9b31efcSSinan Kaya #include <linux/module.h>
31d9b31efcSSinan Kaya #include <linux/interrupt.h>
32d9b31efcSSinan Kaya #include <linux/dma-mapping.h>
33d9b31efcSSinan Kaya #include <linux/scatterlist.h>
34d9b31efcSSinan Kaya #include <linux/device.h>
35d9b31efcSSinan Kaya #include <linux/platform_device.h>
36d9b31efcSSinan Kaya #include <linux/of.h>
37d9b31efcSSinan Kaya #include <linux/of_address.h>
38d9b31efcSSinan Kaya #include <linux/of_irq.h>
39d9b31efcSSinan Kaya #include <linux/of_dma.h>
406b4faeacSSricharan R #include <linux/circ_buf.h>
41d9b31efcSSinan Kaya #include <linux/clk.h>
42d9b31efcSSinan Kaya #include <linux/dmaengine.h>
437d254559SPramod Gurav #include <linux/pm_runtime.h>
44d9b31efcSSinan Kaya 
45d9b31efcSSinan Kaya #include "../dmaengine.h"
46d9b31efcSSinan Kaya #include "../virt-dma.h"
47d9b31efcSSinan Kaya 
48d9b31efcSSinan Kaya struct bam_desc_hw {
49d9b31efcSSinan Kaya 	__le32 addr;		/* Buffer physical address */
50d9b31efcSSinan Kaya 	__le16 size;		/* Buffer size in bytes */
51d9b31efcSSinan Kaya 	__le16 flags;
52d9b31efcSSinan Kaya };
53d9b31efcSSinan Kaya 
547d254559SPramod Gurav #define BAM_DMA_AUTOSUSPEND_DELAY 100
557d254559SPramod Gurav 
56d9b31efcSSinan Kaya #define DESC_FLAG_INT BIT(15)
57d9b31efcSSinan Kaya #define DESC_FLAG_EOT BIT(14)
58d9b31efcSSinan Kaya #define DESC_FLAG_EOB BIT(13)
59d9b31efcSSinan Kaya #define DESC_FLAG_NWD BIT(12)
60749d0d4bSAbhishek Sahu #define DESC_FLAG_CMD BIT(11)
61d9b31efcSSinan Kaya 
62d9b31efcSSinan Kaya struct bam_async_desc {
63d9b31efcSSinan Kaya 	struct virt_dma_desc vd;
64d9b31efcSSinan Kaya 
65d9b31efcSSinan Kaya 	u32 num_desc;
66d9b31efcSSinan Kaya 	u32 xfer_len;
67d9b31efcSSinan Kaya 
68d9b31efcSSinan Kaya 	/* transaction flags, EOT|EOB|NWD */
69d9b31efcSSinan Kaya 	u16 flags;
70d9b31efcSSinan Kaya 
71d9b31efcSSinan Kaya 	struct bam_desc_hw *curr_desc;
72d9b31efcSSinan Kaya 
736b4faeacSSricharan R 	/* list node for the desc in the bam_chan list of descriptors */
746b4faeacSSricharan R 	struct list_head desc_node;
75d9b31efcSSinan Kaya 	enum dma_transfer_direction dir;
76d9b31efcSSinan Kaya 	size_t length;
77c18b5bdeSGustavo A. R. Silva 	struct bam_desc_hw desc[];
78d9b31efcSSinan Kaya };
79d9b31efcSSinan Kaya 
80d9b31efcSSinan Kaya enum bam_reg {
81d9b31efcSSinan Kaya 	BAM_CTRL,
82d9b31efcSSinan Kaya 	BAM_REVISION,
83d9b31efcSSinan Kaya 	BAM_NUM_PIPES,
84d9b31efcSSinan Kaya 	BAM_DESC_CNT_TRSHLD,
85d9b31efcSSinan Kaya 	BAM_IRQ_SRCS,
86d9b31efcSSinan Kaya 	BAM_IRQ_SRCS_MSK,
87d9b31efcSSinan Kaya 	BAM_IRQ_SRCS_UNMASKED,
88d9b31efcSSinan Kaya 	BAM_IRQ_STTS,
89d9b31efcSSinan Kaya 	BAM_IRQ_CLR,
90d9b31efcSSinan Kaya 	BAM_IRQ_EN,
91d9b31efcSSinan Kaya 	BAM_CNFG_BITS,
92d9b31efcSSinan Kaya 	BAM_IRQ_SRCS_EE,
93d9b31efcSSinan Kaya 	BAM_IRQ_SRCS_MSK_EE,
94d9b31efcSSinan Kaya 	BAM_P_CTRL,
95d9b31efcSSinan Kaya 	BAM_P_RST,
96d9b31efcSSinan Kaya 	BAM_P_HALT,
97d9b31efcSSinan Kaya 	BAM_P_IRQ_STTS,
98d9b31efcSSinan Kaya 	BAM_P_IRQ_CLR,
99d9b31efcSSinan Kaya 	BAM_P_IRQ_EN,
100d9b31efcSSinan Kaya 	BAM_P_EVNT_DEST_ADDR,
101d9b31efcSSinan Kaya 	BAM_P_EVNT_REG,
102d9b31efcSSinan Kaya 	BAM_P_SW_OFSTS,
103d9b31efcSSinan Kaya 	BAM_P_DATA_FIFO_ADDR,
104d9b31efcSSinan Kaya 	BAM_P_DESC_FIFO_ADDR,
105d9b31efcSSinan Kaya 	BAM_P_EVNT_GEN_TRSHLD,
106d9b31efcSSinan Kaya 	BAM_P_FIFO_SIZES,
107d9b31efcSSinan Kaya };
108d9b31efcSSinan Kaya 
109d9b31efcSSinan Kaya struct reg_offset_data {
110d9b31efcSSinan Kaya 	u32 base_offset;
111d9b31efcSSinan Kaya 	unsigned int pipe_mult, evnt_mult, ee_mult;
112d9b31efcSSinan Kaya };
113d9b31efcSSinan Kaya 
114d9b31efcSSinan Kaya static const struct reg_offset_data bam_v1_3_reg_info[] = {
115d9b31efcSSinan Kaya 	[BAM_CTRL]		= { 0x0F80, 0x00, 0x00, 0x00 },
116d9b31efcSSinan Kaya 	[BAM_REVISION]		= { 0x0F84, 0x00, 0x00, 0x00 },
117d9b31efcSSinan Kaya 	[BAM_NUM_PIPES]		= { 0x0FBC, 0x00, 0x00, 0x00 },
118d9b31efcSSinan Kaya 	[BAM_DESC_CNT_TRSHLD]	= { 0x0F88, 0x00, 0x00, 0x00 },
119d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS]		= { 0x0F8C, 0x00, 0x00, 0x00 },
120d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS_MSK]	= { 0x0F90, 0x00, 0x00, 0x00 },
121d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS_UNMASKED]	= { 0x0FB0, 0x00, 0x00, 0x00 },
122d9b31efcSSinan Kaya 	[BAM_IRQ_STTS]		= { 0x0F94, 0x00, 0x00, 0x00 },
123d9b31efcSSinan Kaya 	[BAM_IRQ_CLR]		= { 0x0F98, 0x00, 0x00, 0x00 },
124d9b31efcSSinan Kaya 	[BAM_IRQ_EN]		= { 0x0F9C, 0x00, 0x00, 0x00 },
125d9b31efcSSinan Kaya 	[BAM_CNFG_BITS]		= { 0x0FFC, 0x00, 0x00, 0x00 },
126d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS_EE]	= { 0x1800, 0x00, 0x00, 0x80 },
127d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS_MSK_EE]	= { 0x1804, 0x00, 0x00, 0x80 },
128d9b31efcSSinan Kaya 	[BAM_P_CTRL]		= { 0x0000, 0x80, 0x00, 0x00 },
129d9b31efcSSinan Kaya 	[BAM_P_RST]		= { 0x0004, 0x80, 0x00, 0x00 },
130d9b31efcSSinan Kaya 	[BAM_P_HALT]		= { 0x0008, 0x80, 0x00, 0x00 },
131d9b31efcSSinan Kaya 	[BAM_P_IRQ_STTS]	= { 0x0010, 0x80, 0x00, 0x00 },
132d9b31efcSSinan Kaya 	[BAM_P_IRQ_CLR]		= { 0x0014, 0x80, 0x00, 0x00 },
133d9b31efcSSinan Kaya 	[BAM_P_IRQ_EN]		= { 0x0018, 0x80, 0x00, 0x00 },
134d9b31efcSSinan Kaya 	[BAM_P_EVNT_DEST_ADDR]	= { 0x102C, 0x00, 0x40, 0x00 },
135d9b31efcSSinan Kaya 	[BAM_P_EVNT_REG]	= { 0x1018, 0x00, 0x40, 0x00 },
136d9b31efcSSinan Kaya 	[BAM_P_SW_OFSTS]	= { 0x1000, 0x00, 0x40, 0x00 },
137d9b31efcSSinan Kaya 	[BAM_P_DATA_FIFO_ADDR]	= { 0x1024, 0x00, 0x40, 0x00 },
138d9b31efcSSinan Kaya 	[BAM_P_DESC_FIFO_ADDR]	= { 0x101C, 0x00, 0x40, 0x00 },
139d9b31efcSSinan Kaya 	[BAM_P_EVNT_GEN_TRSHLD]	= { 0x1028, 0x00, 0x40, 0x00 },
140d9b31efcSSinan Kaya 	[BAM_P_FIFO_SIZES]	= { 0x1020, 0x00, 0x40, 0x00 },
141d9b31efcSSinan Kaya };
142d9b31efcSSinan Kaya 
143d9b31efcSSinan Kaya static const struct reg_offset_data bam_v1_4_reg_info[] = {
144d9b31efcSSinan Kaya 	[BAM_CTRL]		= { 0x0000, 0x00, 0x00, 0x00 },
145d9b31efcSSinan Kaya 	[BAM_REVISION]		= { 0x0004, 0x00, 0x00, 0x00 },
146d9b31efcSSinan Kaya 	[BAM_NUM_PIPES]		= { 0x003C, 0x00, 0x00, 0x00 },
147d9b31efcSSinan Kaya 	[BAM_DESC_CNT_TRSHLD]	= { 0x0008, 0x00, 0x00, 0x00 },
148d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS]		= { 0x000C, 0x00, 0x00, 0x00 },
149d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS_MSK]	= { 0x0010, 0x00, 0x00, 0x00 },
150d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS_UNMASKED]	= { 0x0030, 0x00, 0x00, 0x00 },
151d9b31efcSSinan Kaya 	[BAM_IRQ_STTS]		= { 0x0014, 0x00, 0x00, 0x00 },
152d9b31efcSSinan Kaya 	[BAM_IRQ_CLR]		= { 0x0018, 0x00, 0x00, 0x00 },
153d9b31efcSSinan Kaya 	[BAM_IRQ_EN]		= { 0x001C, 0x00, 0x00, 0x00 },
154d9b31efcSSinan Kaya 	[BAM_CNFG_BITS]		= { 0x007C, 0x00, 0x00, 0x00 },
155d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS_EE]	= { 0x0800, 0x00, 0x00, 0x80 },
156d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS_MSK_EE]	= { 0x0804, 0x00, 0x00, 0x80 },
157d9b31efcSSinan Kaya 	[BAM_P_CTRL]		= { 0x1000, 0x1000, 0x00, 0x00 },
158d9b31efcSSinan Kaya 	[BAM_P_RST]		= { 0x1004, 0x1000, 0x00, 0x00 },
159d9b31efcSSinan Kaya 	[BAM_P_HALT]		= { 0x1008, 0x1000, 0x00, 0x00 },
160d9b31efcSSinan Kaya 	[BAM_P_IRQ_STTS]	= { 0x1010, 0x1000, 0x00, 0x00 },
161d9b31efcSSinan Kaya 	[BAM_P_IRQ_CLR]		= { 0x1014, 0x1000, 0x00, 0x00 },
162d9b31efcSSinan Kaya 	[BAM_P_IRQ_EN]		= { 0x1018, 0x1000, 0x00, 0x00 },
163d9b31efcSSinan Kaya 	[BAM_P_EVNT_DEST_ADDR]	= { 0x182C, 0x00, 0x1000, 0x00 },
164d9b31efcSSinan Kaya 	[BAM_P_EVNT_REG]	= { 0x1818, 0x00, 0x1000, 0x00 },
165d9b31efcSSinan Kaya 	[BAM_P_SW_OFSTS]	= { 0x1800, 0x00, 0x1000, 0x00 },
166d9b31efcSSinan Kaya 	[BAM_P_DATA_FIFO_ADDR]	= { 0x1824, 0x00, 0x1000, 0x00 },
167d9b31efcSSinan Kaya 	[BAM_P_DESC_FIFO_ADDR]	= { 0x181C, 0x00, 0x1000, 0x00 },
168d9b31efcSSinan Kaya 	[BAM_P_EVNT_GEN_TRSHLD]	= { 0x1828, 0x00, 0x1000, 0x00 },
169d9b31efcSSinan Kaya 	[BAM_P_FIFO_SIZES]	= { 0x1820, 0x00, 0x1000, 0x00 },
170d9b31efcSSinan Kaya };
171d9b31efcSSinan Kaya 
172d9b31efcSSinan Kaya static const struct reg_offset_data bam_v1_7_reg_info[] = {
173d9b31efcSSinan Kaya 	[BAM_CTRL]		= { 0x00000, 0x00, 0x00, 0x00 },
174d9b31efcSSinan Kaya 	[BAM_REVISION]		= { 0x01000, 0x00, 0x00, 0x00 },
175d9b31efcSSinan Kaya 	[BAM_NUM_PIPES]		= { 0x01008, 0x00, 0x00, 0x00 },
176d9b31efcSSinan Kaya 	[BAM_DESC_CNT_TRSHLD]	= { 0x00008, 0x00, 0x00, 0x00 },
177d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS]		= { 0x03010, 0x00, 0x00, 0x00 },
178d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS_MSK]	= { 0x03014, 0x00, 0x00, 0x00 },
179d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS_UNMASKED]	= { 0x03018, 0x00, 0x00, 0x00 },
180d9b31efcSSinan Kaya 	[BAM_IRQ_STTS]		= { 0x00014, 0x00, 0x00, 0x00 },
181d9b31efcSSinan Kaya 	[BAM_IRQ_CLR]		= { 0x00018, 0x00, 0x00, 0x00 },
182d9b31efcSSinan Kaya 	[BAM_IRQ_EN]		= { 0x0001C, 0x00, 0x00, 0x00 },
183d9b31efcSSinan Kaya 	[BAM_CNFG_BITS]		= { 0x0007C, 0x00, 0x00, 0x00 },
184d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS_EE]	= { 0x03000, 0x00, 0x00, 0x1000 },
185d9b31efcSSinan Kaya 	[BAM_IRQ_SRCS_MSK_EE]	= { 0x03004, 0x00, 0x00, 0x1000 },
186d9b31efcSSinan Kaya 	[BAM_P_CTRL]		= { 0x13000, 0x1000, 0x00, 0x00 },
187d9b31efcSSinan Kaya 	[BAM_P_RST]		= { 0x13004, 0x1000, 0x00, 0x00 },
188d9b31efcSSinan Kaya 	[BAM_P_HALT]		= { 0x13008, 0x1000, 0x00, 0x00 },
189d9b31efcSSinan Kaya 	[BAM_P_IRQ_STTS]	= { 0x13010, 0x1000, 0x00, 0x00 },
190d9b31efcSSinan Kaya 	[BAM_P_IRQ_CLR]		= { 0x13014, 0x1000, 0x00, 0x00 },
191d9b31efcSSinan Kaya 	[BAM_P_IRQ_EN]		= { 0x13018, 0x1000, 0x00, 0x00 },
192d9b31efcSSinan Kaya 	[BAM_P_EVNT_DEST_ADDR]	= { 0x1382C, 0x00, 0x1000, 0x00 },
193d9b31efcSSinan Kaya 	[BAM_P_EVNT_REG]	= { 0x13818, 0x00, 0x1000, 0x00 },
194d9b31efcSSinan Kaya 	[BAM_P_SW_OFSTS]	= { 0x13800, 0x00, 0x1000, 0x00 },
195d9b31efcSSinan Kaya 	[BAM_P_DATA_FIFO_ADDR]	= { 0x13824, 0x00, 0x1000, 0x00 },
196d9b31efcSSinan Kaya 	[BAM_P_DESC_FIFO_ADDR]	= { 0x1381C, 0x00, 0x1000, 0x00 },
197d9b31efcSSinan Kaya 	[BAM_P_EVNT_GEN_TRSHLD]	= { 0x13828, 0x00, 0x1000, 0x00 },
198d9b31efcSSinan Kaya 	[BAM_P_FIFO_SIZES]	= { 0x13820, 0x00, 0x1000, 0x00 },
199d9b31efcSSinan Kaya };
200d9b31efcSSinan Kaya 
201d9b31efcSSinan Kaya /* BAM CTRL */
202d9b31efcSSinan Kaya #define BAM_SW_RST			BIT(0)
203d9b31efcSSinan Kaya #define BAM_EN				BIT(1)
204d9b31efcSSinan Kaya #define BAM_EN_ACCUM			BIT(4)
205d9b31efcSSinan Kaya #define BAM_TESTBUS_SEL_SHIFT		5
206d9b31efcSSinan Kaya #define BAM_TESTBUS_SEL_MASK		0x3F
207d9b31efcSSinan Kaya #define BAM_DESC_CACHE_SEL_SHIFT	13
208d9b31efcSSinan Kaya #define BAM_DESC_CACHE_SEL_MASK		0x3
209d9b31efcSSinan Kaya #define BAM_CACHED_DESC_STORE		BIT(15)
210d9b31efcSSinan Kaya #define IBC_DISABLE			BIT(16)
211d9b31efcSSinan Kaya 
212d9b31efcSSinan Kaya /* BAM REVISION */
213d9b31efcSSinan Kaya #define REVISION_SHIFT		0
214d9b31efcSSinan Kaya #define REVISION_MASK		0xFF
215d9b31efcSSinan Kaya #define NUM_EES_SHIFT		8
216d9b31efcSSinan Kaya #define NUM_EES_MASK		0xF
217d9b31efcSSinan Kaya #define CE_BUFFER_SIZE		BIT(13)
218d9b31efcSSinan Kaya #define AXI_ACTIVE		BIT(14)
219d9b31efcSSinan Kaya #define USE_VMIDMT		BIT(15)
220d9b31efcSSinan Kaya #define SECURED			BIT(16)
221d9b31efcSSinan Kaya #define BAM_HAS_NO_BYPASS	BIT(17)
222d9b31efcSSinan Kaya #define HIGH_FREQUENCY_BAM	BIT(18)
223d9b31efcSSinan Kaya #define INACTIV_TMRS_EXST	BIT(19)
224d9b31efcSSinan Kaya #define NUM_INACTIV_TMRS	BIT(20)
225d9b31efcSSinan Kaya #define DESC_CACHE_DEPTH_SHIFT	21
226d9b31efcSSinan Kaya #define DESC_CACHE_DEPTH_1	(0 << DESC_CACHE_DEPTH_SHIFT)
227d9b31efcSSinan Kaya #define DESC_CACHE_DEPTH_2	(1 << DESC_CACHE_DEPTH_SHIFT)
228d9b31efcSSinan Kaya #define DESC_CACHE_DEPTH_3	(2 << DESC_CACHE_DEPTH_SHIFT)
229d9b31efcSSinan Kaya #define DESC_CACHE_DEPTH_4	(3 << DESC_CACHE_DEPTH_SHIFT)
230d9b31efcSSinan Kaya #define CMD_DESC_EN		BIT(23)
231d9b31efcSSinan Kaya #define INACTIV_TMR_BASE_SHIFT	24
232d9b31efcSSinan Kaya #define INACTIV_TMR_BASE_MASK	0xFF
233d9b31efcSSinan Kaya 
234d9b31efcSSinan Kaya /* BAM NUM PIPES */
235d9b31efcSSinan Kaya #define BAM_NUM_PIPES_SHIFT		0
236d9b31efcSSinan Kaya #define BAM_NUM_PIPES_MASK		0xFF
237d9b31efcSSinan Kaya #define PERIPH_NON_PIPE_GRP_SHIFT	16
238d9b31efcSSinan Kaya #define PERIPH_NON_PIP_GRP_MASK		0xFF
239d9b31efcSSinan Kaya #define BAM_NON_PIPE_GRP_SHIFT		24
240d9b31efcSSinan Kaya #define BAM_NON_PIPE_GRP_MASK		0xFF
241d9b31efcSSinan Kaya 
242d9b31efcSSinan Kaya /* BAM CNFG BITS */
243d9b31efcSSinan Kaya #define BAM_PIPE_CNFG		BIT(2)
244d9b31efcSSinan Kaya #define BAM_FULL_PIPE		BIT(11)
245d9b31efcSSinan Kaya #define BAM_NO_EXT_P_RST	BIT(12)
246d9b31efcSSinan Kaya #define BAM_IBC_DISABLE		BIT(13)
247d9b31efcSSinan Kaya #define BAM_SB_CLK_REQ		BIT(14)
248d9b31efcSSinan Kaya #define BAM_PSM_CSW_REQ		BIT(15)
249d9b31efcSSinan Kaya #define BAM_PSM_P_RES		BIT(16)
250d9b31efcSSinan Kaya #define BAM_AU_P_RES		BIT(17)
251d9b31efcSSinan Kaya #define BAM_SI_P_RES		BIT(18)
252d9b31efcSSinan Kaya #define BAM_WB_P_RES		BIT(19)
253d9b31efcSSinan Kaya #define BAM_WB_BLK_CSW		BIT(20)
254d9b31efcSSinan Kaya #define BAM_WB_CSW_ACK_IDL	BIT(21)
255d9b31efcSSinan Kaya #define BAM_WB_RETR_SVPNT	BIT(22)
256d9b31efcSSinan Kaya #define BAM_WB_DSC_AVL_P_RST	BIT(23)
257d9b31efcSSinan Kaya #define BAM_REG_P_EN		BIT(24)
258d9b31efcSSinan Kaya #define BAM_PSM_P_HD_DATA	BIT(25)
259d9b31efcSSinan Kaya #define BAM_AU_ACCUMED		BIT(26)
260d9b31efcSSinan Kaya #define BAM_CMD_ENABLE		BIT(27)
261d9b31efcSSinan Kaya 
262d9b31efcSSinan Kaya #define BAM_CNFG_BITS_DEFAULT	(BAM_PIPE_CNFG |	\
263d9b31efcSSinan Kaya 				 BAM_NO_EXT_P_RST |	\
264d9b31efcSSinan Kaya 				 BAM_IBC_DISABLE |	\
265d9b31efcSSinan Kaya 				 BAM_SB_CLK_REQ |	\
266d9b31efcSSinan Kaya 				 BAM_PSM_CSW_REQ |	\
267d9b31efcSSinan Kaya 				 BAM_PSM_P_RES |	\
268d9b31efcSSinan Kaya 				 BAM_AU_P_RES |		\
269d9b31efcSSinan Kaya 				 BAM_SI_P_RES |		\
270d9b31efcSSinan Kaya 				 BAM_WB_P_RES |		\
271d9b31efcSSinan Kaya 				 BAM_WB_BLK_CSW |	\
272d9b31efcSSinan Kaya 				 BAM_WB_CSW_ACK_IDL |	\
273d9b31efcSSinan Kaya 				 BAM_WB_RETR_SVPNT |	\
274d9b31efcSSinan Kaya 				 BAM_WB_DSC_AVL_P_RST |	\
275d9b31efcSSinan Kaya 				 BAM_REG_P_EN |		\
276d9b31efcSSinan Kaya 				 BAM_PSM_P_HD_DATA |	\
277d9b31efcSSinan Kaya 				 BAM_AU_ACCUMED |	\
278d9b31efcSSinan Kaya 				 BAM_CMD_ENABLE)
279d9b31efcSSinan Kaya 
280d9b31efcSSinan Kaya /* PIPE CTRL */
281d9b31efcSSinan Kaya #define P_EN			BIT(1)
282d9b31efcSSinan Kaya #define P_DIRECTION		BIT(3)
283d9b31efcSSinan Kaya #define P_SYS_STRM		BIT(4)
284d9b31efcSSinan Kaya #define P_SYS_MODE		BIT(5)
285d9b31efcSSinan Kaya #define P_AUTO_EOB		BIT(6)
286d9b31efcSSinan Kaya #define P_AUTO_EOB_SEL_SHIFT	7
287d9b31efcSSinan Kaya #define P_AUTO_EOB_SEL_512	(0 << P_AUTO_EOB_SEL_SHIFT)
288d9b31efcSSinan Kaya #define P_AUTO_EOB_SEL_256	(1 << P_AUTO_EOB_SEL_SHIFT)
289d9b31efcSSinan Kaya #define P_AUTO_EOB_SEL_128	(2 << P_AUTO_EOB_SEL_SHIFT)
290d9b31efcSSinan Kaya #define P_AUTO_EOB_SEL_64	(3 << P_AUTO_EOB_SEL_SHIFT)
291d9b31efcSSinan Kaya #define P_PREFETCH_LIMIT_SHIFT	9
292d9b31efcSSinan Kaya #define P_PREFETCH_LIMIT_32	(0 << P_PREFETCH_LIMIT_SHIFT)
293d9b31efcSSinan Kaya #define P_PREFETCH_LIMIT_16	(1 << P_PREFETCH_LIMIT_SHIFT)
294d9b31efcSSinan Kaya #define P_PREFETCH_LIMIT_4	(2 << P_PREFETCH_LIMIT_SHIFT)
295d9b31efcSSinan Kaya #define P_WRITE_NWD		BIT(11)
296d9b31efcSSinan Kaya #define P_LOCK_GROUP_SHIFT	16
297d9b31efcSSinan Kaya #define P_LOCK_GROUP_MASK	0x1F
298d9b31efcSSinan Kaya 
299d9b31efcSSinan Kaya /* BAM_DESC_CNT_TRSHLD */
300d9b31efcSSinan Kaya #define CNT_TRSHLD		0xffff
301d9b31efcSSinan Kaya #define DEFAULT_CNT_THRSHLD	0x4
302d9b31efcSSinan Kaya 
303d9b31efcSSinan Kaya /* BAM_IRQ_SRCS */
304d9b31efcSSinan Kaya #define BAM_IRQ			BIT(31)
305d9b31efcSSinan Kaya #define P_IRQ			0x7fffffff
306d9b31efcSSinan Kaya 
307d9b31efcSSinan Kaya /* BAM_IRQ_SRCS_MSK */
308d9b31efcSSinan Kaya #define BAM_IRQ_MSK		BAM_IRQ
309d9b31efcSSinan Kaya #define P_IRQ_MSK		P_IRQ
310d9b31efcSSinan Kaya 
311d9b31efcSSinan Kaya /* BAM_IRQ_STTS */
312d9b31efcSSinan Kaya #define BAM_TIMER_IRQ		BIT(4)
313d9b31efcSSinan Kaya #define BAM_EMPTY_IRQ		BIT(3)
314d9b31efcSSinan Kaya #define BAM_ERROR_IRQ		BIT(2)
315d9b31efcSSinan Kaya #define BAM_HRESP_ERR_IRQ	BIT(1)
316d9b31efcSSinan Kaya 
317d9b31efcSSinan Kaya /* BAM_IRQ_CLR */
318d9b31efcSSinan Kaya #define BAM_TIMER_CLR		BIT(4)
319d9b31efcSSinan Kaya #define BAM_EMPTY_CLR		BIT(3)
320d9b31efcSSinan Kaya #define BAM_ERROR_CLR		BIT(2)
321d9b31efcSSinan Kaya #define BAM_HRESP_ERR_CLR	BIT(1)
322d9b31efcSSinan Kaya 
323d9b31efcSSinan Kaya /* BAM_IRQ_EN */
324d9b31efcSSinan Kaya #define BAM_TIMER_EN		BIT(4)
325d9b31efcSSinan Kaya #define BAM_EMPTY_EN		BIT(3)
326d9b31efcSSinan Kaya #define BAM_ERROR_EN		BIT(2)
327d9b31efcSSinan Kaya #define BAM_HRESP_ERR_EN	BIT(1)
328d9b31efcSSinan Kaya 
329d9b31efcSSinan Kaya /* BAM_P_IRQ_EN */
330d9b31efcSSinan Kaya #define P_PRCSD_DESC_EN		BIT(0)
331d9b31efcSSinan Kaya #define P_TIMER_EN		BIT(1)
332d9b31efcSSinan Kaya #define P_WAKE_EN		BIT(2)
333d9b31efcSSinan Kaya #define P_OUT_OF_DESC_EN	BIT(3)
334d9b31efcSSinan Kaya #define P_ERR_EN		BIT(4)
335d9b31efcSSinan Kaya #define P_TRNSFR_END_EN		BIT(5)
336d9b31efcSSinan Kaya #define P_DEFAULT_IRQS_EN	(P_PRCSD_DESC_EN | P_ERR_EN | P_TRNSFR_END_EN)
337d9b31efcSSinan Kaya 
338d9b31efcSSinan Kaya /* BAM_P_SW_OFSTS */
339d9b31efcSSinan Kaya #define P_SW_OFSTS_MASK		0xffff
340d9b31efcSSinan Kaya 
341d9b31efcSSinan Kaya #define BAM_DESC_FIFO_SIZE	SZ_32K
342d9b31efcSSinan Kaya #define MAX_DESCRIPTORS (BAM_DESC_FIFO_SIZE / sizeof(struct bam_desc_hw) - 1)
3435ad3f29fSStanimir Varbanov #define BAM_FIFO_SIZE	(SZ_32K - 8)
3446b4faeacSSricharan R #define IS_BUSY(chan)	(CIRC_SPACE(bchan->tail, bchan->head,\
3456b4faeacSSricharan R 			 MAX_DESCRIPTORS + 1) == 0)
346d9b31efcSSinan Kaya 
347d9b31efcSSinan Kaya struct bam_chan {
348d9b31efcSSinan Kaya 	struct virt_dma_chan vc;
349d9b31efcSSinan Kaya 
350d9b31efcSSinan Kaya 	struct bam_device *bdev;
351d9b31efcSSinan Kaya 
352d9b31efcSSinan Kaya 	/* configuration from device tree */
353d9b31efcSSinan Kaya 	u32 id;
354d9b31efcSSinan Kaya 
355d9b31efcSSinan Kaya 	/* runtime configuration */
356d9b31efcSSinan Kaya 	struct dma_slave_config slave;
357d9b31efcSSinan Kaya 
358d9b31efcSSinan Kaya 	/* fifo storage */
359d9b31efcSSinan Kaya 	struct bam_desc_hw *fifo_virt;
360d9b31efcSSinan Kaya 	dma_addr_t fifo_phys;
361d9b31efcSSinan Kaya 
362d9b31efcSSinan Kaya 	/* fifo markers */
363d9b31efcSSinan Kaya 	unsigned short head;		/* start of active descriptor entries */
364d9b31efcSSinan Kaya 	unsigned short tail;		/* end of active descriptor entries */
365d9b31efcSSinan Kaya 
366d9b31efcSSinan Kaya 	unsigned int initialized;	/* is the channel hw initialized? */
367d9b31efcSSinan Kaya 	unsigned int paused;		/* is the channel paused? */
368d9b31efcSSinan Kaya 	unsigned int reconfigure;	/* new slave config? */
3696b4faeacSSricharan R 	/* list of descriptors currently processed */
3706b4faeacSSricharan R 	struct list_head desc_list;
371d9b31efcSSinan Kaya 
372d9b31efcSSinan Kaya 	struct list_head node;
373d9b31efcSSinan Kaya };
374d9b31efcSSinan Kaya 
to_bam_chan(struct dma_chan * common)375d9b31efcSSinan Kaya static inline struct bam_chan *to_bam_chan(struct dma_chan *common)
376d9b31efcSSinan Kaya {
377d9b31efcSSinan Kaya 	return container_of(common, struct bam_chan, vc.chan);
378d9b31efcSSinan Kaya }
379d9b31efcSSinan Kaya 
380d9b31efcSSinan Kaya struct bam_device {
381d9b31efcSSinan Kaya 	void __iomem *regs;
382d9b31efcSSinan Kaya 	struct device *dev;
383d9b31efcSSinan Kaya 	struct dma_device common;
384d9b31efcSSinan Kaya 	struct bam_chan *channels;
385d9b31efcSSinan Kaya 	u32 num_channels;
38648d163b1SSrinivas Kandagatla 	u32 num_ees;
387d9b31efcSSinan Kaya 
388d9b31efcSSinan Kaya 	/* execution environment ID, from DT */
389d9b31efcSSinan Kaya 	u32 ee;
3905172c9ebSStanimir Varbanov 	bool controlled_remotely;
3919502ffcdSStephan Gerhold 	bool powered_remotely;
3929502ffcdSStephan Gerhold 	u32 active_channels;
393d9b31efcSSinan Kaya 
394d9b31efcSSinan Kaya 	const struct reg_offset_data *layout;
395d9b31efcSSinan Kaya 
396d9b31efcSSinan Kaya 	struct clk *bamclk;
397d9b31efcSSinan Kaya 	int irq;
398d9b31efcSSinan Kaya 
399d9b31efcSSinan Kaya 	/* dma start transaction tasklet */
400d9b31efcSSinan Kaya 	struct tasklet_struct task;
401d9b31efcSSinan Kaya };
402d9b31efcSSinan Kaya 
403d9b31efcSSinan Kaya /**
404d9b31efcSSinan Kaya  * bam_addr - returns BAM register address
405d9b31efcSSinan Kaya  * @bdev: bam device
406d9b31efcSSinan Kaya  * @pipe: pipe instance (ignored when register doesn't have multiple instances)
407d9b31efcSSinan Kaya  * @reg:  register enum
408d9b31efcSSinan Kaya  */
bam_addr(struct bam_device * bdev,u32 pipe,enum bam_reg reg)409d9b31efcSSinan Kaya static inline void __iomem *bam_addr(struct bam_device *bdev, u32 pipe,
410d9b31efcSSinan Kaya 		enum bam_reg reg)
411d9b31efcSSinan Kaya {
412d9b31efcSSinan Kaya 	const struct reg_offset_data r = bdev->layout[reg];
413d9b31efcSSinan Kaya 
414d9b31efcSSinan Kaya 	return bdev->regs + r.base_offset +
415d9b31efcSSinan Kaya 		r.pipe_mult * pipe +
416d9b31efcSSinan Kaya 		r.evnt_mult * pipe +
417d9b31efcSSinan Kaya 		r.ee_mult * bdev->ee;
418d9b31efcSSinan Kaya }
419d9b31efcSSinan Kaya 
420d9b31efcSSinan Kaya /**
4219502ffcdSStephan Gerhold  * bam_reset() - reset and initialize BAM registers
4229502ffcdSStephan Gerhold  * @bdev: bam device
4239502ffcdSStephan Gerhold  */
bam_reset(struct bam_device * bdev)4249502ffcdSStephan Gerhold static void bam_reset(struct bam_device *bdev)
4259502ffcdSStephan Gerhold {
4269502ffcdSStephan Gerhold 	u32 val;
4279502ffcdSStephan Gerhold 
4289502ffcdSStephan Gerhold 	/* s/w reset bam */
4299502ffcdSStephan Gerhold 	/* after reset all pipes are disabled and idle */
4309502ffcdSStephan Gerhold 	val = readl_relaxed(bam_addr(bdev, 0, BAM_CTRL));
4319502ffcdSStephan Gerhold 	val |= BAM_SW_RST;
4329502ffcdSStephan Gerhold 	writel_relaxed(val, bam_addr(bdev, 0, BAM_CTRL));
4339502ffcdSStephan Gerhold 	val &= ~BAM_SW_RST;
4349502ffcdSStephan Gerhold 	writel_relaxed(val, bam_addr(bdev, 0, BAM_CTRL));
4359502ffcdSStephan Gerhold 
4369502ffcdSStephan Gerhold 	/* make sure previous stores are visible before enabling BAM */
4379502ffcdSStephan Gerhold 	wmb();
4389502ffcdSStephan Gerhold 
4399502ffcdSStephan Gerhold 	/* enable bam */
4409502ffcdSStephan Gerhold 	val |= BAM_EN;
4419502ffcdSStephan Gerhold 	writel_relaxed(val, bam_addr(bdev, 0, BAM_CTRL));
4429502ffcdSStephan Gerhold 
4439502ffcdSStephan Gerhold 	/* set descriptor threshhold, start with 4 bytes */
4449502ffcdSStephan Gerhold 	writel_relaxed(DEFAULT_CNT_THRSHLD,
4459502ffcdSStephan Gerhold 			bam_addr(bdev, 0, BAM_DESC_CNT_TRSHLD));
4469502ffcdSStephan Gerhold 
4479502ffcdSStephan Gerhold 	/* Enable default set of h/w workarounds, ie all except BAM_FULL_PIPE */
4489502ffcdSStephan Gerhold 	writel_relaxed(BAM_CNFG_BITS_DEFAULT, bam_addr(bdev, 0, BAM_CNFG_BITS));
4499502ffcdSStephan Gerhold 
4509502ffcdSStephan Gerhold 	/* enable irqs for errors */
4519502ffcdSStephan Gerhold 	writel_relaxed(BAM_ERROR_EN | BAM_HRESP_ERR_EN,
4529502ffcdSStephan Gerhold 			bam_addr(bdev, 0, BAM_IRQ_EN));
4539502ffcdSStephan Gerhold 
4549502ffcdSStephan Gerhold 	/* unmask global bam interrupt */
4559502ffcdSStephan Gerhold 	writel_relaxed(BAM_IRQ_MSK, bam_addr(bdev, 0, BAM_IRQ_SRCS_MSK_EE));
4569502ffcdSStephan Gerhold }
4579502ffcdSStephan Gerhold 
4589502ffcdSStephan Gerhold /**
459d9b31efcSSinan Kaya  * bam_reset_channel - Reset individual BAM DMA channel
460d9b31efcSSinan Kaya  * @bchan: bam channel
461d9b31efcSSinan Kaya  *
462d9b31efcSSinan Kaya  * This function resets a specific BAM channel
463d9b31efcSSinan Kaya  */
bam_reset_channel(struct bam_chan * bchan)464d9b31efcSSinan Kaya static void bam_reset_channel(struct bam_chan *bchan)
465d9b31efcSSinan Kaya {
466d9b31efcSSinan Kaya 	struct bam_device *bdev = bchan->bdev;
467d9b31efcSSinan Kaya 
468d9b31efcSSinan Kaya 	lockdep_assert_held(&bchan->vc.lock);
469d9b31efcSSinan Kaya 
470d9b31efcSSinan Kaya 	/* reset channel */
471d9b31efcSSinan Kaya 	writel_relaxed(1, bam_addr(bdev, bchan->id, BAM_P_RST));
472d9b31efcSSinan Kaya 	writel_relaxed(0, bam_addr(bdev, bchan->id, BAM_P_RST));
473d9b31efcSSinan Kaya 
474d9b31efcSSinan Kaya 	/* don't allow cpu to reorder BAM register accesses done after this */
475d9b31efcSSinan Kaya 	wmb();
476d9b31efcSSinan Kaya 
477d9b31efcSSinan Kaya 	/* make sure hw is initialized when channel is used the first time  */
478d9b31efcSSinan Kaya 	bchan->initialized = 0;
479d9b31efcSSinan Kaya }
480d9b31efcSSinan Kaya 
481d9b31efcSSinan Kaya /**
482d9b31efcSSinan Kaya  * bam_chan_init_hw - Initialize channel hardware
483d9b31efcSSinan Kaya  * @bchan: bam channel
4849c3655cbSSrinivas Kandagatla  * @dir: DMA transfer direction
485d9b31efcSSinan Kaya  *
486d9b31efcSSinan Kaya  * This function resets and initializes the BAM channel
487d9b31efcSSinan Kaya  */
bam_chan_init_hw(struct bam_chan * bchan,enum dma_transfer_direction dir)488d9b31efcSSinan Kaya static void bam_chan_init_hw(struct bam_chan *bchan,
489d9b31efcSSinan Kaya 	enum dma_transfer_direction dir)
490d9b31efcSSinan Kaya {
491d9b31efcSSinan Kaya 	struct bam_device *bdev = bchan->bdev;
492d9b31efcSSinan Kaya 	u32 val;
493d9b31efcSSinan Kaya 
494d9b31efcSSinan Kaya 	/* Reset the channel to clear internal state of the FIFO */
495d9b31efcSSinan Kaya 	bam_reset_channel(bchan);
496d9b31efcSSinan Kaya 
497d9b31efcSSinan Kaya 	/*
498d9b31efcSSinan Kaya 	 * write out 8 byte aligned address.  We have enough space for this
499d9b31efcSSinan Kaya 	 * because we allocated 1 more descriptor (8 bytes) than we can use
500d9b31efcSSinan Kaya 	 */
501d9b31efcSSinan Kaya 	writel_relaxed(ALIGN(bchan->fifo_phys, sizeof(struct bam_desc_hw)),
502d9b31efcSSinan Kaya 			bam_addr(bdev, bchan->id, BAM_P_DESC_FIFO_ADDR));
5035ad3f29fSStanimir Varbanov 	writel_relaxed(BAM_FIFO_SIZE,
504d9b31efcSSinan Kaya 			bam_addr(bdev, bchan->id, BAM_P_FIFO_SIZES));
505d9b31efcSSinan Kaya 
506d9b31efcSSinan Kaya 	/* enable the per pipe interrupts, enable EOT, ERR, and INT irqs */
507d9b31efcSSinan Kaya 	writel_relaxed(P_DEFAULT_IRQS_EN,
508d9b31efcSSinan Kaya 			bam_addr(bdev, bchan->id, BAM_P_IRQ_EN));
509d9b31efcSSinan Kaya 
510d9b31efcSSinan Kaya 	/* unmask the specific pipe and EE combo */
511d9b31efcSSinan Kaya 	val = readl_relaxed(bam_addr(bdev, 0, BAM_IRQ_SRCS_MSK_EE));
512d9b31efcSSinan Kaya 	val |= BIT(bchan->id);
513d9b31efcSSinan Kaya 	writel_relaxed(val, bam_addr(bdev, 0, BAM_IRQ_SRCS_MSK_EE));
514d9b31efcSSinan Kaya 
515d9b31efcSSinan Kaya 	/* don't allow cpu to reorder the channel enable done below */
516d9b31efcSSinan Kaya 	wmb();
517d9b31efcSSinan Kaya 
518d9b31efcSSinan Kaya 	/* set fixed direction and mode, then enable channel */
519d9b31efcSSinan Kaya 	val = P_EN | P_SYS_MODE;
520d9b31efcSSinan Kaya 	if (dir == DMA_DEV_TO_MEM)
521d9b31efcSSinan Kaya 		val |= P_DIRECTION;
522d9b31efcSSinan Kaya 
523d9b31efcSSinan Kaya 	writel_relaxed(val, bam_addr(bdev, bchan->id, BAM_P_CTRL));
524d9b31efcSSinan Kaya 
525d9b31efcSSinan Kaya 	bchan->initialized = 1;
526d9b31efcSSinan Kaya 
527d9b31efcSSinan Kaya 	/* init FIFO pointers */
528d9b31efcSSinan Kaya 	bchan->head = 0;
529d9b31efcSSinan Kaya 	bchan->tail = 0;
530d9b31efcSSinan Kaya }
531d9b31efcSSinan Kaya 
532d9b31efcSSinan Kaya /**
533d9b31efcSSinan Kaya  * bam_alloc_chan - Allocate channel resources for DMA channel.
534d9b31efcSSinan Kaya  * @chan: specified channel
535d9b31efcSSinan Kaya  *
536d9b31efcSSinan Kaya  * This function allocates the FIFO descriptor memory
537d9b31efcSSinan Kaya  */
bam_alloc_chan(struct dma_chan * chan)538d9b31efcSSinan Kaya static int bam_alloc_chan(struct dma_chan *chan)
539d9b31efcSSinan Kaya {
540d9b31efcSSinan Kaya 	struct bam_chan *bchan = to_bam_chan(chan);
541d9b31efcSSinan Kaya 	struct bam_device *bdev = bchan->bdev;
542d9b31efcSSinan Kaya 
543d9b31efcSSinan Kaya 	if (bchan->fifo_virt)
544d9b31efcSSinan Kaya 		return 0;
545d9b31efcSSinan Kaya 
546d9b31efcSSinan Kaya 	/* allocate FIFO descriptor space, but only if necessary */
547b5b131c7SLinus Torvalds 	bchan->fifo_virt = dma_alloc_wc(bdev->dev, BAM_DESC_FIFO_SIZE,
548d9b31efcSSinan Kaya 					&bchan->fifo_phys, GFP_KERNEL);
549d9b31efcSSinan Kaya 
550d9b31efcSSinan Kaya 	if (!bchan->fifo_virt) {
551d9b31efcSSinan Kaya 		dev_err(bdev->dev, "Failed to allocate desc fifo\n");
552d9b31efcSSinan Kaya 		return -ENOMEM;
553d9b31efcSSinan Kaya 	}
554d9b31efcSSinan Kaya 
5559502ffcdSStephan Gerhold 	if (bdev->active_channels++ == 0 && bdev->powered_remotely)
5569502ffcdSStephan Gerhold 		bam_reset(bdev);
5579502ffcdSStephan Gerhold 
558d9b31efcSSinan Kaya 	return 0;
559d9b31efcSSinan Kaya }
560d9b31efcSSinan Kaya 
561d9b31efcSSinan Kaya /**
562d9b31efcSSinan Kaya  * bam_free_chan - Frees dma resources associated with specific channel
563d9b31efcSSinan Kaya  * @chan: specified channel
564d9b31efcSSinan Kaya  *
565d9b31efcSSinan Kaya  * Free the allocated fifo descriptor memory and channel resources
566d9b31efcSSinan Kaya  *
567d9b31efcSSinan Kaya  */
bam_free_chan(struct dma_chan * chan)568d9b31efcSSinan Kaya static void bam_free_chan(struct dma_chan *chan)
569d9b31efcSSinan Kaya {
570d9b31efcSSinan Kaya 	struct bam_chan *bchan = to_bam_chan(chan);
571d9b31efcSSinan Kaya 	struct bam_device *bdev = bchan->bdev;
572d9b31efcSSinan Kaya 	u32 val;
573d9b31efcSSinan Kaya 	unsigned long flags;
5747d254559SPramod Gurav 	int ret;
5757d254559SPramod Gurav 
5760ac9c3ddSCaleb Connolly 	ret = pm_runtime_get_sync(bdev->dev);
5777d254559SPramod Gurav 	if (ret < 0)
5787d254559SPramod Gurav 		return;
579d9b31efcSSinan Kaya 
580d9b31efcSSinan Kaya 	vchan_free_chan_resources(to_virt_chan(chan));
581d9b31efcSSinan Kaya 
5826b4faeacSSricharan R 	if (!list_empty(&bchan->desc_list)) {
583d9b31efcSSinan Kaya 		dev_err(bchan->bdev->dev, "Cannot free busy channel\n");
5847d254559SPramod Gurav 		goto err;
585d9b31efcSSinan Kaya 	}
586d9b31efcSSinan Kaya 
587d9b31efcSSinan Kaya 	spin_lock_irqsave(&bchan->vc.lock, flags);
588d9b31efcSSinan Kaya 	bam_reset_channel(bchan);
589d9b31efcSSinan Kaya 	spin_unlock_irqrestore(&bchan->vc.lock, flags);
590d9b31efcSSinan Kaya 
591b5b131c7SLinus Torvalds 	dma_free_wc(bdev->dev, BAM_DESC_FIFO_SIZE, bchan->fifo_virt,
592d9b31efcSSinan Kaya 		    bchan->fifo_phys);
593d9b31efcSSinan Kaya 	bchan->fifo_virt = NULL;
594d9b31efcSSinan Kaya 
595d9b31efcSSinan Kaya 	/* mask irq for pipe/channel */
596d9b31efcSSinan Kaya 	val = readl_relaxed(bam_addr(bdev, 0, BAM_IRQ_SRCS_MSK_EE));
597d9b31efcSSinan Kaya 	val &= ~BIT(bchan->id);
598d9b31efcSSinan Kaya 	writel_relaxed(val, bam_addr(bdev, 0, BAM_IRQ_SRCS_MSK_EE));
599d9b31efcSSinan Kaya 
600d9b31efcSSinan Kaya 	/* disable irq */
601d9b31efcSSinan Kaya 	writel_relaxed(0, bam_addr(bdev, bchan->id, BAM_P_IRQ_EN));
6027d254559SPramod Gurav 
6039502ffcdSStephan Gerhold 	if (--bdev->active_channels == 0 && bdev->powered_remotely) {
6049502ffcdSStephan Gerhold 		/* s/w reset bam */
6059502ffcdSStephan Gerhold 		val = readl_relaxed(bam_addr(bdev, 0, BAM_CTRL));
6069502ffcdSStephan Gerhold 		val |= BAM_SW_RST;
6079502ffcdSStephan Gerhold 		writel_relaxed(val, bam_addr(bdev, 0, BAM_CTRL));
6089502ffcdSStephan Gerhold 	}
6099502ffcdSStephan Gerhold 
6107d254559SPramod Gurav err:
6117d254559SPramod Gurav 	pm_runtime_mark_last_busy(bdev->dev);
6127d254559SPramod Gurav 	pm_runtime_put_autosuspend(bdev->dev);
613d9b31efcSSinan Kaya }
614d9b31efcSSinan Kaya 
615d9b31efcSSinan Kaya /**
616d9b31efcSSinan Kaya  * bam_slave_config - set slave configuration for channel
617d9b31efcSSinan Kaya  * @chan: dma channel
618d9b31efcSSinan Kaya  * @cfg: slave configuration
619d9b31efcSSinan Kaya  *
620d9b31efcSSinan Kaya  * Sets slave configuration for channel
621d9b31efcSSinan Kaya  *
622d9b31efcSSinan Kaya  */
bam_slave_config(struct dma_chan * chan,struct dma_slave_config * cfg)623d9b31efcSSinan Kaya static int bam_slave_config(struct dma_chan *chan,
624d9b31efcSSinan Kaya 			    struct dma_slave_config *cfg)
625d9b31efcSSinan Kaya {
626d9b31efcSSinan Kaya 	struct bam_chan *bchan = to_bam_chan(chan);
627d9b31efcSSinan Kaya 	unsigned long flag;
628d9b31efcSSinan Kaya 
629d9b31efcSSinan Kaya 	spin_lock_irqsave(&bchan->vc.lock, flag);
630d9b31efcSSinan Kaya 	memcpy(&bchan->slave, cfg, sizeof(*cfg));
631d9b31efcSSinan Kaya 	bchan->reconfigure = 1;
632d9b31efcSSinan Kaya 	spin_unlock_irqrestore(&bchan->vc.lock, flag);
633d9b31efcSSinan Kaya 
634d9b31efcSSinan Kaya 	return 0;
635d9b31efcSSinan Kaya }
636d9b31efcSSinan Kaya 
637d9b31efcSSinan Kaya /**
638d9b31efcSSinan Kaya  * bam_prep_slave_sg - Prep slave sg transaction
639d9b31efcSSinan Kaya  *
640d9b31efcSSinan Kaya  * @chan: dma channel
641d9b31efcSSinan Kaya  * @sgl: scatter gather list
642d9b31efcSSinan Kaya  * @sg_len: length of sg
643d9b31efcSSinan Kaya  * @direction: DMA transfer direction
644d9b31efcSSinan Kaya  * @flags: DMA flags
645d9b31efcSSinan Kaya  * @context: transfer context (unused)
646d9b31efcSSinan Kaya  */
bam_prep_slave_sg(struct dma_chan * chan,struct scatterlist * sgl,unsigned int sg_len,enum dma_transfer_direction direction,unsigned long flags,void * context)647d9b31efcSSinan Kaya static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan,
648d9b31efcSSinan Kaya 	struct scatterlist *sgl, unsigned int sg_len,
649d9b31efcSSinan Kaya 	enum dma_transfer_direction direction, unsigned long flags,
650d9b31efcSSinan Kaya 	void *context)
651d9b31efcSSinan Kaya {
652d9b31efcSSinan Kaya 	struct bam_chan *bchan = to_bam_chan(chan);
653d9b31efcSSinan Kaya 	struct bam_device *bdev = bchan->bdev;
654d9b31efcSSinan Kaya 	struct bam_async_desc *async_desc;
655d9b31efcSSinan Kaya 	struct scatterlist *sg;
656d9b31efcSSinan Kaya 	u32 i;
657d9b31efcSSinan Kaya 	struct bam_desc_hw *desc;
658d9b31efcSSinan Kaya 	unsigned int num_alloc = 0;
659d9b31efcSSinan Kaya 
660d9b31efcSSinan Kaya 
661d9b31efcSSinan Kaya 	if (!is_slave_direction(direction)) {
662d9b31efcSSinan Kaya 		dev_err(bdev->dev, "invalid dma direction\n");
663d9b31efcSSinan Kaya 		return NULL;
664d9b31efcSSinan Kaya 	}
665d9b31efcSSinan Kaya 
666d9b31efcSSinan Kaya 	/* calculate number of required entries */
667d9b31efcSSinan Kaya 	for_each_sg(sgl, sg, sg_len, i)
6685ad3f29fSStanimir Varbanov 		num_alloc += DIV_ROUND_UP(sg_dma_len(sg), BAM_FIFO_SIZE);
669d9b31efcSSinan Kaya 
670d9b31efcSSinan Kaya 	/* allocate enough room to accomodate the number of entries */
671edd3c389SGustavo A. R. Silva 	async_desc = kzalloc(struct_size(async_desc, desc, num_alloc),
672edd3c389SGustavo A. R. Silva 			     GFP_NOWAIT);
673d9b31efcSSinan Kaya 
674d9b31efcSSinan Kaya 	if (!async_desc)
675ba42f61bSZheng Yongjun 		return NULL;
676d9b31efcSSinan Kaya 
677d9b31efcSSinan Kaya 	if (flags & DMA_PREP_FENCE)
678d9b31efcSSinan Kaya 		async_desc->flags |= DESC_FLAG_NWD;
679d9b31efcSSinan Kaya 
680d9b31efcSSinan Kaya 	if (flags & DMA_PREP_INTERRUPT)
681d9b31efcSSinan Kaya 		async_desc->flags |= DESC_FLAG_EOT;
682d9b31efcSSinan Kaya 
683d9b31efcSSinan Kaya 	async_desc->num_desc = num_alloc;
684d9b31efcSSinan Kaya 	async_desc->curr_desc = async_desc->desc;
685d9b31efcSSinan Kaya 	async_desc->dir = direction;
686d9b31efcSSinan Kaya 
687d9b31efcSSinan Kaya 	/* fill in temporary descriptors */
688d9b31efcSSinan Kaya 	desc = async_desc->desc;
689d9b31efcSSinan Kaya 	for_each_sg(sgl, sg, sg_len, i) {
690d9b31efcSSinan Kaya 		unsigned int remainder = sg_dma_len(sg);
691d9b31efcSSinan Kaya 		unsigned int curr_offset = 0;
692d9b31efcSSinan Kaya 
693d9b31efcSSinan Kaya 		do {
694749d0d4bSAbhishek Sahu 			if (flags & DMA_PREP_CMD)
695749d0d4bSAbhishek Sahu 				desc->flags |= cpu_to_le16(DESC_FLAG_CMD);
696749d0d4bSAbhishek Sahu 
697d9b31efcSSinan Kaya 			desc->addr = cpu_to_le32(sg_dma_address(sg) +
698d9b31efcSSinan Kaya 						 curr_offset);
699d9b31efcSSinan Kaya 
7005ad3f29fSStanimir Varbanov 			if (remainder > BAM_FIFO_SIZE) {
7015ad3f29fSStanimir Varbanov 				desc->size = cpu_to_le16(BAM_FIFO_SIZE);
7025ad3f29fSStanimir Varbanov 				remainder -= BAM_FIFO_SIZE;
7035ad3f29fSStanimir Varbanov 				curr_offset += BAM_FIFO_SIZE;
704d9b31efcSSinan Kaya 			} else {
705d9b31efcSSinan Kaya 				desc->size = cpu_to_le16(remainder);
706d9b31efcSSinan Kaya 				remainder = 0;
707d9b31efcSSinan Kaya 			}
708d9b31efcSSinan Kaya 
7095c63de1eSSrinivas Kandagatla 			async_desc->length += le16_to_cpu(desc->size);
710d9b31efcSSinan Kaya 			desc++;
711d9b31efcSSinan Kaya 		} while (remainder > 0);
712d9b31efcSSinan Kaya 	}
713d9b31efcSSinan Kaya 
714d9b31efcSSinan Kaya 	return vchan_tx_prep(&bchan->vc, &async_desc->vd, flags);
715d9b31efcSSinan Kaya }
716d9b31efcSSinan Kaya 
717d9b31efcSSinan Kaya /**
718d9b31efcSSinan Kaya  * bam_dma_terminate_all - terminate all transactions on a channel
7199c3655cbSSrinivas Kandagatla  * @chan: bam dma channel
720d9b31efcSSinan Kaya  *
721d9b31efcSSinan Kaya  * Dequeues and frees all transactions
722d9b31efcSSinan Kaya  * No callbacks are done
723d9b31efcSSinan Kaya  *
724d9b31efcSSinan Kaya  */
bam_dma_terminate_all(struct dma_chan * chan)725d9b31efcSSinan Kaya static int bam_dma_terminate_all(struct dma_chan *chan)
726d9b31efcSSinan Kaya {
727d9b31efcSSinan Kaya 	struct bam_chan *bchan = to_bam_chan(chan);
7286b4faeacSSricharan R 	struct bam_async_desc *async_desc, *tmp;
729d9b31efcSSinan Kaya 	unsigned long flag;
730d9b31efcSSinan Kaya 	LIST_HEAD(head);
731d9b31efcSSinan Kaya 
732d9b31efcSSinan Kaya 	/* remove all transactions, including active transaction */
733d9b31efcSSinan Kaya 	spin_lock_irqsave(&bchan->vc.lock, flag);
73476678193SJeffrey Hugo 	/*
73576678193SJeffrey Hugo 	 * If we have transactions queued, then some might be committed to the
73676678193SJeffrey Hugo 	 * hardware in the desc fifo.  The only way to reset the desc fifo is
73776678193SJeffrey Hugo 	 * to do a hardware reset (either by pipe or the entire block).
73876678193SJeffrey Hugo 	 * bam_chan_init_hw() will trigger a pipe reset, and also reinit the
73976678193SJeffrey Hugo 	 * pipe.  If the pipe is left disabled (default state after pipe reset)
74076678193SJeffrey Hugo 	 * and is accessed by a connected hardware engine, a fatal error in
74176678193SJeffrey Hugo 	 * the BAM will occur.  There is a small window where this could happen
74276678193SJeffrey Hugo 	 * with bam_chan_init_hw(), but it is assumed that the caller has
74376678193SJeffrey Hugo 	 * stopped activity on any attached hardware engine.  Make sure to do
74476678193SJeffrey Hugo 	 * this first so that the BAM hardware doesn't cause memory corruption
74576678193SJeffrey Hugo 	 * by accessing freed resources.
74676678193SJeffrey Hugo 	 */
74776678193SJeffrey Hugo 	if (!list_empty(&bchan->desc_list)) {
74876678193SJeffrey Hugo 		async_desc = list_first_entry(&bchan->desc_list,
74976678193SJeffrey Hugo 					      struct bam_async_desc, desc_node);
75076678193SJeffrey Hugo 		bam_chan_init_hw(bchan, async_desc->dir);
75176678193SJeffrey Hugo 	}
75276678193SJeffrey Hugo 
7536b4faeacSSricharan R 	list_for_each_entry_safe(async_desc, tmp,
7546b4faeacSSricharan R 				 &bchan->desc_list, desc_node) {
7556b4faeacSSricharan R 		list_add(&async_desc->vd.node, &bchan->vc.desc_issued);
7566b4faeacSSricharan R 		list_del(&async_desc->desc_node);
757d9b31efcSSinan Kaya 	}
758d9b31efcSSinan Kaya 
759d9b31efcSSinan Kaya 	vchan_get_all_descriptors(&bchan->vc, &head);
760d9b31efcSSinan Kaya 	spin_unlock_irqrestore(&bchan->vc.lock, flag);
761d9b31efcSSinan Kaya 
762d9b31efcSSinan Kaya 	vchan_dma_desc_free_list(&bchan->vc, &head);
763d9b31efcSSinan Kaya 
764d9b31efcSSinan Kaya 	return 0;
765d9b31efcSSinan Kaya }
766d9b31efcSSinan Kaya 
767d9b31efcSSinan Kaya /**
768d9b31efcSSinan Kaya  * bam_pause - Pause DMA channel
769d9b31efcSSinan Kaya  * @chan: dma channel
770d9b31efcSSinan Kaya  *
771d9b31efcSSinan Kaya  */
bam_pause(struct dma_chan * chan)772d9b31efcSSinan Kaya static int bam_pause(struct dma_chan *chan)
773d9b31efcSSinan Kaya {
774d9b31efcSSinan Kaya 	struct bam_chan *bchan = to_bam_chan(chan);
775d9b31efcSSinan Kaya 	struct bam_device *bdev = bchan->bdev;
776d9b31efcSSinan Kaya 	unsigned long flag;
7777d254559SPramod Gurav 	int ret;
7787d254559SPramod Gurav 
7790ac9c3ddSCaleb Connolly 	ret = pm_runtime_get_sync(bdev->dev);
7807d254559SPramod Gurav 	if (ret < 0)
7817d254559SPramod Gurav 		return ret;
782d9b31efcSSinan Kaya 
783d9b31efcSSinan Kaya 	spin_lock_irqsave(&bchan->vc.lock, flag);
784d9b31efcSSinan Kaya 	writel_relaxed(1, bam_addr(bdev, bchan->id, BAM_P_HALT));
785d9b31efcSSinan Kaya 	bchan->paused = 1;
786d9b31efcSSinan Kaya 	spin_unlock_irqrestore(&bchan->vc.lock, flag);
7877d254559SPramod Gurav 	pm_runtime_mark_last_busy(bdev->dev);
7887d254559SPramod Gurav 	pm_runtime_put_autosuspend(bdev->dev);
789d9b31efcSSinan Kaya 
790d9b31efcSSinan Kaya 	return 0;
791d9b31efcSSinan Kaya }
792d9b31efcSSinan Kaya 
793d9b31efcSSinan Kaya /**
794d9b31efcSSinan Kaya  * bam_resume - Resume DMA channel operations
795d9b31efcSSinan Kaya  * @chan: dma channel
796d9b31efcSSinan Kaya  *
797d9b31efcSSinan Kaya  */
bam_resume(struct dma_chan * chan)798d9b31efcSSinan Kaya static int bam_resume(struct dma_chan *chan)
799d9b31efcSSinan Kaya {
800d9b31efcSSinan Kaya 	struct bam_chan *bchan = to_bam_chan(chan);
801d9b31efcSSinan Kaya 	struct bam_device *bdev = bchan->bdev;
802d9b31efcSSinan Kaya 	unsigned long flag;
8037d254559SPramod Gurav 	int ret;
8047d254559SPramod Gurav 
8050ac9c3ddSCaleb Connolly 	ret = pm_runtime_get_sync(bdev->dev);
8067d254559SPramod Gurav 	if (ret < 0)
8077d254559SPramod Gurav 		return ret;
808d9b31efcSSinan Kaya 
809d9b31efcSSinan Kaya 	spin_lock_irqsave(&bchan->vc.lock, flag);
810d9b31efcSSinan Kaya 	writel_relaxed(0, bam_addr(bdev, bchan->id, BAM_P_HALT));
811d9b31efcSSinan Kaya 	bchan->paused = 0;
812d9b31efcSSinan Kaya 	spin_unlock_irqrestore(&bchan->vc.lock, flag);
8137d254559SPramod Gurav 	pm_runtime_mark_last_busy(bdev->dev);
8147d254559SPramod Gurav 	pm_runtime_put_autosuspend(bdev->dev);
815d9b31efcSSinan Kaya 
816d9b31efcSSinan Kaya 	return 0;
817d9b31efcSSinan Kaya }
818d9b31efcSSinan Kaya 
819d9b31efcSSinan Kaya /**
820d9b31efcSSinan Kaya  * process_channel_irqs - processes the channel interrupts
821d9b31efcSSinan Kaya  * @bdev: bam controller
822d9b31efcSSinan Kaya  *
823d9b31efcSSinan Kaya  * This function processes the channel interrupts
824d9b31efcSSinan Kaya  *
825d9b31efcSSinan Kaya  */
process_channel_irqs(struct bam_device * bdev)826d9b31efcSSinan Kaya static u32 process_channel_irqs(struct bam_device *bdev)
827d9b31efcSSinan Kaya {
8286b4faeacSSricharan R 	u32 i, srcs, pipe_stts, offset, avail;
829d9b31efcSSinan Kaya 	unsigned long flags;
8306b4faeacSSricharan R 	struct bam_async_desc *async_desc, *tmp;
831d9b31efcSSinan Kaya 
832d9b31efcSSinan Kaya 	srcs = readl_relaxed(bam_addr(bdev, 0, BAM_IRQ_SRCS_EE));
833d9b31efcSSinan Kaya 
834d9b31efcSSinan Kaya 	/* return early if no pipe/channel interrupts are present */
835d9b31efcSSinan Kaya 	if (!(srcs & P_IRQ))
836d9b31efcSSinan Kaya 		return srcs;
837d9b31efcSSinan Kaya 
838d9b31efcSSinan Kaya 	for (i = 0; i < bdev->num_channels; i++) {
839d9b31efcSSinan Kaya 		struct bam_chan *bchan = &bdev->channels[i];
840d9b31efcSSinan Kaya 
841d9b31efcSSinan Kaya 		if (!(srcs & BIT(i)))
842d9b31efcSSinan Kaya 			continue;
843d9b31efcSSinan Kaya 
844d9b31efcSSinan Kaya 		/* clear pipe irq */
845d9b31efcSSinan Kaya 		pipe_stts = readl_relaxed(bam_addr(bdev, i, BAM_P_IRQ_STTS));
846d9b31efcSSinan Kaya 
847d9b31efcSSinan Kaya 		writel_relaxed(pipe_stts, bam_addr(bdev, i, BAM_P_IRQ_CLR));
848d9b31efcSSinan Kaya 
849d9b31efcSSinan Kaya 		spin_lock_irqsave(&bchan->vc.lock, flags);
850d9b31efcSSinan Kaya 
8516b4faeacSSricharan R 		offset = readl_relaxed(bam_addr(bdev, i, BAM_P_SW_OFSTS)) &
8526b4faeacSSricharan R 				       P_SW_OFSTS_MASK;
8536b4faeacSSricharan R 		offset /= sizeof(struct bam_desc_hw);
8546b4faeacSSricharan R 
8556b4faeacSSricharan R 		/* Number of bytes available to read */
8566b4faeacSSricharan R 		avail = CIRC_CNT(offset, bchan->head, MAX_DESCRIPTORS + 1);
8576b4faeacSSricharan R 
858f6034225SSricharan R 		if (offset < bchan->head)
859f6034225SSricharan R 			avail--;
860f6034225SSricharan R 
8616b4faeacSSricharan R 		list_for_each_entry_safe(async_desc, tmp,
8626b4faeacSSricharan R 					 &bchan->desc_list, desc_node) {
8636b4faeacSSricharan R 			/* Not enough data to read */
8646b4faeacSSricharan R 			if (avail < async_desc->xfer_len)
8656b4faeacSSricharan R 				break;
866d9b31efcSSinan Kaya 
867d9b31efcSSinan Kaya 			/* manage FIFO */
868d9b31efcSSinan Kaya 			bchan->head += async_desc->xfer_len;
869d9b31efcSSinan Kaya 			bchan->head %= MAX_DESCRIPTORS;
870d9b31efcSSinan Kaya 
8716b4faeacSSricharan R 			async_desc->num_desc -= async_desc->xfer_len;
8726b4faeacSSricharan R 			async_desc->curr_desc += async_desc->xfer_len;
8736b4faeacSSricharan R 			avail -= async_desc->xfer_len;
8746b4faeacSSricharan R 
875d9b31efcSSinan Kaya 			/*
876d9b31efcSSinan Kaya 			 * if complete, process cookie. Otherwise
877d9b31efcSSinan Kaya 			 * push back to front of desc_issued so that
878d9b31efcSSinan Kaya 			 * it gets restarted by the tasklet
879d9b31efcSSinan Kaya 			 */
8806b4faeacSSricharan R 			if (!async_desc->num_desc) {
881d9b31efcSSinan Kaya 				vchan_cookie_complete(&async_desc->vd);
8826b4faeacSSricharan R 			} else {
883d9b31efcSSinan Kaya 				list_add(&async_desc->vd.node,
884d9b31efcSSinan Kaya 					 &bchan->vc.desc_issued);
885d9b31efcSSinan Kaya 			}
8866b4faeacSSricharan R 			list_del(&async_desc->desc_node);
8876b4faeacSSricharan R 		}
888d9b31efcSSinan Kaya 
889d9b31efcSSinan Kaya 		spin_unlock_irqrestore(&bchan->vc.lock, flags);
890d9b31efcSSinan Kaya 	}
891d9b31efcSSinan Kaya 
892d9b31efcSSinan Kaya 	return srcs;
893d9b31efcSSinan Kaya }
894d9b31efcSSinan Kaya 
895d9b31efcSSinan Kaya /**
896d9b31efcSSinan Kaya  * bam_dma_irq - irq handler for bam controller
897d9b31efcSSinan Kaya  * @irq: IRQ of interrupt
898d9b31efcSSinan Kaya  * @data: callback data
899d9b31efcSSinan Kaya  *
900d9b31efcSSinan Kaya  * IRQ handler for the bam controller
901d9b31efcSSinan Kaya  */
bam_dma_irq(int irq,void * data)902d9b31efcSSinan Kaya static irqreturn_t bam_dma_irq(int irq, void *data)
903d9b31efcSSinan Kaya {
904d9b31efcSSinan Kaya 	struct bam_device *bdev = data;
905d9b31efcSSinan Kaya 	u32 clr_mask = 0, srcs = 0;
9067d254559SPramod Gurav 	int ret;
907d9b31efcSSinan Kaya 
908d9b31efcSSinan Kaya 	srcs |= process_channel_irqs(bdev);
909d9b31efcSSinan Kaya 
910d9b31efcSSinan Kaya 	/* kick off tasklet to start next dma transfer */
911d9b31efcSSinan Kaya 	if (srcs & P_IRQ)
912d9b31efcSSinan Kaya 		tasklet_schedule(&bdev->task);
913d9b31efcSSinan Kaya 
9140ac9c3ddSCaleb Connolly 	ret = pm_runtime_get_sync(bdev->dev);
9157d254559SPramod Gurav 	if (ret < 0)
9164421fe53SParth Y Shah 		return IRQ_NONE;
9177d254559SPramod Gurav 
918f89117c0SStanimir Varbanov 	if (srcs & BAM_IRQ) {
919d9b31efcSSinan Kaya 		clr_mask = readl_relaxed(bam_addr(bdev, 0, BAM_IRQ_STTS));
920d9b31efcSSinan Kaya 
921f89117c0SStanimir Varbanov 		/*
922f89117c0SStanimir Varbanov 		 * don't allow reorder of the various accesses to the BAM
923f89117c0SStanimir Varbanov 		 * registers
924f89117c0SStanimir Varbanov 		 */
925d9b31efcSSinan Kaya 		mb();
926d9b31efcSSinan Kaya 
927d9b31efcSSinan Kaya 		writel_relaxed(clr_mask, bam_addr(bdev, 0, BAM_IRQ_CLR));
928f89117c0SStanimir Varbanov 	}
929d9b31efcSSinan Kaya 
9307d254559SPramod Gurav 	pm_runtime_mark_last_busy(bdev->dev);
9317d254559SPramod Gurav 	pm_runtime_put_autosuspend(bdev->dev);
9327d254559SPramod Gurav 
933d9b31efcSSinan Kaya 	return IRQ_HANDLED;
934d9b31efcSSinan Kaya }
935d9b31efcSSinan Kaya 
936d9b31efcSSinan Kaya /**
937d9b31efcSSinan Kaya  * bam_tx_status - returns status of transaction
938d9b31efcSSinan Kaya  * @chan: dma channel
939d9b31efcSSinan Kaya  * @cookie: transaction cookie
940d9b31efcSSinan Kaya  * @txstate: DMA transaction state
941d9b31efcSSinan Kaya  *
942d9b31efcSSinan Kaya  * Return status of dma transaction
943d9b31efcSSinan Kaya  */
bam_tx_status(struct dma_chan * chan,dma_cookie_t cookie,struct dma_tx_state * txstate)944d9b31efcSSinan Kaya static enum dma_status bam_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
945d9b31efcSSinan Kaya 		struct dma_tx_state *txstate)
946d9b31efcSSinan Kaya {
947d9b31efcSSinan Kaya 	struct bam_chan *bchan = to_bam_chan(chan);
9486b4faeacSSricharan R 	struct bam_async_desc *async_desc;
949d9b31efcSSinan Kaya 	struct virt_dma_desc *vd;
950d9b31efcSSinan Kaya 	int ret;
951d9b31efcSSinan Kaya 	size_t residue = 0;
952d9b31efcSSinan Kaya 	unsigned int i;
953d9b31efcSSinan Kaya 	unsigned long flags;
954d9b31efcSSinan Kaya 
955d9b31efcSSinan Kaya 	ret = dma_cookie_status(chan, cookie, txstate);
956d9b31efcSSinan Kaya 	if (ret == DMA_COMPLETE)
957d9b31efcSSinan Kaya 		return ret;
958d9b31efcSSinan Kaya 
959d9b31efcSSinan Kaya 	if (!txstate)
960d9b31efcSSinan Kaya 		return bchan->paused ? DMA_PAUSED : ret;
961d9b31efcSSinan Kaya 
962d9b31efcSSinan Kaya 	spin_lock_irqsave(&bchan->vc.lock, flags);
963d9b31efcSSinan Kaya 	vd = vchan_find_desc(&bchan->vc, cookie);
9646b4faeacSSricharan R 	if (vd) {
965d9b31efcSSinan Kaya 		residue = container_of(vd, struct bam_async_desc, vd)->length;
9666b4faeacSSricharan R 	} else {
9676b4faeacSSricharan R 		list_for_each_entry(async_desc, &bchan->desc_list, desc_node) {
9686b4faeacSSricharan R 			if (async_desc->vd.tx.cookie != cookie)
9696b4faeacSSricharan R 				continue;
9706b4faeacSSricharan R 
9716b4faeacSSricharan R 			for (i = 0; i < async_desc->num_desc; i++)
9725c63de1eSSrinivas Kandagatla 				residue += le16_to_cpu(
9735c63de1eSSrinivas Kandagatla 						async_desc->curr_desc[i].size);
9746b4faeacSSricharan R 		}
9756b4faeacSSricharan R 	}
976d9b31efcSSinan Kaya 
977d9b31efcSSinan Kaya 	spin_unlock_irqrestore(&bchan->vc.lock, flags);
978d9b31efcSSinan Kaya 
979d9b31efcSSinan Kaya 	dma_set_residue(txstate, residue);
980d9b31efcSSinan Kaya 
981d9b31efcSSinan Kaya 	if (ret == DMA_IN_PROGRESS && bchan->paused)
982d9b31efcSSinan Kaya 		ret = DMA_PAUSED;
983d9b31efcSSinan Kaya 
984d9b31efcSSinan Kaya 	return ret;
985d9b31efcSSinan Kaya }
986d9b31efcSSinan Kaya 
987d9b31efcSSinan Kaya /**
988d9b31efcSSinan Kaya  * bam_apply_new_config
989d9b31efcSSinan Kaya  * @bchan: bam dma channel
990d9b31efcSSinan Kaya  * @dir: DMA direction
991d9b31efcSSinan Kaya  */
bam_apply_new_config(struct bam_chan * bchan,enum dma_transfer_direction dir)992d9b31efcSSinan Kaya static void bam_apply_new_config(struct bam_chan *bchan,
993d9b31efcSSinan Kaya 	enum dma_transfer_direction dir)
994d9b31efcSSinan Kaya {
995d9b31efcSSinan Kaya 	struct bam_device *bdev = bchan->bdev;
996d9b31efcSSinan Kaya 	u32 maxburst;
997d9b31efcSSinan Kaya 
99854eb5e26SSrinivas Kandagatla 	if (!bdev->controlled_remotely) {
999d9b31efcSSinan Kaya 		if (dir == DMA_DEV_TO_MEM)
1000d9b31efcSSinan Kaya 			maxburst = bchan->slave.src_maxburst;
1001d9b31efcSSinan Kaya 		else
1002d9b31efcSSinan Kaya 			maxburst = bchan->slave.dst_maxburst;
1003d9b31efcSSinan Kaya 
100454eb5e26SSrinivas Kandagatla 		writel_relaxed(maxburst,
100554eb5e26SSrinivas Kandagatla 			       bam_addr(bdev, 0, BAM_DESC_CNT_TRSHLD));
100654eb5e26SSrinivas Kandagatla 	}
1007d9b31efcSSinan Kaya 
1008d9b31efcSSinan Kaya 	bchan->reconfigure = 0;
1009d9b31efcSSinan Kaya }
1010d9b31efcSSinan Kaya 
1011d9b31efcSSinan Kaya /**
1012d9b31efcSSinan Kaya  * bam_start_dma - start next transaction
10139c3655cbSSrinivas Kandagatla  * @bchan: bam dma channel
1014d9b31efcSSinan Kaya  */
bam_start_dma(struct bam_chan * bchan)1015d9b31efcSSinan Kaya static void bam_start_dma(struct bam_chan *bchan)
1016d9b31efcSSinan Kaya {
1017d9b31efcSSinan Kaya 	struct virt_dma_desc *vd = vchan_next_desc(&bchan->vc);
1018d9b31efcSSinan Kaya 	struct bam_device *bdev = bchan->bdev;
10196b4faeacSSricharan R 	struct bam_async_desc *async_desc = NULL;
1020d9b31efcSSinan Kaya 	struct bam_desc_hw *desc;
1021d9b31efcSSinan Kaya 	struct bam_desc_hw *fifo = PTR_ALIGN(bchan->fifo_virt,
1022d9b31efcSSinan Kaya 					sizeof(struct bam_desc_hw));
10237d254559SPramod Gurav 	int ret;
10246b4faeacSSricharan R 	unsigned int avail;
10256b4faeacSSricharan R 	struct dmaengine_desc_callback cb;
1026d9b31efcSSinan Kaya 
1027d9b31efcSSinan Kaya 	lockdep_assert_held(&bchan->vc.lock);
1028d9b31efcSSinan Kaya 
1029d9b31efcSSinan Kaya 	if (!vd)
1030d9b31efcSSinan Kaya 		return;
1031d9b31efcSSinan Kaya 
10320ac9c3ddSCaleb Connolly 	ret = pm_runtime_get_sync(bdev->dev);
10337d254559SPramod Gurav 	if (ret < 0)
10347d254559SPramod Gurav 		return;
10357d254559SPramod Gurav 
10366b4faeacSSricharan R 	while (vd && !IS_BUSY(bchan)) {
10376b4faeacSSricharan R 		list_del(&vd->node);
10386b4faeacSSricharan R 
10396b4faeacSSricharan R 		async_desc = container_of(vd, struct bam_async_desc, vd);
10406b4faeacSSricharan R 
1041d9b31efcSSinan Kaya 		/* on first use, initialize the channel hardware */
1042d9b31efcSSinan Kaya 		if (!bchan->initialized)
1043d9b31efcSSinan Kaya 			bam_chan_init_hw(bchan, async_desc->dir);
1044d9b31efcSSinan Kaya 
1045d9b31efcSSinan Kaya 		/* apply new slave config changes, if necessary */
1046d9b31efcSSinan Kaya 		if (bchan->reconfigure)
1047d9b31efcSSinan Kaya 			bam_apply_new_config(bchan, async_desc->dir);
1048d9b31efcSSinan Kaya 
10496b4faeacSSricharan R 		desc = async_desc->curr_desc;
10506b4faeacSSricharan R 		avail = CIRC_SPACE(bchan->tail, bchan->head,
10516b4faeacSSricharan R 				   MAX_DESCRIPTORS + 1);
1052d9b31efcSSinan Kaya 
10536b4faeacSSricharan R 		if (async_desc->num_desc > avail)
10546b4faeacSSricharan R 			async_desc->xfer_len = avail;
1055d9b31efcSSinan Kaya 		else
1056d9b31efcSSinan Kaya 			async_desc->xfer_len = async_desc->num_desc;
1057d9b31efcSSinan Kaya 
1058d9b31efcSSinan Kaya 		/* set any special flags on the last descriptor */
1059d9b31efcSSinan Kaya 		if (async_desc->num_desc == async_desc->xfer_len)
1060749d0d4bSAbhishek Sahu 			desc[async_desc->xfer_len - 1].flags |=
1061d9b31efcSSinan Kaya 						cpu_to_le16(async_desc->flags);
10626b4faeacSSricharan R 
10636b4faeacSSricharan R 		vd = vchan_next_desc(&bchan->vc);
10646b4faeacSSricharan R 
10656b4faeacSSricharan R 		dmaengine_desc_get_callback(&async_desc->vd.tx, &cb);
10666b4faeacSSricharan R 
10676b4faeacSSricharan R 		/*
10686b4faeacSSricharan R 		 * An interrupt is generated at this desc, if
10696b4faeacSSricharan R 		 *  - FIFO is FULL.
10706b4faeacSSricharan R 		 *  - No more descriptors to add.
10716b4faeacSSricharan R 		 *  - If a callback completion was requested for this DESC,
10726b4faeacSSricharan R 		 *     In this case, BAM will deliver the completion callback
10736b4faeacSSricharan R 		 *     for this desc and continue processing the next desc.
10746b4faeacSSricharan R 		 */
10756b4faeacSSricharan R 		if (((avail <= async_desc->xfer_len) || !vd ||
10766b4faeacSSricharan R 		     dmaengine_desc_callback_valid(&cb)) &&
10776b4faeacSSricharan R 		    !(async_desc->flags & DESC_FLAG_EOT))
1078d9b31efcSSinan Kaya 			desc[async_desc->xfer_len - 1].flags |=
1079d9b31efcSSinan Kaya 				cpu_to_le16(DESC_FLAG_INT);
1080d9b31efcSSinan Kaya 
1081d9b31efcSSinan Kaya 		if (bchan->tail + async_desc->xfer_len > MAX_DESCRIPTORS) {
1082d9b31efcSSinan Kaya 			u32 partial = MAX_DESCRIPTORS - bchan->tail;
1083d9b31efcSSinan Kaya 
1084d9b31efcSSinan Kaya 			memcpy(&fifo[bchan->tail], desc,
1085d9b31efcSSinan Kaya 			       partial * sizeof(struct bam_desc_hw));
10866b4faeacSSricharan R 			memcpy(fifo, &desc[partial],
10876b4faeacSSricharan R 			       (async_desc->xfer_len - partial) *
1088d9b31efcSSinan Kaya 				sizeof(struct bam_desc_hw));
1089d9b31efcSSinan Kaya 		} else {
1090d9b31efcSSinan Kaya 			memcpy(&fifo[bchan->tail], desc,
10916b4faeacSSricharan R 			       async_desc->xfer_len *
10926b4faeacSSricharan R 			       sizeof(struct bam_desc_hw));
1093d9b31efcSSinan Kaya 		}
1094d9b31efcSSinan Kaya 
1095d9b31efcSSinan Kaya 		bchan->tail += async_desc->xfer_len;
1096d9b31efcSSinan Kaya 		bchan->tail %= MAX_DESCRIPTORS;
10976b4faeacSSricharan R 		list_add_tail(&async_desc->desc_node, &bchan->desc_list);
10986b4faeacSSricharan R 	}
1099d9b31efcSSinan Kaya 
1100d9b31efcSSinan Kaya 	/* ensure descriptor writes and dma start not reordered */
1101d9b31efcSSinan Kaya 	wmb();
1102d9b31efcSSinan Kaya 	writel_relaxed(bchan->tail * sizeof(struct bam_desc_hw),
1103d9b31efcSSinan Kaya 			bam_addr(bdev, bchan->id, BAM_P_EVNT_REG));
11047d254559SPramod Gurav 
11057d254559SPramod Gurav 	pm_runtime_mark_last_busy(bdev->dev);
11067d254559SPramod Gurav 	pm_runtime_put_autosuspend(bdev->dev);
1107d9b31efcSSinan Kaya }
1108d9b31efcSSinan Kaya 
1109d9b31efcSSinan Kaya /**
1110d9b31efcSSinan Kaya  * dma_tasklet - DMA IRQ tasklet
1111a5e399a5SVinod Koul  * @t: tasklet argument (bam controller structure)
1112d9b31efcSSinan Kaya  *
1113d9b31efcSSinan Kaya  * Sets up next DMA operation and then processes all completed transactions
1114d9b31efcSSinan Kaya  */
dma_tasklet(struct tasklet_struct * t)111500c4747aSAllen Pais static void dma_tasklet(struct tasklet_struct *t)
1116d9b31efcSSinan Kaya {
111700c4747aSAllen Pais 	struct bam_device *bdev = from_tasklet(bdev, t, task);
1118d9b31efcSSinan Kaya 	struct bam_chan *bchan;
1119d9b31efcSSinan Kaya 	unsigned long flags;
1120d9b31efcSSinan Kaya 	unsigned int i;
1121d9b31efcSSinan Kaya 
1122d9b31efcSSinan Kaya 	/* go through the channels and kick off transactions */
1123d9b31efcSSinan Kaya 	for (i = 0; i < bdev->num_channels; i++) {
1124d9b31efcSSinan Kaya 		bchan = &bdev->channels[i];
1125d9b31efcSSinan Kaya 		spin_lock_irqsave(&bchan->vc.lock, flags);
1126d9b31efcSSinan Kaya 
11276b4faeacSSricharan R 		if (!list_empty(&bchan->vc.desc_issued) && !IS_BUSY(bchan))
1128d9b31efcSSinan Kaya 			bam_start_dma(bchan);
1129d9b31efcSSinan Kaya 		spin_unlock_irqrestore(&bchan->vc.lock, flags);
1130d9b31efcSSinan Kaya 	}
11317d254559SPramod Gurav 
1132d9b31efcSSinan Kaya }
1133d9b31efcSSinan Kaya 
1134d9b31efcSSinan Kaya /**
1135d9b31efcSSinan Kaya  * bam_issue_pending - starts pending transactions
1136d9b31efcSSinan Kaya  * @chan: dma channel
1137d9b31efcSSinan Kaya  *
1138d9b31efcSSinan Kaya  * Calls tasklet directly which in turn starts any pending transactions
1139d9b31efcSSinan Kaya  */
bam_issue_pending(struct dma_chan * chan)1140d9b31efcSSinan Kaya static void bam_issue_pending(struct dma_chan *chan)
1141d9b31efcSSinan Kaya {
1142d9b31efcSSinan Kaya 	struct bam_chan *bchan = to_bam_chan(chan);
1143d9b31efcSSinan Kaya 	unsigned long flags;
1144d9b31efcSSinan Kaya 
1145d9b31efcSSinan Kaya 	spin_lock_irqsave(&bchan->vc.lock, flags);
1146d9b31efcSSinan Kaya 
1147d9b31efcSSinan Kaya 	/* if work pending and idle, start a transaction */
11486b4faeacSSricharan R 	if (vchan_issue_pending(&bchan->vc) && !IS_BUSY(bchan))
1149d9b31efcSSinan Kaya 		bam_start_dma(bchan);
1150d9b31efcSSinan Kaya 
1151d9b31efcSSinan Kaya 	spin_unlock_irqrestore(&bchan->vc.lock, flags);
1152d9b31efcSSinan Kaya }
1153d9b31efcSSinan Kaya 
1154d9b31efcSSinan Kaya /**
1155d9b31efcSSinan Kaya  * bam_dma_free_desc - free descriptor memory
1156d9b31efcSSinan Kaya  * @vd: virtual descriptor
1157d9b31efcSSinan Kaya  *
1158d9b31efcSSinan Kaya  */
bam_dma_free_desc(struct virt_dma_desc * vd)1159d9b31efcSSinan Kaya static void bam_dma_free_desc(struct virt_dma_desc *vd)
1160d9b31efcSSinan Kaya {
1161d9b31efcSSinan Kaya 	struct bam_async_desc *async_desc = container_of(vd,
1162d9b31efcSSinan Kaya 			struct bam_async_desc, vd);
1163d9b31efcSSinan Kaya 
1164d9b31efcSSinan Kaya 	kfree(async_desc);
1165d9b31efcSSinan Kaya }
1166d9b31efcSSinan Kaya 
bam_dma_xlate(struct of_phandle_args * dma_spec,struct of_dma * of)1167d9b31efcSSinan Kaya static struct dma_chan *bam_dma_xlate(struct of_phandle_args *dma_spec,
1168d9b31efcSSinan Kaya 		struct of_dma *of)
1169d9b31efcSSinan Kaya {
1170d9b31efcSSinan Kaya 	struct bam_device *bdev = container_of(of->of_dma_data,
1171d9b31efcSSinan Kaya 					struct bam_device, common);
1172d9b31efcSSinan Kaya 	unsigned int request;
1173d9b31efcSSinan Kaya 
1174d9b31efcSSinan Kaya 	if (dma_spec->args_count != 1)
1175d9b31efcSSinan Kaya 		return NULL;
1176d9b31efcSSinan Kaya 
1177d9b31efcSSinan Kaya 	request = dma_spec->args[0];
1178d9b31efcSSinan Kaya 	if (request >= bdev->num_channels)
1179d9b31efcSSinan Kaya 		return NULL;
1180d9b31efcSSinan Kaya 
1181d9b31efcSSinan Kaya 	return dma_get_slave_channel(&(bdev->channels[request].vc.chan));
1182d9b31efcSSinan Kaya }
1183d9b31efcSSinan Kaya 
1184d9b31efcSSinan Kaya /**
1185d9b31efcSSinan Kaya  * bam_init
1186d9b31efcSSinan Kaya  * @bdev: bam device
1187d9b31efcSSinan Kaya  *
1188d9b31efcSSinan Kaya  * Initialization helper for global bam registers
1189d9b31efcSSinan Kaya  */
bam_init(struct bam_device * bdev)1190d9b31efcSSinan Kaya static int bam_init(struct bam_device *bdev)
1191d9b31efcSSinan Kaya {
1192d9b31efcSSinan Kaya 	u32 val;
1193d9b31efcSSinan Kaya 
1194d9b31efcSSinan Kaya 	/* read revision and configuration information */
119548d163b1SSrinivas Kandagatla 	if (!bdev->num_ees) {
119648d163b1SSrinivas Kandagatla 		val = readl_relaxed(bam_addr(bdev, 0, BAM_REVISION));
119748d163b1SSrinivas Kandagatla 		bdev->num_ees = (val >> NUM_EES_SHIFT) & NUM_EES_MASK;
119848d163b1SSrinivas Kandagatla 	}
1199d9b31efcSSinan Kaya 
1200d9b31efcSSinan Kaya 	/* check that configured EE is within range */
120148d163b1SSrinivas Kandagatla 	if (bdev->ee >= bdev->num_ees)
1202d9b31efcSSinan Kaya 		return -EINVAL;
1203d9b31efcSSinan Kaya 
120448d163b1SSrinivas Kandagatla 	if (!bdev->num_channels) {
1205d9b31efcSSinan Kaya 		val = readl_relaxed(bam_addr(bdev, 0, BAM_NUM_PIPES));
1206d9b31efcSSinan Kaya 		bdev->num_channels = val & BAM_NUM_PIPES_MASK;
120748d163b1SSrinivas Kandagatla 	}
1208d9b31efcSSinan Kaya 
12099502ffcdSStephan Gerhold 	/* Reset BAM now if fully controlled locally */
12109502ffcdSStephan Gerhold 	if (!bdev->controlled_remotely && !bdev->powered_remotely)
12119502ffcdSStephan Gerhold 		bam_reset(bdev);
1212d9b31efcSSinan Kaya 
1213d9b31efcSSinan Kaya 	return 0;
1214d9b31efcSSinan Kaya }
1215d9b31efcSSinan Kaya 
bam_channel_init(struct bam_device * bdev,struct bam_chan * bchan,u32 index)1216d9b31efcSSinan Kaya static void bam_channel_init(struct bam_device *bdev, struct bam_chan *bchan,
1217d9b31efcSSinan Kaya 	u32 index)
1218d9b31efcSSinan Kaya {
1219d9b31efcSSinan Kaya 	bchan->id = index;
1220d9b31efcSSinan Kaya 	bchan->bdev = bdev;
1221d9b31efcSSinan Kaya 
1222d9b31efcSSinan Kaya 	vchan_init(&bchan->vc, &bdev->common);
1223d9b31efcSSinan Kaya 	bchan->vc.desc_free = bam_dma_free_desc;
12246b4faeacSSricharan R 	INIT_LIST_HEAD(&bchan->desc_list);
1225d9b31efcSSinan Kaya }
1226d9b31efcSSinan Kaya 
1227d9b31efcSSinan Kaya static const struct of_device_id bam_of_match[] = {
1228d9b31efcSSinan Kaya 	{ .compatible = "qcom,bam-v1.3.0", .data = &bam_v1_3_reg_info },
1229d9b31efcSSinan Kaya 	{ .compatible = "qcom,bam-v1.4.0", .data = &bam_v1_4_reg_info },
1230d9b31efcSSinan Kaya 	{ .compatible = "qcom,bam-v1.7.0", .data = &bam_v1_7_reg_info },
1231d9b31efcSSinan Kaya 	{}
1232d9b31efcSSinan Kaya };
1233d9b31efcSSinan Kaya 
1234d9b31efcSSinan Kaya MODULE_DEVICE_TABLE(of, bam_of_match);
1235d9b31efcSSinan Kaya 
bam_dma_probe(struct platform_device * pdev)1236d9b31efcSSinan Kaya static int bam_dma_probe(struct platform_device *pdev)
1237d9b31efcSSinan Kaya {
1238d9b31efcSSinan Kaya 	struct bam_device *bdev;
1239d9b31efcSSinan Kaya 	const struct of_device_id *match;
1240d9b31efcSSinan Kaya 	int ret, i;
1241d9b31efcSSinan Kaya 
1242d9b31efcSSinan Kaya 	bdev = devm_kzalloc(&pdev->dev, sizeof(*bdev), GFP_KERNEL);
1243d9b31efcSSinan Kaya 	if (!bdev)
1244d9b31efcSSinan Kaya 		return -ENOMEM;
1245d9b31efcSSinan Kaya 
1246d9b31efcSSinan Kaya 	bdev->dev = &pdev->dev;
1247d9b31efcSSinan Kaya 
1248d9b31efcSSinan Kaya 	match = of_match_node(bam_of_match, pdev->dev.of_node);
1249d9b31efcSSinan Kaya 	if (!match) {
1250d9b31efcSSinan Kaya 		dev_err(&pdev->dev, "Unsupported BAM module\n");
1251d9b31efcSSinan Kaya 		return -ENODEV;
1252d9b31efcSSinan Kaya 	}
1253d9b31efcSSinan Kaya 
1254d9b31efcSSinan Kaya 	bdev->layout = match->data;
1255d9b31efcSSinan Kaya 
12564b23603aSTudor Ambarus 	bdev->regs = devm_platform_ioremap_resource(pdev, 0);
1257d9b31efcSSinan Kaya 	if (IS_ERR(bdev->regs))
1258d9b31efcSSinan Kaya 		return PTR_ERR(bdev->regs);
1259d9b31efcSSinan Kaya 
1260d9b31efcSSinan Kaya 	bdev->irq = platform_get_irq(pdev, 0);
1261d9b31efcSSinan Kaya 	if (bdev->irq < 0)
1262d9b31efcSSinan Kaya 		return bdev->irq;
1263d9b31efcSSinan Kaya 
1264d9b31efcSSinan Kaya 	ret = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &bdev->ee);
1265d9b31efcSSinan Kaya 	if (ret) {
1266d9b31efcSSinan Kaya 		dev_err(bdev->dev, "Execution environment unspecified\n");
1267d9b31efcSSinan Kaya 		return ret;
1268d9b31efcSSinan Kaya 	}
1269d9b31efcSSinan Kaya 
12705172c9ebSStanimir Varbanov 	bdev->controlled_remotely = of_property_read_bool(pdev->dev.of_node,
12715172c9ebSStanimir Varbanov 						"qcom,controlled-remotely");
12729502ffcdSStephan Gerhold 	bdev->powered_remotely = of_property_read_bool(pdev->dev.of_node,
12739502ffcdSStephan Gerhold 						"qcom,powered-remotely");
12745172c9ebSStanimir Varbanov 
1275*8975dd41SStephan Gerhold 	if (bdev->controlled_remotely || bdev->powered_remotely)
1276*8975dd41SStephan Gerhold 		bdev->bamclk = devm_clk_get_optional(bdev->dev, "bam_clk");
1277*8975dd41SStephan Gerhold 	else
1278*8975dd41SStephan Gerhold 		bdev->bamclk = devm_clk_get(bdev->dev, "bam_clk");
1279*8975dd41SStephan Gerhold 
1280*8975dd41SStephan Gerhold 	if (IS_ERR(bdev->bamclk))
1281*8975dd41SStephan Gerhold 		return PTR_ERR(bdev->bamclk);
1282*8975dd41SStephan Gerhold 
1283*8975dd41SStephan Gerhold 	if (!bdev->bamclk) {
128448d163b1SSrinivas Kandagatla 		ret = of_property_read_u32(pdev->dev.of_node, "num-channels",
128548d163b1SSrinivas Kandagatla 					   &bdev->num_channels);
128648d163b1SSrinivas Kandagatla 		if (ret)
128748d163b1SSrinivas Kandagatla 			dev_err(bdev->dev, "num-channels unspecified in dt\n");
128848d163b1SSrinivas Kandagatla 
128948d163b1SSrinivas Kandagatla 		ret = of_property_read_u32(pdev->dev.of_node, "qcom,num-ees",
129048d163b1SSrinivas Kandagatla 					   &bdev->num_ees);
129148d163b1SSrinivas Kandagatla 		if (ret)
129248d163b1SSrinivas Kandagatla 			dev_err(bdev->dev, "num-ees unspecified in dt\n");
129348d163b1SSrinivas Kandagatla 	}
129448d163b1SSrinivas Kandagatla 
1295d9b31efcSSinan Kaya 	ret = clk_prepare_enable(bdev->bamclk);
1296d9b31efcSSinan Kaya 	if (ret) {
1297d9b31efcSSinan Kaya 		dev_err(bdev->dev, "failed to prepare/enable clock\n");
1298d9b31efcSSinan Kaya 		return ret;
1299d9b31efcSSinan Kaya 	}
1300d9b31efcSSinan Kaya 
1301d9b31efcSSinan Kaya 	ret = bam_init(bdev);
1302d9b31efcSSinan Kaya 	if (ret)
1303d9b31efcSSinan Kaya 		goto err_disable_clk;
1304d9b31efcSSinan Kaya 
130500c4747aSAllen Pais 	tasklet_setup(&bdev->task, dma_tasklet);
1306d9b31efcSSinan Kaya 
1307d9b31efcSSinan Kaya 	bdev->channels = devm_kcalloc(bdev->dev, bdev->num_channels,
1308d9b31efcSSinan Kaya 				sizeof(*bdev->channels), GFP_KERNEL);
1309d9b31efcSSinan Kaya 
1310d9b31efcSSinan Kaya 	if (!bdev->channels) {
1311d9b31efcSSinan Kaya 		ret = -ENOMEM;
1312d9b31efcSSinan Kaya 		goto err_tasklet_kill;
1313d9b31efcSSinan Kaya 	}
1314d9b31efcSSinan Kaya 
1315d9b31efcSSinan Kaya 	/* allocate and initialize channels */
1316d9b31efcSSinan Kaya 	INIT_LIST_HEAD(&bdev->common.channels);
1317d9b31efcSSinan Kaya 
1318d9b31efcSSinan Kaya 	for (i = 0; i < bdev->num_channels; i++)
1319d9b31efcSSinan Kaya 		bam_channel_init(bdev, &bdev->channels[i], i);
1320d9b31efcSSinan Kaya 
1321d9b31efcSSinan Kaya 	ret = devm_request_irq(bdev->dev, bdev->irq, bam_dma_irq,
1322d9b31efcSSinan Kaya 			IRQF_TRIGGER_HIGH, "bam_dma", bdev);
1323d9b31efcSSinan Kaya 	if (ret)
1324d9b31efcSSinan Kaya 		goto err_bam_channel_exit;
1325d9b31efcSSinan Kaya 
1326d9b31efcSSinan Kaya 	/* set max dma segment size */
1327d9b31efcSSinan Kaya 	bdev->common.dev = bdev->dev;
13285ad3f29fSStanimir Varbanov 	ret = dma_set_max_seg_size(bdev->common.dev, BAM_FIFO_SIZE);
1329d9b31efcSSinan Kaya 	if (ret) {
1330d9b31efcSSinan Kaya 		dev_err(bdev->dev, "cannot set maximum segment size\n");
1331d9b31efcSSinan Kaya 		goto err_bam_channel_exit;
1332d9b31efcSSinan Kaya 	}
1333d9b31efcSSinan Kaya 
1334d9b31efcSSinan Kaya 	platform_set_drvdata(pdev, bdev);
1335d9b31efcSSinan Kaya 
1336d9b31efcSSinan Kaya 	/* set capabilities */
1337d9b31efcSSinan Kaya 	dma_cap_zero(bdev->common.cap_mask);
1338d9b31efcSSinan Kaya 	dma_cap_set(DMA_SLAVE, bdev->common.cap_mask);
1339d9b31efcSSinan Kaya 
1340d9b31efcSSinan Kaya 	/* initialize dmaengine apis */
1341d9b31efcSSinan Kaya 	bdev->common.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
1342d9b31efcSSinan Kaya 	bdev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
1343d9b31efcSSinan Kaya 	bdev->common.src_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
1344d9b31efcSSinan Kaya 	bdev->common.dst_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
1345d9b31efcSSinan Kaya 	bdev->common.device_alloc_chan_resources = bam_alloc_chan;
1346d9b31efcSSinan Kaya 	bdev->common.device_free_chan_resources = bam_free_chan;
1347d9b31efcSSinan Kaya 	bdev->common.device_prep_slave_sg = bam_prep_slave_sg;
1348d9b31efcSSinan Kaya 	bdev->common.device_config = bam_slave_config;
1349d9b31efcSSinan Kaya 	bdev->common.device_pause = bam_pause;
1350d9b31efcSSinan Kaya 	bdev->common.device_resume = bam_resume;
1351d9b31efcSSinan Kaya 	bdev->common.device_terminate_all = bam_dma_terminate_all;
1352d9b31efcSSinan Kaya 	bdev->common.device_issue_pending = bam_issue_pending;
1353d9b31efcSSinan Kaya 	bdev->common.device_tx_status = bam_tx_status;
1354d9b31efcSSinan Kaya 	bdev->common.dev = bdev->dev;
1355d9b31efcSSinan Kaya 
1356d9b31efcSSinan Kaya 	ret = dma_async_device_register(&bdev->common);
1357d9b31efcSSinan Kaya 	if (ret) {
1358d9b31efcSSinan Kaya 		dev_err(bdev->dev, "failed to register dma async device\n");
1359d9b31efcSSinan Kaya 		goto err_bam_channel_exit;
1360d9b31efcSSinan Kaya 	}
1361d9b31efcSSinan Kaya 
1362d9b31efcSSinan Kaya 	ret = of_dma_controller_register(pdev->dev.of_node, bam_dma_xlate,
1363d9b31efcSSinan Kaya 					&bdev->common);
1364d9b31efcSSinan Kaya 	if (ret)
1365d9b31efcSSinan Kaya 		goto err_unregister_dma;
1366d9b31efcSSinan Kaya 
13677d254559SPramod Gurav 	pm_runtime_irq_safe(&pdev->dev);
13687d254559SPramod Gurav 	pm_runtime_set_autosuspend_delay(&pdev->dev, BAM_DMA_AUTOSUSPEND_DELAY);
13697d254559SPramod Gurav 	pm_runtime_use_autosuspend(&pdev->dev);
13707d254559SPramod Gurav 	pm_runtime_mark_last_busy(&pdev->dev);
13717d254559SPramod Gurav 	pm_runtime_set_active(&pdev->dev);
13727d254559SPramod Gurav 	pm_runtime_enable(&pdev->dev);
13737d254559SPramod Gurav 
1374d9b31efcSSinan Kaya 	return 0;
1375d9b31efcSSinan Kaya 
1376d9b31efcSSinan Kaya err_unregister_dma:
1377d9b31efcSSinan Kaya 	dma_async_device_unregister(&bdev->common);
1378d9b31efcSSinan Kaya err_bam_channel_exit:
1379d9b31efcSSinan Kaya 	for (i = 0; i < bdev->num_channels; i++)
1380d9b31efcSSinan Kaya 		tasklet_kill(&bdev->channels[i].vc.task);
1381d9b31efcSSinan Kaya err_tasklet_kill:
1382d9b31efcSSinan Kaya 	tasklet_kill(&bdev->task);
1383d9b31efcSSinan Kaya err_disable_clk:
1384d9b31efcSSinan Kaya 	clk_disable_unprepare(bdev->bamclk);
1385d9b31efcSSinan Kaya 
1386d9b31efcSSinan Kaya 	return ret;
1387d9b31efcSSinan Kaya }
1388d9b31efcSSinan Kaya 
bam_dma_remove(struct platform_device * pdev)1389d9b31efcSSinan Kaya static int bam_dma_remove(struct platform_device *pdev)
1390d9b31efcSSinan Kaya {
1391d9b31efcSSinan Kaya 	struct bam_device *bdev = platform_get_drvdata(pdev);
1392d9b31efcSSinan Kaya 	u32 i;
1393d9b31efcSSinan Kaya 
13947d254559SPramod Gurav 	pm_runtime_force_suspend(&pdev->dev);
13957d254559SPramod Gurav 
1396d9b31efcSSinan Kaya 	of_dma_controller_free(pdev->dev.of_node);
1397d9b31efcSSinan Kaya 	dma_async_device_unregister(&bdev->common);
1398d9b31efcSSinan Kaya 
1399d9b31efcSSinan Kaya 	/* mask all interrupts for this execution environment */
1400d9b31efcSSinan Kaya 	writel_relaxed(0, bam_addr(bdev, 0,  BAM_IRQ_SRCS_MSK_EE));
1401d9b31efcSSinan Kaya 
1402d9b31efcSSinan Kaya 	devm_free_irq(bdev->dev, bdev->irq, bdev);
1403d9b31efcSSinan Kaya 
1404d9b31efcSSinan Kaya 	for (i = 0; i < bdev->num_channels; i++) {
1405d9b31efcSSinan Kaya 		bam_dma_terminate_all(&bdev->channels[i].vc.chan);
1406d9b31efcSSinan Kaya 		tasklet_kill(&bdev->channels[i].vc.task);
1407d9b31efcSSinan Kaya 
1408f139f978SStanimir Varbanov 		if (!bdev->channels[i].fifo_virt)
1409f139f978SStanimir Varbanov 			continue;
1410f139f978SStanimir Varbanov 
1411b5b131c7SLinus Torvalds 		dma_free_wc(bdev->dev, BAM_DESC_FIFO_SIZE,
1412d9b31efcSSinan Kaya 			    bdev->channels[i].fifo_virt,
1413d9b31efcSSinan Kaya 			    bdev->channels[i].fifo_phys);
1414d9b31efcSSinan Kaya 	}
1415d9b31efcSSinan Kaya 
1416d9b31efcSSinan Kaya 	tasklet_kill(&bdev->task);
1417d9b31efcSSinan Kaya 
1418d9b31efcSSinan Kaya 	clk_disable_unprepare(bdev->bamclk);
1419d9b31efcSSinan Kaya 
1420d9b31efcSSinan Kaya 	return 0;
1421d9b31efcSSinan Kaya }
1422d9b31efcSSinan Kaya 
bam_dma_runtime_suspend(struct device * dev)1423184f337eSArnd Bergmann static int __maybe_unused bam_dma_runtime_suspend(struct device *dev)
14247d254559SPramod Gurav {
14257d254559SPramod Gurav 	struct bam_device *bdev = dev_get_drvdata(dev);
14267d254559SPramod Gurav 
14277d254559SPramod Gurav 	clk_disable(bdev->bamclk);
14287d254559SPramod Gurav 
14297d254559SPramod Gurav 	return 0;
14307d254559SPramod Gurav }
14317d254559SPramod Gurav 
bam_dma_runtime_resume(struct device * dev)1432184f337eSArnd Bergmann static int __maybe_unused bam_dma_runtime_resume(struct device *dev)
14337d254559SPramod Gurav {
14347d254559SPramod Gurav 	struct bam_device *bdev = dev_get_drvdata(dev);
14357d254559SPramod Gurav 	int ret;
14367d254559SPramod Gurav 
14377d254559SPramod Gurav 	ret = clk_enable(bdev->bamclk);
14387d254559SPramod Gurav 	if (ret < 0) {
14397d254559SPramod Gurav 		dev_err(dev, "clk_enable failed: %d\n", ret);
14407d254559SPramod Gurav 		return ret;
14417d254559SPramod Gurav 	}
14427d254559SPramod Gurav 
14437d254559SPramod Gurav 	return 0;
14447d254559SPramod Gurav }
1445184f337eSArnd Bergmann 
bam_dma_suspend(struct device * dev)1446184f337eSArnd Bergmann static int __maybe_unused bam_dma_suspend(struct device *dev)
14477d254559SPramod Gurav {
14487d254559SPramod Gurav 	struct bam_device *bdev = dev_get_drvdata(dev);
14497d254559SPramod Gurav 
14507d254559SPramod Gurav 	pm_runtime_force_suspend(dev);
14517d254559SPramod Gurav 	clk_unprepare(bdev->bamclk);
14527d254559SPramod Gurav 
14537d254559SPramod Gurav 	return 0;
14547d254559SPramod Gurav }
14557d254559SPramod Gurav 
bam_dma_resume(struct device * dev)1456184f337eSArnd Bergmann static int __maybe_unused bam_dma_resume(struct device *dev)
14577d254559SPramod Gurav {
14587d254559SPramod Gurav 	struct bam_device *bdev = dev_get_drvdata(dev);
14597d254559SPramod Gurav 	int ret;
14607d254559SPramod Gurav 
14617d254559SPramod Gurav 	ret = clk_prepare(bdev->bamclk);
14627d254559SPramod Gurav 	if (ret)
14637d254559SPramod Gurav 		return ret;
14647d254559SPramod Gurav 
14657d254559SPramod Gurav 	pm_runtime_force_resume(dev);
14667d254559SPramod Gurav 
14677d254559SPramod Gurav 	return 0;
14687d254559SPramod Gurav }
14697d254559SPramod Gurav 
14707d254559SPramod Gurav static const struct dev_pm_ops bam_dma_pm_ops = {
14717d254559SPramod Gurav 	SET_LATE_SYSTEM_SLEEP_PM_OPS(bam_dma_suspend, bam_dma_resume)
14727d254559SPramod Gurav 	SET_RUNTIME_PM_OPS(bam_dma_runtime_suspend, bam_dma_runtime_resume,
14737d254559SPramod Gurav 				NULL)
14747d254559SPramod Gurav };
14757d254559SPramod Gurav 
1476d9b31efcSSinan Kaya static struct platform_driver bam_dma_driver = {
1477d9b31efcSSinan Kaya 	.probe = bam_dma_probe,
1478d9b31efcSSinan Kaya 	.remove = bam_dma_remove,
1479d9b31efcSSinan Kaya 	.driver = {
1480d9b31efcSSinan Kaya 		.name = "bam-dma-engine",
14817d254559SPramod Gurav 		.pm = &bam_dma_pm_ops,
1482d9b31efcSSinan Kaya 		.of_match_table = bam_of_match,
1483d9b31efcSSinan Kaya 	},
1484d9b31efcSSinan Kaya };
1485d9b31efcSSinan Kaya 
1486d9b31efcSSinan Kaya module_platform_driver(bam_dma_driver);
1487d9b31efcSSinan Kaya 
1488d9b31efcSSinan Kaya MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
1489d9b31efcSSinan Kaya MODULE_DESCRIPTION("QCOM BAM DMA engine driver");
1490d9b31efcSSinan Kaya MODULE_LICENSE("GPL v2");
1491