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