Blame view

drivers/dma/imx-sdma.c 69.9 KB
c01faaca1   Fabio Estevam   dmaengine: imx-sd...
1
2
3
4
5
6
7
8
9
10
  // SPDX-License-Identifier: GPL-2.0+
  //
  // drivers/dma/imx-sdma.c
  //
  // This file contains a driver for the Freescale Smart DMA engine
  //
  // Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
  //
  // Based on code from Freescale:
  //
00054a209   Robin Gong   MLK-17385: dma: i...
11
12
  // Copyright 2004-2016 Freescale Semiconductor, Inc. All Rights Reserved.
  // Copyright 2018 NXP.
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
13
14
  
  #include <linux/init.h>
1d069bfa3   Michael Olbrich   dmaengine: imx-sd...
15
  #include <linux/iopoll.h>
f8de8f4ce   Axel Lin   dmaengine i.MX DM...
16
  #include <linux/module.h>
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
17
  #include <linux/types.h>
0bbc14130   Richard Zhao   dma/imx-sdma: con...
18
  #include <linux/bitops.h>
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
19
20
21
  #include <linux/mm.h>
  #include <linux/interrupt.h>
  #include <linux/clk.h>
2ccaef052   Richard Zhao   dma: imx-sdma: ma...
22
  #include <linux/delay.h>
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
23
24
25
26
  #include <linux/sched.h>
  #include <linux/semaphore.h>
  #include <linux/spinlock.h>
  #include <linux/device.h>
dd7efc1f2   Nicolin Chen   dmaengine: imx-sd...
27
  #include <linux/genalloc.h>
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
28
29
30
31
  #include <linux/dma-mapping.h>
  #include <linux/firmware.h>
  #include <linux/slab.h>
  #include <linux/platform_device.h>
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
32
  #include <linux/pm_runtime.h>
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
33
  #include <linux/dmaengine.h>
580975d7f   Shawn Guo   dmaengine: imx-sd...
34
  #include <linux/of.h>
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
35
  #include <linux/of_address.h>
580975d7f   Shawn Guo   dmaengine: imx-sd...
36
  #include <linux/of_device.h>
9479e17c9   Shawn Guo   dma: imx-sdma: mo...
37
  #include <linux/of_dma.h>
b8603d2a5   Lucas Stach   dmaengine: imx-sd...
38
  #include <linux/workqueue.h>
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
39
40
  
  #include <asm/irq.h>
82906b13a   Arnd Bergmann   ARM: imx: move pl...
41
42
  #include <linux/platform_data/dma-imx-sdma.h>
  #include <linux/platform_data/dma-imx.h>
d078cd1b4   Zidan Wang   dmaengine: imx-sd...
43
44
45
  #include <linux/regmap.h>
  #include <linux/mfd/syscon.h>
  #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
46

d2ebfb335   Russell King - ARM Linux   dmaengine: add pr...
47
  #include "dmaengine.h"
57b772b86   Robin Gong   dmaengine: imx-sd...
48
  #include "virt-dma.h"
d2ebfb335   Russell King - ARM Linux   dmaengine: add pr...
49

1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  /* SDMA registers */
  #define SDMA_H_C0PTR		0x000
  #define SDMA_H_INTR		0x004
  #define SDMA_H_STATSTOP		0x008
  #define SDMA_H_START		0x00c
  #define SDMA_H_EVTOVR		0x010
  #define SDMA_H_DSPOVR		0x014
  #define SDMA_H_HOSTOVR		0x018
  #define SDMA_H_EVTPEND		0x01c
  #define SDMA_H_DSPENBL		0x020
  #define SDMA_H_RESET		0x024
  #define SDMA_H_EVTERR		0x028
  #define SDMA_H_INTRMSK		0x02c
  #define SDMA_H_PSW		0x030
  #define SDMA_H_EVTERRDBG	0x034
  #define SDMA_H_CONFIG		0x038
  #define SDMA_ONCE_ENB		0x040
  #define SDMA_ONCE_DATA		0x044
  #define SDMA_ONCE_INSTR		0x048
  #define SDMA_ONCE_STAT		0x04c
  #define SDMA_ONCE_CMD		0x050
  #define SDMA_EVT_MIRROR		0x054
  #define SDMA_ILLINSTADDR	0x058
  #define SDMA_CHN0ADDR		0x05c
  #define SDMA_ONCE_RTB		0x060
  #define SDMA_XTRIG_CONF1	0x070
  #define SDMA_XTRIG_CONF2	0x074
62550cd7c   Shawn Guo   dmaengine: imx-sd...
77
78
  #define SDMA_CHNENBL0_IMX35	0x200
  #define SDMA_CHNENBL0_IMX31	0x080
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
79
  #define SDMA_CHNPRI_0		0x100
d431de8fb   Robin Gong   dmaengine: imx-sd...
80
81
82
  #define SDMA_DONE0_CONFIG	0x1000
  #define SDMA_DONE0_CONFIG_DONE_SEL	0x7
  #define SDMA_DONE0_CONFIG_DONE_DIS	0x6
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  
  /*
   * Buffer descriptor status values.
   */
  #define BD_DONE  0x01
  #define BD_WRAP  0x02
  #define BD_CONT  0x04
  #define BD_INTR  0x08
  #define BD_RROR  0x10
  #define BD_LAST  0x20
  #define BD_EXTD  0x80
  
  /*
   * Data Node descriptor status values.
   */
  #define DND_END_OF_FRAME  0x80
  #define DND_END_OF_XFER   0x40
  #define DND_DONE          0x20
  #define DND_UNUSED        0x01
  
  /*
   * IPCV2 descriptor status values.
   */
  #define BD_IPCV2_END_OF_FRAME  0x40
  
  #define IPCV2_MAX_NODES        50
  /*
   * Error bit set in the CCB status field by the SDMA,
   * in setbd routine, in case of a transfer error
   */
  #define DATA_ERROR  0x10000000
  
  /*
   * Buffer descriptor commands.
   */
  #define C0_ADDR             0x01
  #define C0_LOAD             0x02
  #define C0_DUMP             0x03
  #define C0_SETCTX           0x07
  #define C0_GETCTX           0x03
  #define C0_SETDM            0x01
  #define C0_SETPM            0x04
  #define C0_GETDM            0x02
  #define C0_GETPM            0x08
  /*
   * Change endianness indicator in the BD command field
   */
  #define CHANGE_ENDIANNESS   0x80
  
  /*
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
   *  p_2_p watermark_level description
   *	Bits		Name			Description
   *	0-7		Lower WML		Lower watermark level
   *	8		PS			1: Pad Swallowing
   *						0: No Pad Swallowing
   *	9		PA			1: Pad Adding
   *						0: No Pad Adding
   *	10		SPDIF			If this bit is set both source
   *						and destination are on SPBA
   *	11		Source Bit(SP)		1: Source on SPBA
   *						0: Source on AIPS
   *	12		Destination Bit(DP)	1: Destination on SPBA
   *						0: Destination on AIPS
   *	13-15		---------		MUST BE 0
   *	16-23		Higher WML		HWML
   *	24-27		N			Total number of samples after
   *						which Pad adding/Swallowing
   *						must be done. It must be odd.
   *	28		Lower WML Event(LWE)	SDMA events reg to check for
   *						LWML event mask
   *						0: LWE in EVENTS register
   *						1: LWE in EVENTS2 register
   *	29		Higher WML Event(HWE)	SDMA events reg to check for
   *						HWML event mask
   *						0: HWE in EVENTS register
   *						1: HWE in EVENTS2 register
   *	30		---------		MUST BE 0
   *	31		CONT			1: Amount of samples to be
   *						transferred is unknown and
   *						script will keep on
   *						transferring samples as long as
   *						both events are detected and
   *						script must be manually stopped
   *						by the application
   *						0: The amount of samples to be
   *						transferred is equal to the
   *						count field of mode word
   */
  #define SDMA_WATERMARK_LEVEL_LWML	0xFF
  #define SDMA_WATERMARK_LEVEL_PS		BIT(8)
  #define SDMA_WATERMARK_LEVEL_PA		BIT(9)
  #define SDMA_WATERMARK_LEVEL_SPDIF	BIT(10)
  #define SDMA_WATERMARK_LEVEL_SP		BIT(11)
  #define SDMA_WATERMARK_LEVEL_DP		BIT(12)
883a39c56   Shengjiu Wang   MLK-11259-1: dmae...
177
178
  #define SDMA_WATERMARK_LEVEL_SD		BIT(13)
  #define SDMA_WATERMARK_LEVEL_DD		BIT(14)
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
179
180
181
182
  #define SDMA_WATERMARK_LEVEL_HWML	(0xFF << 16)
  #define SDMA_WATERMARK_LEVEL_LWE	BIT(28)
  #define SDMA_WATERMARK_LEVEL_HWE	BIT(29)
  #define SDMA_WATERMARK_LEVEL_CONT	BIT(31)
f9d4a398f   Nicolin Chen   dmaengine: imx-sd...
183
184
  #define SDMA_DMA_BUSWIDTHS	(BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
  				 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
df2b7feb7   Shengjiu Wang   MLK-16885-1: DMA:...
185
  				 BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \
f9d4a398f   Nicolin Chen   dmaengine: imx-sd...
186
187
188
189
190
  				 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
  
  #define SDMA_DMA_DIRECTIONS	(BIT(DMA_DEV_TO_MEM) | \
  				 BIT(DMA_MEM_TO_DEV) | \
  				 BIT(DMA_DEV_TO_DEV))
d431de8fb   Robin Gong   dmaengine: imx-sd...
191
192
193
  #define SDMA_WATERMARK_LEVEL_FIFOS_OFF	12
  #define SDMA_WATERMARK_LEVEL_SW_DONE	BIT(23)
  #define SDMA_WATERMARK_LEVEL_SW_DONE_SEL_OFF 24
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
194
  /*
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
195
196
197
   * Mode/Count of data node descriptors - IPCv2
   */
  struct sdma_mode_count {
4a6b2e8a9   Robin Gong   dmaengine: imx-sd...
198
  #define SDMA_BD_MAX_CNT	0xffff
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
199
200
  	u32 count   : 16; /* size of the buffer pointed by this BD */
  	u32 status  :  8; /* E,R,I,C,W,D status bits stored here */
e4b75760f   Martin Kaiser   dmaengine: imx-sd...
201
  	u32 command :  8; /* command mostly used for channel 0 */
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
  };
  
  /*
   * Buffer descriptor
   */
  struct sdma_buffer_descriptor {
  	struct sdma_mode_count  mode;
  	u32 buffer_addr;	/* address of the buffer described */
  	u32 ext_buffer_addr;	/* extended buffer address */
  } __attribute__ ((packed));
  
  /**
   * struct sdma_channel_control - Channel control Block
   *
24ca312dd   Robin Gong   dmaengine: imx-sd...
216
217
218
   * @current_bd_ptr:	current buffer descriptor processed
   * @base_bd_ptr:	first element of buffer descriptor array
   * @unused:		padding. The SDMA engine expects an array of 128 byte
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
219
220
221
222
223
224
225
226
227
228
229
230
   *			control blocks
   */
  struct sdma_channel_control {
  	u32 current_bd_ptr;
  	u32 base_bd_ptr;
  	u32 unused[2];
  } __attribute__ ((packed));
  
  /**
   * struct sdma_state_registers - SDMA context for a channel
   *
   * @pc:		program counter
24ca312dd   Robin Gong   dmaengine: imx-sd...
231
   * @unused1:	unused
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
232
233
   * @t:		test bit: status of arithmetic & test instruction
   * @rpc:	return program counter
24ca312dd   Robin Gong   dmaengine: imx-sd...
234
   * @unused0:	unused
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
235
236
   * @sf:		source fault while loading data
   * @spc:	loop start program counter
24ca312dd   Robin Gong   dmaengine: imx-sd...
237
   * @unused2:	unused
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
   * @df:		destination fault while storing data
   * @epc:	loop end program counter
   * @lm:		loop mode
   */
  struct sdma_state_registers {
  	u32 pc     :14;
  	u32 unused1: 1;
  	u32 t      : 1;
  	u32 rpc    :14;
  	u32 unused0: 1;
  	u32 sf     : 1;
  	u32 spc    :14;
  	u32 unused2: 1;
  	u32 df     : 1;
  	u32 epc    :14;
  	u32 lm     : 2;
  } __attribute__ ((packed));
  
  /**
   * struct sdma_context_data - sdma context specific to a channel
   *
   * @channel_state:	channel state bits
   * @gReg:		general registers
   * @mda:		burst dma destination address register
   * @msa:		burst dma source address register
   * @ms:			burst dma status register
   * @md:			burst dma data register
   * @pda:		peripheral dma destination address register
   * @psa:		peripheral dma source address register
   * @ps:			peripheral dma status register
   * @pd:			peripheral dma data register
   * @ca:			CRC polynomial register
   * @cs:			CRC accumulator register
   * @dda:		dedicated core destination address register
   * @dsa:		dedicated core source address register
   * @ds:			dedicated core status register
   * @dd:			dedicated core data register
24ca312dd   Robin Gong   dmaengine: imx-sd...
275
276
277
278
279
280
281
282
   * @scratch0:		1st word of dedicated ram for context switch
   * @scratch1:		2nd word of dedicated ram for context switch
   * @scratch2:		3rd word of dedicated ram for context switch
   * @scratch3:		4th word of dedicated ram for context switch
   * @scratch4:		5th word of dedicated ram for context switch
   * @scratch5:		6th word of dedicated ram for context switch
   * @scratch6:		7th word of dedicated ram for context switch
   * @scratch7:		8th word of dedicated ram for context switch
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
   */
  struct sdma_context_data {
  	struct sdma_state_registers  channel_state;
  	u32  gReg[8];
  	u32  mda;
  	u32  msa;
  	u32  ms;
  	u32  md;
  	u32  pda;
  	u32  psa;
  	u32  ps;
  	u32  pd;
  	u32  ca;
  	u32  cs;
  	u32  dda;
  	u32  dsa;
  	u32  ds;
  	u32  dd;
  	u32  scratch0;
  	u32  scratch1;
  	u32  scratch2;
  	u32  scratch3;
  	u32  scratch4;
  	u32  scratch5;
  	u32  scratch6;
  	u32  scratch7;
  } __attribute__ ((packed));
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
310
311
312
313
  
  struct sdma_engine;
  
  /**
76c33d270   Sascha Hauer   dmaengine: imx-sd...
314
   * struct sdma_desc - descriptor structor for one transfer
24ca312dd   Robin Gong   dmaengine: imx-sd...
315
316
317
318
319
320
321
322
323
324
   * @vd:			descriptor for virt dma
   * @num_bd:		number of descriptors currently handling
   * @bd_phys:		physical address of bd
   * @buf_tail:		ID of the buffer that was processed
   * @buf_ptail:		ID of the previous buffer that was processed
   * @period_len:		period length, used in cyclic.
   * @chn_real_count:	the real count updated from bd->mode.count
   * @chn_count:		the transfer count set
   * @sdmac:		sdma_channel pointer
   * @bd:			pointer of allocate bd
76c33d270   Sascha Hauer   dmaengine: imx-sd...
325
326
   */
  struct sdma_desc {
57b772b86   Robin Gong   dmaengine: imx-sd...
327
  	struct virt_dma_desc	vd;
76c33d270   Sascha Hauer   dmaengine: imx-sd...
328
329
330
331
332
333
334
335
336
337
338
339
  	unsigned int		num_bd;
  	dma_addr_t		bd_phys;
  	unsigned int		buf_tail;
  	unsigned int		buf_ptail;
  	unsigned int		period_len;
  	unsigned int		chn_real_count;
  	unsigned int		chn_count;
  	struct sdma_channel	*sdmac;
  	struct sdma_buffer_descriptor *bd;
  };
  
  /**
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
340
341
   * struct sdma_channel - housekeeping for a SDMA channel
   *
24ca312dd   Robin Gong   dmaengine: imx-sd...
342
343
344
345
346
   * @vc:			virt_dma base structure
   * @desc:		sdma description including vd and other special member
   * @sdma:		pointer to the SDMA engine for this channel
   * @channel:		the channel number, matches dmaengine chan_id + 1
   * @direction:		transfer type. Needed for setting SDMA script
d0c4a1492   Lee Jones   dmaengine: imx-sd...
347
   * @slave_config:	Slave configuration
24ca312dd   Robin Gong   dmaengine: imx-sd...
348
349
350
351
352
353
354
   * @peripheral_type:	Peripheral type. Needed for setting SDMA script
   * @event_id0:		aka dma request line
   * @event_id1:		for channels that use 2 events
   * @word_size:		peripheral access size
   * @pc_from_device:	script address for those device_2_memory
   * @pc_to_device:	script address for those memory_2_device
   * @device_to_device:	script address for those device_2_device
0f06c0275   Robin Gong   dmaengine: imx-sd...
355
   * @pc_to_pc:		script address for those memory_2_memory
24ca312dd   Robin Gong   dmaengine: imx-sd...
356
357
358
359
360
361
362
363
364
365
   * @flags:		loop mode or not
   * @per_address:	peripheral source or destination address in common case
   *                      destination address in p_2_p case
   * @per_address2:	peripheral source address in p_2_p case
   * @event_mask:		event mask used in p_2_p script
   * @watermark_level:	value for gReg[7], some script will extend it from
   *			basic watermark such as p_2_p
   * @shp_addr:		value for gReg[6]
   * @per_addr:		value for gReg[2]
   * @status:		status of dma channel
d0c4a1492   Lee Jones   dmaengine: imx-sd...
366
   * @context_loaded:	ensure context is only loaded once
24ca312dd   Robin Gong   dmaengine: imx-sd...
367
368
   * @data:		specific sdma interface structure
   * @bd_pool:		dma_pool for bd
d0c4a1492   Lee Jones   dmaengine: imx-sd...
369
   * @terminate_worker:	used to call back into terminate work function
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
370
371
   */
  struct sdma_channel {
57b772b86   Robin Gong   dmaengine: imx-sd...
372
  	struct virt_dma_chan		vc;
76c33d270   Sascha Hauer   dmaengine: imx-sd...
373
  	struct sdma_desc		*desc;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
374
375
  	struct sdma_engine		*sdma;
  	unsigned int			channel;
db8196df4   Vinod Koul   dmaengine: move d...
376
  	enum dma_transfer_direction		direction;
107d06441   Vinod Koul   dmaengine: imx-sd...
377
  	struct dma_slave_config		slave_config;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
378
379
380
381
  	enum sdma_peripheral_type	peripheral_type;
  	unsigned int			event_id0;
  	unsigned int			event_id1;
  	enum dma_slave_buswidth		word_size;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
382
  	unsigned int			pc_from_device, pc_to_device;
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
383
  	unsigned int			device_to_device;
0f06c0275   Robin Gong   dmaengine: imx-sd...
384
  	unsigned int                    pc_to_pc;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
385
  	unsigned long			flags;
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
386
  	dma_addr_t			per_address, per_address2;
0bbc14130   Richard Zhao   dma/imx-sdma: con...
387
388
  	unsigned long			event_mask[2];
  	unsigned long			watermark_level;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
389
  	u32				shp_addr, per_addr;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
390
  	enum dma_status			status;
0b3518652   Nicolin Chen   dmaengine: imx-sd...
391
  	struct imx_dma_data		data;
b8603d2a5   Lucas Stach   dmaengine: imx-sd...
392
  	struct work_struct		terminate_worker;
24e30e721   Robin Gong   dmaengine: imx-sd...
393
  	struct list_head                terminated;
57d1ed37c   Robin Gong   dmaengine: imx-sd...
394
  	bool				is_ram_script;
883a39c56   Shengjiu Wang   MLK-11259-1: dmae...
395
396
  	bool				src_dualfifo;
  	bool				dst_dualfifo;
d431de8fb   Robin Gong   dmaengine: imx-sd...
397
398
399
  	unsigned int			fifo_num;
  	bool				sw_done;
  	u32				sw_done_sel;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
400
  };
0bbc14130   Richard Zhao   dma/imx-sdma: con...
401
  #define IMX_DMA_SG_LOOP		BIT(0)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
402
403
404
405
406
  
  #define MAX_DMA_CHANNELS 32
  #define MXC_SDMA_DEFAULT_PRIORITY 1
  #define MXC_SDMA_MIN_PRIORITY 1
  #define MXC_SDMA_MAX_PRIORITY 7
57d1ed37c   Robin Gong   dmaengine: imx-sd...
407
408
409
410
411
412
413
414
  /*
   * 0x78(SDMA_XTRIG_CONF2+4)~0x100(SDMA_CHNPRI_O) registers are reserved and
   * can't be accessed. Skip these register touch in suspend/resume. Also below
   * two macros are only used on i.mx6sx.
   */
  #define MXC_SDMA_RESERVED_REG (SDMA_CHNPRI_0 - SDMA_XTRIG_CONF2 - 4)
  #define MXC_SDMA_SAVED_REG_NUM (((SDMA_CHNENBL0_IMX35 + 4 * 48) - \
  				MXC_SDMA_RESERVED_REG) / 4)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
415
416
417
418
419
  #define SDMA_FIRMWARE_MAGIC 0x414d4453
  
  /**
   * struct sdma_firmware_header - Layout of the firmware image
   *
24ca312dd   Robin Gong   dmaengine: imx-sd...
420
421
422
423
424
425
426
427
428
   * @magic:		"SDMA"
   * @version_major:	increased whenever layout of struct
   *			sdma_script_start_addrs changes.
   * @version_minor:	firmware minor version (for binary compatible changes)
   * @script_addrs_start:	offset of struct sdma_script_start_addrs in this image
   * @num_script_addrs:	Number of script addresses in this image
   * @ram_code_start:	offset of SDMA ram image in this firmware image
   * @ram_code_size:	size of SDMA ram image
   * @script_addrs:	Stores the start address of the SDMA scripts
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
429
430
431
432
433
434
435
436
437
438
439
   *			(in SDMA memory space)
   */
  struct sdma_firmware_header {
  	u32	magic;
  	u32	version_major;
  	u32	version_minor;
  	u32	script_addrs_start;
  	u32	num_script_addrs;
  	u32	ram_code_start;
  	u32	ram_code_size;
  };
17bba72f8   Sascha Hauer   dma: imx-sdma: Us...
440
441
442
  struct sdma_driver_data {
  	int chnenbl0;
  	int num_events;
dcfec3c09   Sascha Hauer   dma: imx-sdma: Ad...
443
  	struct sdma_script_start_addrs	*script_addrs;
941acd566   Angus Ainslie (Purism)   dmaengine: imx-sd...
444
  	bool check_ratio;
21f5bae68   Robin Gong   dmaengine: imx-sd...
445
446
447
448
449
450
451
  	/*
  	 * ecspi ERR009165 fixed should be done in sdma script
  	 * and it be fixed in soc from i.mx6ul.
  	 * please get more information from below link:
  	 * https://www.nxp.com/docs/en/errata/IMX6DQCE.pdf
  	 */
  	bool ecspi_fixed;
ad57e9874   Robin Gong   MLK-23540 dmaengi...
452
  	bool has_done0;
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
453
  	bool pm_runtime;
62550cd7c   Shawn Guo   dmaengine: imx-sd...
454
  };
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
455
456
457
458
  struct sdma_engine {
  	struct device			*dev;
  	struct sdma_channel		channel[MAX_DMA_CHANNELS];
  	struct sdma_channel_control	*channel_control;
57d1ed37c   Robin Gong   dmaengine: imx-sd...
459
  	u32				save_regs[MXC_SDMA_SAVED_REG_NUM];
ad57e9874   Robin Gong   MLK-23540 dmaengi...
460
  	u32				save_done0_regs[2];
57d1ed37c   Robin Gong   dmaengine: imx-sd...
461
  	const char			*fw_name;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
462
  	void __iomem			*regs;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
463
464
  	struct sdma_context_data	*context;
  	dma_addr_t			context_phys;
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
465
  	dma_addr_t			ccb_phys;
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
466
  	bool				is_on;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
467
  	struct dma_device		dma_device;
7560e3f35   Sascha Hauer   dmaengine i.MX SD...
468
469
  	struct clk			*clk_ipg;
  	struct clk			*clk_ahb;
2ccaef052   Richard Zhao   dma: imx-sdma: ma...
470
  	spinlock_t			channel_0_lock;
cd72b8462   Nicolin Chen   dma: imx-sdma: Ad...
471
  	u32				script_number;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
472
  	struct sdma_script_start_addrs	*script_addrs;
17bba72f8   Sascha Hauer   dma: imx-sdma: Us...
473
  	const struct sdma_driver_data	*drvdata;
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
474
475
  	u32				spba_start_addr;
  	u32				spba_end_addr;
5bb9dbb5a   Vinod Koul   dmaengine: imx-sd...
476
  	unsigned int			irq;
76c33d270   Sascha Hauer   dmaengine: imx-sd...
477
478
  	dma_addr_t			bd0_phys;
  	struct sdma_buffer_descriptor	*bd0;
25aaa75df   Angus Ainslie (Purism)   dmaengine: imx-sd...
479
480
  	/* clock ratio for AHB:SDMA core. 1:1 is 1, 2:1 is 0*/
  	bool				clk_ratio;
dd7efc1f2   Nicolin Chen   dmaengine: imx-sd...
481
  	struct gen_pool			*iram_pool;
57d1ed37c   Robin Gong   dmaengine: imx-sd...
482
  	bool				fw_loaded;
fec4cb374   Robin Gong   LF-301: dmaengine...
483
  	u32				fw_fail;
57d1ed37c   Robin Gong   dmaengine: imx-sd...
484
  	unsigned short			ram_code_start;
17bba72f8   Sascha Hauer   dma: imx-sdma: Us...
485
  };
107d06441   Vinod Koul   dmaengine: imx-sd...
486
487
488
  static int sdma_config_write(struct dma_chan *chan,
  		       struct dma_slave_config *dmaengine_cfg,
  		       enum dma_transfer_direction direction);
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
489
490
  static int sdma_get_firmware(struct sdma_engine *sdma,
  		const char *fw_name);
5763d3189   Robin Gong   MLK-23869-3: dmae...
491
492
  static int sdma_get_firmware_wait(struct sdma_engine *sdma,
  		const char *fw_name);
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
493

e9fd58de6   Fabio Estevam   dma: imx-sdma: St...
494
  static struct sdma_driver_data sdma_imx31 = {
17bba72f8   Sascha Hauer   dma: imx-sdma: Us...
495
496
497
  	.chnenbl0 = SDMA_CHNENBL0_IMX31,
  	.num_events = 32,
  };
dcfec3c09   Sascha Hauer   dma: imx-sdma: Ad...
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
  static struct sdma_script_start_addrs sdma_script_imx25 = {
  	.ap_2_ap_addr = 729,
  	.uart_2_mcu_addr = 904,
  	.per_2_app_addr = 1255,
  	.mcu_2_app_addr = 834,
  	.uartsh_2_mcu_addr = 1120,
  	.per_2_shp_addr = 1329,
  	.mcu_2_shp_addr = 1048,
  	.ata_2_mcu_addr = 1560,
  	.mcu_2_ata_addr = 1479,
  	.app_2_per_addr = 1189,
  	.app_2_mcu_addr = 770,
  	.shp_2_per_addr = 1407,
  	.shp_2_mcu_addr = 979,
  };
e9fd58de6   Fabio Estevam   dma: imx-sdma: St...
513
  static struct sdma_driver_data sdma_imx25 = {
dcfec3c09   Sascha Hauer   dma: imx-sdma: Ad...
514
515
516
517
  	.chnenbl0 = SDMA_CHNENBL0_IMX35,
  	.num_events = 48,
  	.script_addrs = &sdma_script_imx25,
  };
e9fd58de6   Fabio Estevam   dma: imx-sdma: St...
518
  static struct sdma_driver_data sdma_imx35 = {
17bba72f8   Sascha Hauer   dma: imx-sdma: Us...
519
520
  	.chnenbl0 = SDMA_CHNENBL0_IMX35,
  	.num_events = 48,
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
521
  };
dcfec3c09   Sascha Hauer   dma: imx-sdma: Ad...
522
523
524
525
526
527
528
529
530
531
532
533
  static struct sdma_script_start_addrs sdma_script_imx51 = {
  	.ap_2_ap_addr = 642,
  	.uart_2_mcu_addr = 817,
  	.mcu_2_app_addr = 747,
  	.mcu_2_shp_addr = 961,
  	.ata_2_mcu_addr = 1473,
  	.mcu_2_ata_addr = 1392,
  	.app_2_per_addr = 1033,
  	.app_2_mcu_addr = 683,
  	.shp_2_per_addr = 1251,
  	.shp_2_mcu_addr = 892,
  };
e9fd58de6   Fabio Estevam   dma: imx-sdma: St...
534
  static struct sdma_driver_data sdma_imx51 = {
dcfec3c09   Sascha Hauer   dma: imx-sdma: Ad...
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
  	.chnenbl0 = SDMA_CHNENBL0_IMX35,
  	.num_events = 48,
  	.script_addrs = &sdma_script_imx51,
  };
  
  static struct sdma_script_start_addrs sdma_script_imx53 = {
  	.ap_2_ap_addr = 642,
  	.app_2_mcu_addr = 683,
  	.mcu_2_app_addr = 747,
  	.uart_2_mcu_addr = 817,
  	.shp_2_mcu_addr = 891,
  	.mcu_2_shp_addr = 960,
  	.uartsh_2_mcu_addr = 1032,
  	.spdif_2_mcu_addr = 1100,
  	.mcu_2_spdif_addr = 1134,
  	.firi_2_mcu_addr = 1193,
  	.mcu_2_firi_addr = 1290,
  };
e9fd58de6   Fabio Estevam   dma: imx-sdma: St...
553
  static struct sdma_driver_data sdma_imx53 = {
dcfec3c09   Sascha Hauer   dma: imx-sdma: Ad...
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
  	.chnenbl0 = SDMA_CHNENBL0_IMX35,
  	.num_events = 48,
  	.script_addrs = &sdma_script_imx53,
  };
  
  static struct sdma_script_start_addrs sdma_script_imx6q = {
  	.ap_2_ap_addr = 642,
  	.uart_2_mcu_addr = 817,
  	.mcu_2_app_addr = 747,
  	.per_2_per_addr = 6331,
  	.uartsh_2_mcu_addr = 1032,
  	.mcu_2_shp_addr = 960,
  	.app_2_mcu_addr = 683,
  	.shp_2_mcu_addr = 891,
  	.spdif_2_mcu_addr = 1100,
  	.mcu_2_spdif_addr = 1134,
  };
e9fd58de6   Fabio Estevam   dma: imx-sdma: St...
571
  static struct sdma_driver_data sdma_imx6q = {
dcfec3c09   Sascha Hauer   dma: imx-sdma: Ad...
572
573
574
575
  	.chnenbl0 = SDMA_CHNENBL0_IMX35,
  	.num_events = 48,
  	.script_addrs = &sdma_script_imx6q,
  };
21f5bae68   Robin Gong   dmaengine: imx-sd...
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
  static struct sdma_script_start_addrs sdma_script_imx6sx = {
  	.ap_2_ap_addr = 642,
  	.uart_2_mcu_addr = 817,
  	.mcu_2_app_addr = 747,
  	.uartsh_2_mcu_addr = 1032,
  	.mcu_2_shp_addr = 960,
  	.app_2_mcu_addr = 683,
  	.shp_2_mcu_addr = 891,
  	.spdif_2_mcu_addr = 1100,
  	.mcu_2_spdif_addr = 1134,
  };
  
  static struct sdma_driver_data sdma_imx6sx = {
  	.chnenbl0 = SDMA_CHNENBL0_IMX35,
  	.num_events = 48,
  	.script_addrs = &sdma_script_imx6sx,
  };
  
  static struct sdma_driver_data sdma_imx6ul = {
  	.chnenbl0 = SDMA_CHNENBL0_IMX35,
  	.num_events = 48,
  	.script_addrs = &sdma_script_imx6sx,
  	.ecspi_fixed = true,
  };
b7d2648ac   Fabio Estevam   dmaengine: imx-sd...
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
  static struct sdma_script_start_addrs sdma_script_imx7d = {
  	.ap_2_ap_addr = 644,
  	.uart_2_mcu_addr = 819,
  	.mcu_2_app_addr = 749,
  	.uartsh_2_mcu_addr = 1034,
  	.mcu_2_shp_addr = 962,
  	.app_2_mcu_addr = 685,
  	.shp_2_mcu_addr = 893,
  	.spdif_2_mcu_addr = 1102,
  	.mcu_2_spdif_addr = 1136,
  };
  
  static struct sdma_driver_data sdma_imx7d = {
  	.chnenbl0 = SDMA_CHNENBL0_IMX35,
  	.num_events = 48,
  	.script_addrs = &sdma_script_imx7d,
  };
941acd566   Angus Ainslie (Purism)   dmaengine: imx-sd...
617
618
619
620
621
622
  static struct sdma_driver_data sdma_imx8mq = {
  	.chnenbl0 = SDMA_CHNENBL0_IMX35,
  	.num_events = 48,
  	.script_addrs = &sdma_script_imx7d,
  	.check_ratio = 1,
  };
9c485b715   Robin Gong   MLK-23400-1: dmae...
623
624
625
626
627
628
  static struct sdma_driver_data sdma_imx8mp = {
  	.chnenbl0 = SDMA_CHNENBL0_IMX35,
  	.num_events = 48,
  	.script_addrs = &sdma_script_imx7d,
  	.check_ratio = 1,
  	.ecspi_fixed = true,
ad57e9874   Robin Gong   MLK-23540 dmaengi...
629
  	.has_done0 = true,
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
630
  	.pm_runtime = true,
9c485b715   Robin Gong   MLK-23400-1: dmae...
631
  };
afe7cded9   Krzysztof Kozlowski   dmaengine: imx: C...
632
  static const struct platform_device_id sdma_devtypes[] = {
62550cd7c   Shawn Guo   dmaengine: imx-sd...
633
  	{
dcfec3c09   Sascha Hauer   dma: imx-sdma: Ad...
634
635
636
  		.name = "imx25-sdma",
  		.driver_data = (unsigned long)&sdma_imx25,
  	}, {
62550cd7c   Shawn Guo   dmaengine: imx-sd...
637
  		.name = "imx31-sdma",
17bba72f8   Sascha Hauer   dma: imx-sdma: Us...
638
  		.driver_data = (unsigned long)&sdma_imx31,
62550cd7c   Shawn Guo   dmaengine: imx-sd...
639
640
  	}, {
  		.name = "imx35-sdma",
17bba72f8   Sascha Hauer   dma: imx-sdma: Us...
641
  		.driver_data = (unsigned long)&sdma_imx35,
62550cd7c   Shawn Guo   dmaengine: imx-sd...
642
  	}, {
dcfec3c09   Sascha Hauer   dma: imx-sdma: Ad...
643
644
645
646
647
648
649
650
651
  		.name = "imx51-sdma",
  		.driver_data = (unsigned long)&sdma_imx51,
  	}, {
  		.name = "imx53-sdma",
  		.driver_data = (unsigned long)&sdma_imx53,
  	}, {
  		.name = "imx6q-sdma",
  		.driver_data = (unsigned long)&sdma_imx6q,
  	}, {
21f5bae68   Robin Gong   dmaengine: imx-sd...
652
653
654
  		.name = "imx6sx-sdma",
  		.driver_data = (unsigned long)&sdma_imx6sx,
  	}, {
b7d2648ac   Fabio Estevam   dmaengine: imx-sd...
655
656
657
  		.name = "imx7d-sdma",
  		.driver_data = (unsigned long)&sdma_imx7d,
  	}, {
21f5bae68   Robin Gong   dmaengine: imx-sd...
658
659
660
  		.name = "imx6ul-sdma",
  		.driver_data = (unsigned long)&sdma_imx6ul,
  	}, {
941acd566   Angus Ainslie (Purism)   dmaengine: imx-sd...
661
662
663
  		.name = "imx8mq-sdma",
  		.driver_data = (unsigned long)&sdma_imx8mq,
  	}, {
9c485b715   Robin Gong   MLK-23400-1: dmae...
664
665
666
  		.name = "imx8mp-sdma",
  		.driver_data = (unsigned long)&sdma_imx8mp,
  	}, {
62550cd7c   Shawn Guo   dmaengine: imx-sd...
667
668
669
670
  		/* sentinel */
  	}
  };
  MODULE_DEVICE_TABLE(platform, sdma_devtypes);
580975d7f   Shawn Guo   dmaengine: imx-sd...
671
  static const struct of_device_id sdma_dt_ids[] = {
dcfec3c09   Sascha Hauer   dma: imx-sdma: Ad...
672
673
674
  	{ .compatible = "fsl,imx6q-sdma", .data = &sdma_imx6q, },
  	{ .compatible = "fsl,imx53-sdma", .data = &sdma_imx53, },
  	{ .compatible = "fsl,imx51-sdma", .data = &sdma_imx51, },
17bba72f8   Sascha Hauer   dma: imx-sdma: Us...
675
  	{ .compatible = "fsl,imx35-sdma", .data = &sdma_imx35, },
dcfec3c09   Sascha Hauer   dma: imx-sdma: Ad...
676
  	{ .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, },
63edea16b   Markus Pargmann   dma: sdma: Add im...
677
  	{ .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, },
21f5bae68   Robin Gong   dmaengine: imx-sd...
678
  	{ .compatible = "fsl,imx6sx-sdma", .data = &sdma_imx6sx, },
b7d2648ac   Fabio Estevam   dmaengine: imx-sd...
679
  	{ .compatible = "fsl,imx7d-sdma", .data = &sdma_imx7d, },
21f5bae68   Robin Gong   dmaengine: imx-sd...
680
  	{ .compatible = "fsl,imx6ul-sdma", .data = &sdma_imx6ul, },
941acd566   Angus Ainslie (Purism)   dmaengine: imx-sd...
681
  	{ .compatible = "fsl,imx8mq-sdma", .data = &sdma_imx8mq, },
9c485b715   Robin Gong   MLK-23400-1: dmae...
682
  	{ .compatible = "fsl,imx8mp-sdma", .data = &sdma_imx8mp, },
580975d7f   Shawn Guo   dmaengine: imx-sd...
683
684
685
  	{ /* sentinel */ }
  };
  MODULE_DEVICE_TABLE(of, sdma_dt_ids);
0bbc14130   Richard Zhao   dma/imx-sdma: con...
686
687
688
  #define SDMA_H_CONFIG_DSPDMA	BIT(12) /* indicates if the DSPDMA is used */
  #define SDMA_H_CONFIG_RTD_PINS	BIT(11) /* indicates if Real-Time Debug pins are enabled */
  #define SDMA_H_CONFIG_ACR	BIT(4)  /* indicates if AHB freq /core freq = 2 or 1 */
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
689
690
691
692
  #define SDMA_H_CONFIG_CSM	(3)       /* indicates which context switch mode is selected*/
  
  static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
  {
17bba72f8   Sascha Hauer   dma: imx-sdma: Us...
693
  	u32 chnenbl0 = sdma->drvdata->chnenbl0;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
694
695
696
697
698
699
700
701
  	return chnenbl0 + event * 4;
  }
  
  static int sdma_config_ownership(struct sdma_channel *sdmac,
  		bool event_override, bool mcu_override, bool dsp_override)
  {
  	struct sdma_engine *sdma = sdmac->sdma;
  	int channel = sdmac->channel;
0bbc14130   Richard Zhao   dma/imx-sdma: con...
702
  	unsigned long evt, mcu, dsp;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
703
704
705
  
  	if (event_override && mcu_override && dsp_override)
  		return -EINVAL;
c4b56857d   Richard Zhao   dma/imx-sdma: use...
706
707
708
  	evt = readl_relaxed(sdma->regs + SDMA_H_EVTOVR);
  	mcu = readl_relaxed(sdma->regs + SDMA_H_HOSTOVR);
  	dsp = readl_relaxed(sdma->regs + SDMA_H_DSPOVR);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
709
710
  
  	if (dsp_override)
0bbc14130   Richard Zhao   dma/imx-sdma: con...
711
  		__clear_bit(channel, &dsp);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
712
  	else
0bbc14130   Richard Zhao   dma/imx-sdma: con...
713
  		__set_bit(channel, &dsp);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
714
715
  
  	if (event_override)
0bbc14130   Richard Zhao   dma/imx-sdma: con...
716
  		__clear_bit(channel, &evt);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
717
  	else
0bbc14130   Richard Zhao   dma/imx-sdma: con...
718
  		__set_bit(channel, &evt);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
719
720
  
  	if (mcu_override)
0bbc14130   Richard Zhao   dma/imx-sdma: con...
721
  		__clear_bit(channel, &mcu);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
722
  	else
0bbc14130   Richard Zhao   dma/imx-sdma: con...
723
  		__set_bit(channel, &mcu);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
724

c4b56857d   Richard Zhao   dma/imx-sdma: use...
725
726
727
  	writel_relaxed(evt, sdma->regs + SDMA_H_EVTOVR);
  	writel_relaxed(mcu, sdma->regs + SDMA_H_HOSTOVR);
  	writel_relaxed(dsp, sdma->regs + SDMA_H_DSPOVR);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
728
729
730
  
  	return 0;
  }
b9a591664   Richard Zhao   dma/imx-sdma: let...
731
732
  static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
  {
0bbc14130   Richard Zhao   dma/imx-sdma: con...
733
  	writel(BIT(channel), sdma->regs + SDMA_H_START);
b9a591664   Richard Zhao   dma/imx-sdma: let...
734
  }
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
735
  /*
2ccaef052   Richard Zhao   dma: imx-sdma: ma...
736
   * sdma_run_channel0 - run a channel and wait till it's done
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
737
   */
2ccaef052   Richard Zhao   dma: imx-sdma: ma...
738
  static int sdma_run_channel0(struct sdma_engine *sdma)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
739
  {
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
740
  	int ret;
1d069bfa3   Michael Olbrich   dmaengine: imx-sd...
741
  	u32 reg;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
742

2ccaef052   Richard Zhao   dma: imx-sdma: ma...
743
  	sdma_enable_channel(sdma, 0);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
744

1d069bfa3   Michael Olbrich   dmaengine: imx-sd...
745
  	ret = readl_relaxed_poll_timeout_atomic(sdma->regs + SDMA_H_STATSTOP,
41fdb664e   Robin Gong   LF-3132: dmaengin...
746
  						reg, !(reg & 1), 1, 5000);
1d069bfa3   Michael Olbrich   dmaengine: imx-sd...
747
  	if (ret)
2ccaef052   Richard Zhao   dma: imx-sdma: ma...
748
749
  		dev_err(sdma->dev, "Timeout waiting for CH0 ready
  ");
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
750

855832e47   Robin Gong   dmaengine: imx-sd...
751
  	/* Set bits of CONFIG register with dynamic context switching */
25aaa75df   Angus Ainslie (Purism)   dmaengine: imx-sd...
752
753
754
755
756
  	reg = readl(sdma->regs + SDMA_H_CONFIG);
  	if ((reg & SDMA_H_CONFIG_CSM) == 0) {
  		reg |= SDMA_H_CONFIG_CSM;
  		writel_relaxed(reg, sdma->regs + SDMA_H_CONFIG);
  	}
855832e47   Robin Gong   dmaengine: imx-sd...
757

1d069bfa3   Michael Olbrich   dmaengine: imx-sd...
758
  	return ret;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
759
760
761
762
763
  }
  
  static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
  		u32 address)
  {
76c33d270   Sascha Hauer   dmaengine: imx-sd...
764
  	struct sdma_buffer_descriptor *bd0 = sdma->bd0;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
765
766
767
  	void *buf_virt;
  	dma_addr_t buf_phys;
  	int ret;
2ccaef052   Richard Zhao   dma: imx-sdma: ma...
768
  	unsigned long flags;
73eab978a   Sascha Hauer   dmaengine i.MX SD...
769

e961d76bb   Robin Gong   MLK-25116-1: dmae...
770
  	buf_virt = dma_alloc_coherent(sdma->dev, size, &buf_phys,
dd7efc1f2   Nicolin Chen   dmaengine: imx-sd...
771
772
  					      GFP_KERNEL);
  	if (!buf_virt)
2ccaef052   Richard Zhao   dma: imx-sdma: ma...
773
  		return -ENOMEM;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
774

2ccaef052   Richard Zhao   dma: imx-sdma: ma...
775
  	spin_lock_irqsave(&sdma->channel_0_lock, flags);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
776
  	bd0->mode.command = C0_SETPM;
3f93a4f29   Robin Gong   dmaengine: imx-sd...
777
  	bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
778
779
780
781
782
  	bd0->mode.count = size / 2;
  	bd0->buffer_addr = buf_phys;
  	bd0->ext_buffer_addr = address;
  
  	memcpy(buf_virt, buf, size);
2ccaef052   Richard Zhao   dma: imx-sdma: ma...
783
  	ret = sdma_run_channel0(sdma);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
784

2ccaef052   Richard Zhao   dma: imx-sdma: ma...
785
  	spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
786

e961d76bb   Robin Gong   MLK-25116-1: dmae...
787
  	dma_free_coherent(sdma->dev, size, buf_virt, buf_phys);
73eab978a   Sascha Hauer   dmaengine i.MX SD...
788

1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
789
790
791
792
793
794
795
  	return ret;
  }
  
  static void sdma_event_enable(struct sdma_channel *sdmac, unsigned int event)
  {
  	struct sdma_engine *sdma = sdmac->sdma;
  	int channel = sdmac->channel;
0bbc14130   Richard Zhao   dma/imx-sdma: con...
796
  	unsigned long val;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
797
  	u32 chnenbl = chnenbl_ofs(sdma, event);
c4b56857d   Richard Zhao   dma/imx-sdma: use...
798
  	val = readl_relaxed(sdma->regs + chnenbl);
0bbc14130   Richard Zhao   dma/imx-sdma: con...
799
  	__set_bit(channel, &val);
c4b56857d   Richard Zhao   dma/imx-sdma: use...
800
  	writel_relaxed(val, sdma->regs + chnenbl);
d431de8fb   Robin Gong   dmaengine: imx-sd...
801
802
803
804
805
806
807
808
809
810
811
812
813
814
  
  	/* Set SDMA_DONEx_CONFIG is sw_done enabled */
  	if (sdmac->sw_done) {
  		u32 offset = SDMA_DONE0_CONFIG + sdmac->sw_done_sel / 4;
  		u32 done_sel = SDMA_DONE0_CONFIG_DONE_SEL +
  				((sdmac->sw_done_sel % 4) << 3);
  		u32 sw_done_dis = SDMA_DONE0_CONFIG_DONE_DIS +
  				((sdmac->sw_done_sel % 4) << 3);
  
  		val = readl_relaxed(sdma->regs + offset);
  		__set_bit(done_sel, &val);
  		__clear_bit(sw_done_dis, &val);
  		writel_relaxed(val, sdma->regs + offset);
  	}
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
815
816
817
818
819
820
821
  }
  
  static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
  {
  	struct sdma_engine *sdma = sdmac->sdma;
  	int channel = sdmac->channel;
  	u32 chnenbl = chnenbl_ofs(sdma, event);
0bbc14130   Richard Zhao   dma/imx-sdma: con...
822
  	unsigned long val;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
823

c4b56857d   Richard Zhao   dma/imx-sdma: use...
824
  	val = readl_relaxed(sdma->regs + chnenbl);
0bbc14130   Richard Zhao   dma/imx-sdma: con...
825
  	__clear_bit(channel, &val);
c4b56857d   Richard Zhao   dma/imx-sdma: use...
826
  	writel_relaxed(val, sdma->regs + chnenbl);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
827
  }
57b772b86   Robin Gong   dmaengine: imx-sd...
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
  static struct sdma_desc *to_sdma_desc(struct dma_async_tx_descriptor *t)
  {
  	return container_of(t, struct sdma_desc, vd.tx);
  }
  
  static void sdma_start_desc(struct sdma_channel *sdmac)
  {
  	struct virt_dma_desc *vd = vchan_next_desc(&sdmac->vc);
  	struct sdma_desc *desc;
  	struct sdma_engine *sdma = sdmac->sdma;
  	int channel = sdmac->channel;
  
  	if (!vd) {
  		sdmac->desc = NULL;
  		return;
  	}
  	sdmac->desc = desc = to_sdma_desc(&vd->tx);
02939cd16   Sascha Hauer   dmaengine: imx-sd...
845
846
  
  	list_del(&vd->node);
57b772b86   Robin Gong   dmaengine: imx-sd...
847
848
849
850
851
  
  	sdma->channel_control[channel].base_bd_ptr = desc->bd_phys;
  	sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
  	sdma_enable_channel(sdma, sdmac->channel);
  }
d1a792f3b   Russell King - ARM Linux   Update imx-sdma c...
852
853
  static void sdma_update_channel_loop(struct sdma_channel *sdmac)
  {
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
854
  	struct sdma_buffer_descriptor *bd;
5881826de   Nandor Han   dmaengine: imx-sd...
855
856
  	int error = 0;
  	enum dma_status	old_status = sdmac->status;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
857
858
859
860
861
  
  	/*
  	 * loop mode. Iterate over descriptors, re-setup them and
  	 * call callback function.
  	 */
57b772b86   Robin Gong   dmaengine: imx-sd...
862
  	while (sdmac->desc) {
76c33d270   Sascha Hauer   dmaengine: imx-sd...
863
864
865
  		struct sdma_desc *desc = sdmac->desc;
  
  		bd = &desc->bd[desc->buf_tail];
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
866
867
868
  
  		if (bd->mode.status & BD_DONE)
  			break;
5881826de   Nandor Han   dmaengine: imx-sd...
869
870
  		if (bd->mode.status & BD_RROR) {
  			bd->mode.status &= ~BD_RROR;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
871
  			sdmac->status = DMA_ERROR;
5881826de   Nandor Han   dmaengine: imx-sd...
872
873
  			error = -EIO;
  		}
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
874

5881826de   Nandor Han   dmaengine: imx-sd...
875
876
877
878
  	       /*
  		* We use bd->mode.count to calculate the residue, since contains
  		* the number of bytes present in the current buffer descriptor.
  		*/
76c33d270   Sascha Hauer   dmaengine: imx-sd...
879
  		desc->chn_real_count = bd->mode.count;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
880
  		bd->mode.status |= BD_DONE;
76c33d270   Sascha Hauer   dmaengine: imx-sd...
881
882
883
  		bd->mode.count = desc->period_len;
  		desc->buf_ptail = desc->buf_tail;
  		desc->buf_tail = (desc->buf_tail + 1) % desc->num_bd;
15f30f513   Nandor Han   dmaengine: imx-sd...
884
885
886
887
888
889
890
  
  		/*
  		 * The callback is called from the interrupt context in order
  		 * to reduce latency and to avoid the risk of altering the
  		 * SDMA transaction status by the time the client tasklet is
  		 * executed.
  		 */
57b772b86   Robin Gong   dmaengine: imx-sd...
891
892
893
  		spin_unlock(&sdmac->vc.lock);
  		dmaengine_desc_get_callback_invoke(&desc->vd.tx, NULL);
  		spin_lock(&sdmac->vc.lock);
15f30f513   Nandor Han   dmaengine: imx-sd...
894

5881826de   Nandor Han   dmaengine: imx-sd...
895
896
  		if (error)
  			sdmac->status = old_status;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
897
898
  	}
  }
57b772b86   Robin Gong   dmaengine: imx-sd...
899
  static void mxc_sdma_handle_channel_normal(struct sdma_channel *data)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
900
  {
15f30f513   Nandor Han   dmaengine: imx-sd...
901
  	struct sdma_channel *sdmac = (struct sdma_channel *) data;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
902
903
  	struct sdma_buffer_descriptor *bd;
  	int i, error = 0;
76c33d270   Sascha Hauer   dmaengine: imx-sd...
904
  	sdmac->desc->chn_real_count = 0;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
905
906
907
908
  	/*
  	 * non loop mode. Iterate over all descriptors, collect
  	 * errors and call callback function
  	 */
76c33d270   Sascha Hauer   dmaengine: imx-sd...
909
910
  	for (i = 0; i < sdmac->desc->num_bd; i++) {
  		bd = &sdmac->desc->bd[i];
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
911
912
913
  
  		 if (bd->mode.status & (BD_DONE | BD_RROR))
  			error = -EIO;
76c33d270   Sascha Hauer   dmaengine: imx-sd...
914
  		 sdmac->desc->chn_real_count += bd->mode.count;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
915
916
917
918
919
  	}
  
  	if (error)
  		sdmac->status = DMA_ERROR;
  	else
409bff6a0   Vinod Koul   dmaengine: imx-sd...
920
  		sdmac->status = DMA_COMPLETE;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
921
  }
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
922
923
924
  static irqreturn_t sdma_int_handler(int irq, void *dev_id)
  {
  	struct sdma_engine *sdma = dev_id;
0bbc14130   Richard Zhao   dma/imx-sdma: con...
925
  	unsigned long stat;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
926

2fde63aff   Robin Gong   MLK-20598 dmaengi...
927
928
  	clk_enable(sdma->clk_ipg);
  	clk_enable(sdma->clk_ahb);
c4b56857d   Richard Zhao   dma/imx-sdma: use...
929
930
  	stat = readl_relaxed(sdma->regs + SDMA_H_INTR);
  	writel_relaxed(stat, sdma->regs + SDMA_H_INTR);
1d069bfa3   Michael Olbrich   dmaengine: imx-sd...
931
932
  	/* channel 0 is special and not handled here, see run_channel0() */
  	stat &= ~1;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
933
934
935
936
  
  	while (stat) {
  		int channel = fls(stat) - 1;
  		struct sdma_channel *sdmac = &sdma->channel[channel];
57b772b86   Robin Gong   dmaengine: imx-sd...
937
938
939
940
941
942
  		struct sdma_desc *desc;
  
  		spin_lock(&sdmac->vc.lock);
  		desc = sdmac->desc;
  		if (desc) {
  			if (sdmac->flags & IMX_DMA_SG_LOOP) {
3ec0b6819   Shengjiu Wang   dmaengine: imx-sd...
943
944
945
946
  				if (sdmac->peripheral_type != IMX_DMATYPE_HDMI)
  					sdma_update_channel_loop(sdmac);
  				else
  					vchan_cyclic_callback(&desc->vd);
57b772b86   Robin Gong   dmaengine: imx-sd...
947
948
949
950
951
952
  			} else {
  				mxc_sdma_handle_channel_normal(sdmac);
  				vchan_cookie_complete(&desc->vd);
  				sdma_start_desc(sdmac);
  			}
  		}
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
953

57b772b86   Robin Gong   dmaengine: imx-sd...
954
  		spin_unlock(&sdmac->vc.lock);
0bbc14130   Richard Zhao   dma/imx-sdma: con...
955
  		__clear_bit(channel, &stat);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
956
  	}
2fde63aff   Robin Gong   MLK-20598 dmaengi...
957
958
  	clk_disable(sdma->clk_ipg);
  	clk_disable(sdma->clk_ahb);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
  	return IRQ_HANDLED;
  }
  
  /*
   * sets the pc of SDMA script according to the peripheral type
   */
  static void sdma_get_pc(struct sdma_channel *sdmac,
  		enum sdma_peripheral_type peripheral_type)
  {
  	struct sdma_engine *sdma = sdmac->sdma;
  	int per_2_emi = 0, emi_2_per = 0;
  	/*
  	 * These are needed once we start to support transfers between
  	 * two peripherals or memory-to-memory transfers
  	 */
0f06c0275   Robin Gong   dmaengine: imx-sd...
974
  	int per_2_per = 0, emi_2_emi = 0;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
975
976
977
  
  	sdmac->pc_from_device = 0;
  	sdmac->pc_to_device = 0;
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
978
  	sdmac->device_to_device = 0;
0f06c0275   Robin Gong   dmaengine: imx-sd...
979
  	sdmac->pc_to_pc = 0;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
980
981
982
  
  	switch (peripheral_type) {
  	case IMX_DMATYPE_MEMORY:
0f06c0275   Robin Gong   dmaengine: imx-sd...
983
  		emi_2_emi = sdma->script_addrs->ap_2_ap_addr;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
  		break;
  	case IMX_DMATYPE_DSP:
  		emi_2_per = sdma->script_addrs->bp_2_ap_addr;
  		per_2_emi = sdma->script_addrs->ap_2_bp_addr;
  		break;
  	case IMX_DMATYPE_FIRI:
  		per_2_emi = sdma->script_addrs->firi_2_mcu_addr;
  		emi_2_per = sdma->script_addrs->mcu_2_firi_addr;
  		break;
  	case IMX_DMATYPE_UART:
  		per_2_emi = sdma->script_addrs->uart_2_mcu_addr;
  		emi_2_per = sdma->script_addrs->mcu_2_app_addr;
  		break;
  	case IMX_DMATYPE_UART_SP:
  		per_2_emi = sdma->script_addrs->uartsh_2_mcu_addr;
  		emi_2_per = sdma->script_addrs->mcu_2_shp_addr;
  		break;
  	case IMX_DMATYPE_ATA:
  		per_2_emi = sdma->script_addrs->ata_2_mcu_addr;
  		emi_2_per = sdma->script_addrs->mcu_2_ata_addr;
  		break;
  	case IMX_DMATYPE_CSPI:
9ec27cb4f   Robin Gong   dma: engine: imx-...
1006
1007
  		per_2_emi = sdma->script_addrs->app_2_mcu_addr;
  		emi_2_per = sdma->script_addrs->mcu_2_ecspi_addr;
b32477240   Robin Gong   LF-246: dmaengine...
1008
  		sdmac->is_ram_script = true;
9ec27cb4f   Robin Gong   dma: engine: imx-...
1009
  		break;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1010
1011
  	case IMX_DMATYPE_EXT:
  	case IMX_DMATYPE_SSI:
29aebfde8   Nicolin Chen   dmaengine: imx-sd...
1012
  	case IMX_DMATYPE_SAI:
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1013
1014
1015
  		per_2_emi = sdma->script_addrs->app_2_mcu_addr;
  		emi_2_per = sdma->script_addrs->mcu_2_app_addr;
  		break;
1a895578d   Nicolin Chen   dma: imx-sdma: Ad...
1016
1017
1018
  	case IMX_DMATYPE_SSI_DUAL:
  		per_2_emi = sdma->script_addrs->ssish_2_mcu_addr;
  		emi_2_per = sdma->script_addrs->mcu_2_ssish_addr;
b32477240   Robin Gong   LF-246: dmaengine...
1019
  		sdmac->is_ram_script = true;
1a895578d   Nicolin Chen   dma: imx-sdma: Ad...
1020
  		break;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
  	case IMX_DMATYPE_SSI_SP:
  	case IMX_DMATYPE_MMC:
  	case IMX_DMATYPE_SDHC:
  	case IMX_DMATYPE_CSPI_SP:
  	case IMX_DMATYPE_ESAI:
  	case IMX_DMATYPE_MSHC_SP:
  		per_2_emi = sdma->script_addrs->shp_2_mcu_addr;
  		emi_2_per = sdma->script_addrs->mcu_2_shp_addr;
  		break;
  	case IMX_DMATYPE_ASRC:
  		per_2_emi = sdma->script_addrs->asrc_2_mcu_addr;
  		emi_2_per = sdma->script_addrs->asrc_2_mcu_addr;
  		per_2_per = sdma->script_addrs->per_2_per_addr;
b32477240   Robin Gong   LF-246: dmaengine...
1034
  		sdmac->is_ram_script = true;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1035
  		break;
f892afb07   Nicolin Chen   dmaengine: imx-sd...
1036
1037
1038
1039
  	case IMX_DMATYPE_ASRC_SP:
  		per_2_emi = sdma->script_addrs->shp_2_mcu_addr;
  		emi_2_per = sdma->script_addrs->mcu_2_shp_addr;
  		per_2_per = sdma->script_addrs->per_2_per_addr;
b32477240   Robin Gong   LF-246: dmaengine...
1040
  		sdmac->is_ram_script = true;
f892afb07   Nicolin Chen   dmaengine: imx-sd...
1041
  		break;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
  	case IMX_DMATYPE_MSHC:
  		per_2_emi = sdma->script_addrs->mshc_2_mcu_addr;
  		emi_2_per = sdma->script_addrs->mcu_2_mshc_addr;
  		break;
  	case IMX_DMATYPE_CCM:
  		per_2_emi = sdma->script_addrs->dptc_dvfs_addr;
  		break;
  	case IMX_DMATYPE_SPDIF:
  		per_2_emi = sdma->script_addrs->spdif_2_mcu_addr;
  		emi_2_per = sdma->script_addrs->mcu_2_spdif_addr;
  		break;
  	case IMX_DMATYPE_IPU_MEMORY:
  		emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr;
  		break;
3ec0b6819   Shengjiu Wang   dmaengine: imx-sd...
1056
1057
  	case IMX_DMATYPE_HDMI:
  		emi_2_per = sdma->script_addrs->hdmi_dma_addr;
b32477240   Robin Gong   LF-246: dmaengine...
1058
  		sdmac->is_ram_script = true;
3ec0b6819   Shengjiu Wang   dmaengine: imx-sd...
1059
  		break;
d431de8fb   Robin Gong   dmaengine: imx-sd...
1060
1061
1062
  	case IMX_DMATYPE_MULTI_SAI:
  		per_2_emi = sdma->script_addrs->sai_2_mcu_addr;
  		emi_2_per = sdma->script_addrs->mcu_2_sai_addr;
b32477240   Robin Gong   LF-246: dmaengine...
1063
  		sdmac->is_ram_script = true;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1064
1065
1066
1067
1068
1069
  	default:
  		break;
  	}
  
  	sdmac->pc_from_device = per_2_emi;
  	sdmac->pc_to_device = emi_2_per;
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
1070
  	sdmac->device_to_device = per_2_per;
0f06c0275   Robin Gong   dmaengine: imx-sd...
1071
  	sdmac->pc_to_pc = emi_2_emi;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1072
1073
1074
1075
1076
1077
1078
1079
  }
  
  static int sdma_load_context(struct sdma_channel *sdmac)
  {
  	struct sdma_engine *sdma = sdmac->sdma;
  	int channel = sdmac->channel;
  	int load_address;
  	struct sdma_context_data *context = sdma->context;
76c33d270   Sascha Hauer   dmaengine: imx-sd...
1080
  	struct sdma_buffer_descriptor *bd0 = sdma->bd0;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1081
  	int ret;
2ccaef052   Richard Zhao   dma: imx-sdma: ma...
1082
  	unsigned long flags;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1083

8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
1084
  	if (sdmac->direction == DMA_DEV_TO_MEM)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1085
  		load_address = sdmac->pc_from_device;
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
1086
1087
  	else if (sdmac->direction == DMA_DEV_TO_DEV)
  		load_address = sdmac->device_to_device;
0f06c0275   Robin Gong   dmaengine: imx-sd...
1088
1089
  	else if (sdmac->direction == DMA_MEM_TO_MEM)
  		load_address = sdmac->pc_to_pc;
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
1090
  	else
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1091
  		load_address = sdmac->pc_to_device;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1092
1093
1094
1095
1096
1097
  
  	if (load_address < 0)
  		return load_address;
  
  	dev_dbg(sdma->dev, "load_address = %d
  ", load_address);
0bbc14130   Richard Zhao   dma/imx-sdma: con...
1098
1099
  	dev_dbg(sdma->dev, "wml = 0x%08x
  ", (u32)sdmac->watermark_level);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1100
1101
1102
1103
  	dev_dbg(sdma->dev, "shp_addr = 0x%08x
  ", sdmac->shp_addr);
  	dev_dbg(sdma->dev, "per_addr = 0x%08x
  ", sdmac->per_addr);
0bbc14130   Richard Zhao   dma/imx-sdma: con...
1104
1105
1106
1107
  	dev_dbg(sdma->dev, "event_mask0 = 0x%08x
  ", (u32)sdmac->event_mask[0]);
  	dev_dbg(sdma->dev, "event_mask1 = 0x%08x
  ", (u32)sdmac->event_mask[1]);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1108

2ccaef052   Richard Zhao   dma: imx-sdma: ma...
1109
  	spin_lock_irqsave(&sdma->channel_0_lock, flags);
73eab978a   Sascha Hauer   dmaengine i.MX SD...
1110

1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1111
1112
1113
1114
1115
1116
  	memset(context, 0, sizeof(*context));
  	context->channel_state.pc = load_address;
  
  	/* Send by context the event mask,base address for peripheral
  	 * and watermark level
  	 */
3ec0b6819   Shengjiu Wang   dmaengine: imx-sd...
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
  	if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) {
  		context->gReg[4] = sdmac->per_addr;
  		context->gReg[6] = sdmac->shp_addr;
  	} else {
  		context->gReg[0] = sdmac->event_mask[1];
  		context->gReg[1] = sdmac->event_mask[0];
  		context->gReg[2] = sdmac->per_addr;
  		context->gReg[6] = sdmac->shp_addr;
  		context->gReg[7] = sdmac->watermark_level;
  	}
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1127
1128
  
  	bd0->mode.command = C0_SETDM;
3f93a4f29   Robin Gong   dmaengine: imx-sd...
1129
  	bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1130
1131
1132
  	bd0->mode.count = sizeof(*context) / 4;
  	bd0->buffer_addr = sdma->context_phys;
  	bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel;
2ccaef052   Richard Zhao   dma: imx-sdma: ma...
1133
  	ret = sdma_run_channel0(sdma);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1134

2ccaef052   Richard Zhao   dma: imx-sdma: ma...
1135
  	spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
73eab978a   Sascha Hauer   dmaengine i.MX SD...
1136

1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1137
1138
  	return ret;
  }
57d1ed37c   Robin Gong   dmaengine: imx-sd...
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
  static int sdma_save_restore_context(struct sdma_engine *sdma, bool save)
  {
  	struct sdma_context_data *context = sdma->context;
  	struct sdma_buffer_descriptor *bd0 = sdma->bd0;
  	unsigned long flags;
  	int ret;
  
  	spin_lock_irqsave(&sdma->channel_0_lock, flags);
  
  	if (save)
  		bd0->mode.command = C0_GETDM;
  	else
  		bd0->mode.command = C0_SETDM;
  
  	bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
  	bd0->mode.count = MAX_DMA_CHANNELS * sizeof(*context) / 4;
  	bd0->buffer_addr = sdma->context_phys;
  	bd0->ext_buffer_addr = 2048;
  	ret = sdma_run_channel0(sdma);
  
  	spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
  
  	return ret;
  }
7b350ab0f   Maxime Ripard   dmaengine: imx-sd...
1163
1164
  static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
  {
57b772b86   Robin Gong   dmaengine: imx-sd...
1165
  	return container_of(chan, struct sdma_channel, vc.chan);
7b350ab0f   Maxime Ripard   dmaengine: imx-sd...
1166
1167
1168
  }
  
  static int sdma_disable_channel(struct dma_chan *chan)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1169
  {
7b350ab0f   Maxime Ripard   dmaengine: imx-sd...
1170
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1171
1172
  	struct sdma_engine *sdma = sdmac->sdma;
  	int channel = sdmac->channel;
0bbc14130   Richard Zhao   dma/imx-sdma: con...
1173
  	writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1174
  	sdmac->status = DMA_ERROR;
7b350ab0f   Maxime Ripard   dmaengine: imx-sd...
1175
1176
  
  	return 0;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1177
  }
b8603d2a5   Lucas Stach   dmaengine: imx-sd...
1178
  static void sdma_channel_terminate_work(struct work_struct *work)
7f3ff14b7   Jiada Wang   dmaengine: imx-sd...
1179
  {
b8603d2a5   Lucas Stach   dmaengine: imx-sd...
1180
1181
  	struct sdma_channel *sdmac = container_of(work, struct sdma_channel,
  						  terminate_worker);
7f3ff14b7   Jiada Wang   dmaengine: imx-sd...
1182
1183
1184
1185
1186
1187
  	/*
  	 * According to NXP R&D team a delay of one BD SDMA cost time
  	 * (maximum is 1ms) should be added after disable of the channel
  	 * bit, to ensure SDMA core has really been stopped after SDMA
  	 * clients call .device_terminate_all.
  	 */
b8603d2a5   Lucas Stach   dmaengine: imx-sd...
1188
  	usleep_range(1000, 2000);
24e30e721   Robin Gong   dmaengine: imx-sd...
1189
  	vchan_dma_desc_free_list(&sdmac->vc, &sdmac->terminated);
b8603d2a5   Lucas Stach   dmaengine: imx-sd...
1190
  }
a80f2787f   Sascha Hauer   dmaengine: imx-sd...
1191
  static int sdma_terminate_all(struct dma_chan *chan)
b8603d2a5   Lucas Stach   dmaengine: imx-sd...
1192
1193
  {
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
02939cd16   Sascha Hauer   dmaengine: imx-sd...
1194
1195
1196
  	unsigned long flags;
  
  	spin_lock_irqsave(&sdmac->vc.lock, flags);
b8603d2a5   Lucas Stach   dmaengine: imx-sd...
1197
1198
  
  	sdma_disable_channel(chan);
02939cd16   Sascha Hauer   dmaengine: imx-sd...
1199
1200
  	if (sdmac->desc) {
  		vchan_terminate_vdesc(&sdmac->desc->vd);
24e30e721   Robin Gong   dmaengine: imx-sd...
1201
1202
1203
1204
1205
1206
1207
  		/*
  		 * move out current descriptor into terminated list so that
  		 * it could be free in sdma_channel_terminate_work alone
  		 * later without potential involving next descriptor raised
  		 * up before the last descriptor terminated.
  		 */
  		vchan_get_all_descriptors(&sdmac->vc, &sdmac->terminated);
02939cd16   Sascha Hauer   dmaengine: imx-sd...
1208
  		sdmac->desc = NULL;
b8603d2a5   Lucas Stach   dmaengine: imx-sd...
1209
  		schedule_work(&sdmac->terminate_worker);
02939cd16   Sascha Hauer   dmaengine: imx-sd...
1210
1211
1212
  	}
  
  	spin_unlock_irqrestore(&sdmac->vc.lock, flags);
7f3ff14b7   Jiada Wang   dmaengine: imx-sd...
1213
1214
1215
  
  	return 0;
  }
b8603d2a5   Lucas Stach   dmaengine: imx-sd...
1216
1217
1218
1219
1220
1221
1222
1223
  static void sdma_channel_synchronize(struct dma_chan *chan)
  {
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
  
  	vchan_synchronize(&sdmac->vc);
  
  	flush_work(&sdmac->terminate_worker);
  }
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
  static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac)
  {
  	struct sdma_engine *sdma = sdmac->sdma;
  
  	int lwml = sdmac->watermark_level & SDMA_WATERMARK_LEVEL_LWML;
  	int hwml = (sdmac->watermark_level & SDMA_WATERMARK_LEVEL_HWML) >> 16;
  
  	set_bit(sdmac->event_id0 % 32, &sdmac->event_mask[1]);
  	set_bit(sdmac->event_id1 % 32, &sdmac->event_mask[0]);
  
  	if (sdmac->event_id0 > 31)
  		sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_LWE;
  
  	if (sdmac->event_id1 > 31)
  		sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_HWE;
  
  	/*
  	 * If LWML(src_maxburst) > HWML(dst_maxburst), we need
  	 * swap LWML and HWML of INFO(A.3.2.5.1), also need swap
  	 * r0(event_mask[1]) and r1(event_mask[0]).
  	 */
  	if (lwml > hwml) {
  		sdmac->watermark_level &= ~(SDMA_WATERMARK_LEVEL_LWML |
  						SDMA_WATERMARK_LEVEL_HWML);
  		sdmac->watermark_level |= hwml;
  		sdmac->watermark_level |= lwml << 16;
  		swap(sdmac->event_mask[0], sdmac->event_mask[1]);
  	}
  
  	if (sdmac->per_address2 >= sdma->spba_start_addr &&
  			sdmac->per_address2 <= sdma->spba_end_addr)
  		sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SP;
  
  	if (sdmac->per_address >= sdma->spba_start_addr &&
  			sdmac->per_address <= sdma->spba_end_addr)
  		sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_DP;
  
  	sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_CONT;
883a39c56   Shengjiu Wang   MLK-11259-1: dmae...
1262
1263
1264
1265
1266
  
  	if (sdmac->src_dualfifo)
  		sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SD;
  	if (sdmac->dst_dualfifo)
  		sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_DD;
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
1267
  }
d431de8fb   Robin Gong   dmaengine: imx-sd...
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
  static void sdma_set_watermarklevel_for_sais(struct sdma_channel *sdmac)
  {
  	sdmac->watermark_level &= ~(0xFF << SDMA_WATERMARK_LEVEL_FIFOS_OFF |
  				    SDMA_WATERMARK_LEVEL_SW_DONE |
  				    0xf << SDMA_WATERMARK_LEVEL_SW_DONE_SEL_OFF);
  
  	if (sdmac->sw_done)
  		sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SW_DONE |
  			sdmac->sw_done_sel <<
  			SDMA_WATERMARK_LEVEL_SW_DONE_SEL_OFF;
  
  	/* For fifo_num
  	 * bit 12-15 is the fifo number;
  	 * bit 16-19 is the fifo offset,
  	 * so here only need to shift left fifo_num 12 bit for watermake_level
  	 */
  	sdmac->watermark_level |= sdmac->fifo_num<<
  				SDMA_WATERMARK_LEVEL_FIFOS_OFF;
  }
7b350ab0f   Maxime Ripard   dmaengine: imx-sd...
1287
  static int sdma_config_channel(struct dma_chan *chan)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1288
  {
7b350ab0f   Maxime Ripard   dmaengine: imx-sd...
1289
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1290

7b350ab0f   Maxime Ripard   dmaengine: imx-sd...
1291
  	sdma_disable_channel(chan);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1292

0bbc14130   Richard Zhao   dma/imx-sdma: con...
1293
1294
  	sdmac->event_mask[0] = 0;
  	sdmac->event_mask[1] = 0;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1295
1296
  	sdmac->shp_addr = 0;
  	sdmac->per_addr = 0;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
  	switch (sdmac->peripheral_type) {
  	case IMX_DMATYPE_DSP:
  		sdma_config_ownership(sdmac, false, true, true);
  		break;
  	case IMX_DMATYPE_MEMORY:
  		sdma_config_ownership(sdmac, false, true, false);
  		break;
  	default:
  		sdma_config_ownership(sdmac, true, true, false);
  		break;
  	}
  
  	sdma_get_pc(sdmac, sdmac->peripheral_type);
  
  	if ((sdmac->peripheral_type != IMX_DMATYPE_MEMORY) &&
  			(sdmac->peripheral_type != IMX_DMATYPE_DSP)) {
  		/* Handle multiple event channels differently */
  		if (sdmac->event_id1) {
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
1315
1316
1317
  			if (sdmac->peripheral_type == IMX_DMATYPE_ASRC_SP ||
  			    sdmac->peripheral_type == IMX_DMATYPE_ASRC)
  				sdma_set_watermarklevel_for_p2p(sdmac);
21f5bae68   Robin Gong   dmaengine: imx-sd...
1318
1319
1320
1321
1322
1323
1324
1325
1326
  		} else {
  			/*
  			 * ERR009165 fixed from i.mx6ul, no errata need,
  			 * set bit31 to let sdma script skip the errata.
  			 */
  			if (sdmac->peripheral_type == IMX_DMATYPE_CSPI &&
  			    sdmac->direction == DMA_MEM_TO_DEV &&
  			    sdmac->sdma->drvdata->ecspi_fixed)
  				__set_bit(31, &sdmac->watermark_level);
d431de8fb   Robin Gong   dmaengine: imx-sd...
1327
1328
1329
  			else if (sdmac->peripheral_type ==
  					IMX_DMATYPE_MULTI_SAI)
  				sdma_set_watermarklevel_for_sais(sdmac);
0bbc14130   Richard Zhao   dma/imx-sdma: con...
1330
  			__set_bit(sdmac->event_id0, sdmac->event_mask);
21f5bae68   Robin Gong   dmaengine: imx-sd...
1331
  		}
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
1332

1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1333
1334
  		/* Address */
  		sdmac->shp_addr = sdmac->per_address;
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
1335
  		sdmac->per_addr = sdmac->per_address2;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1336
1337
1338
  	} else {
  		sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */
  	}
b50d66fa6   Robin Gong   dmaengine: imx-sd...
1339
  	return 0;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
  }
  
  static int sdma_set_channel_priority(struct sdma_channel *sdmac,
  		unsigned int priority)
  {
  	struct sdma_engine *sdma = sdmac->sdma;
  	int channel = sdmac->channel;
  
  	if (priority < MXC_SDMA_MIN_PRIORITY
  	    || priority > MXC_SDMA_MAX_PRIORITY) {
  		return -EINVAL;
  	}
c4b56857d   Richard Zhao   dma/imx-sdma: use...
1352
  	writel_relaxed(priority, sdma->regs + SDMA_CHNPRI_0 + 4 * channel);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1353
1354
1355
  
  	return 0;
  }
57b772b86   Robin Gong   dmaengine: imx-sd...
1356
  static int sdma_request_channel0(struct sdma_engine *sdma)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1357
  {
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1358
  	int ret = -EBUSY;
dd7efc1f2   Nicolin Chen   dmaengine: imx-sd...
1359
  	if (sdma->iram_pool)
e961d76bb   Robin Gong   MLK-25116-1: dmae...
1360
1361
1362
  		sdma->bd0 = gen_pool_dma_alloc(sdma->iram_pool,
  					sizeof(struct sdma_buffer_descriptor),
  					&sdma->bd0_phys);
dd7efc1f2   Nicolin Chen   dmaengine: imx-sd...
1363
  	else
e961d76bb   Robin Gong   MLK-25116-1: dmae...
1364
1365
1366
  		sdma->bd0 = dma_alloc_coherent(sdma->dev,
  					sizeof(struct sdma_buffer_descriptor),
  					&sdma->bd0_phys, GFP_NOWAIT);
57b772b86   Robin Gong   dmaengine: imx-sd...
1367
  	if (!sdma->bd0) {
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1368
1369
1370
  		ret = -ENOMEM;
  		goto out;
  	}
57b772b86   Robin Gong   dmaengine: imx-sd...
1371
1372
  	sdma->channel_control[0].base_bd_ptr = sdma->bd0_phys;
  	sdma->channel_control[0].current_bd_ptr = sdma->bd0_phys;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1373

57b772b86   Robin Gong   dmaengine: imx-sd...
1374
  	sdma_set_channel_priority(&sdma->channel[0], MXC_SDMA_DEFAULT_PRIORITY);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1375
1376
1377
1378
1379
  	return 0;
  out:
  
  	return ret;
  }
57b772b86   Robin Gong   dmaengine: imx-sd...
1380
1381
  
  static int sdma_alloc_bd(struct sdma_desc *desc)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1382
  {
ebb853b1b   Lucas Stach   Revert "dmaengine...
1383
  	u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
dd7efc1f2   Nicolin Chen   dmaengine: imx-sd...
1384
  	struct sdma_engine *sdma = desc->sdmac->sdma;
57b772b86   Robin Gong   dmaengine: imx-sd...
1385
  	int ret = 0;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1386

dd7efc1f2   Nicolin Chen   dmaengine: imx-sd...
1387
  	if (sdma->iram_pool)
e961d76bb   Robin Gong   MLK-25116-1: dmae...
1388
  		desc->bd = gen_pool_dma_alloc(sdma->iram_pool, bd_size,
dd7efc1f2   Nicolin Chen   dmaengine: imx-sd...
1389
1390
1391
1392
  					      &desc->bd_phys);
  	else
  		desc->bd = dma_alloc_coherent(sdma->dev, bd_size,
  					      &desc->bd_phys, GFP_NOWAIT);
57b772b86   Robin Gong   dmaengine: imx-sd...
1393
1394
1395
1396
1397
1398
1399
  	if (!desc->bd) {
  		ret = -ENOMEM;
  		goto out;
  	}
  out:
  	return ret;
  }
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1400

57b772b86   Robin Gong   dmaengine: imx-sd...
1401
1402
  static void sdma_free_bd(struct sdma_desc *desc)
  {
ebb853b1b   Lucas Stach   Revert "dmaengine...
1403
  	u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
dd7efc1f2   Nicolin Chen   dmaengine: imx-sd...
1404
  	struct sdma_engine *sdma = desc->sdmac->sdma;
ebb853b1b   Lucas Stach   Revert "dmaengine...
1405

dd7efc1f2   Nicolin Chen   dmaengine: imx-sd...
1406
1407
  	if (sdma->iram_pool)
  		gen_pool_free(sdma->iram_pool, (unsigned long)desc->bd,
e961d76bb   Robin Gong   MLK-25116-1: dmae...
1408
  			      bd_size);
dd7efc1f2   Nicolin Chen   dmaengine: imx-sd...
1409
1410
1411
  	else
  		dma_free_coherent(desc->sdmac->sdma->dev, bd_size, desc->bd,
  				  desc->bd_phys);
57b772b86   Robin Gong   dmaengine: imx-sd...
1412
  }
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1413

57b772b86   Robin Gong   dmaengine: imx-sd...
1414
1415
1416
1417
1418
1419
  static void sdma_desc_free(struct virt_dma_desc *vd)
  {
  	struct sdma_desc *desc = container_of(vd, struct sdma_desc, vd);
  
  	sdma_free_bd(desc);
  	kfree(desc);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1420
  }
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
1421
  static int sdma_runtime_suspend(struct device *dev)
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
1422
  {
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
1423
1424
1425
1426
1427
1428
1429
1430
  	struct platform_device *pdev = to_platform_device(dev);
  	struct sdma_engine *sdma = platform_get_drvdata(pdev);
  
  	sdma->fw_loaded = false;
  	sdma->is_on = false;
  
  	clk_disable(sdma->clk_ipg);
  	clk_disable(sdma->clk_ahb);
5763d3189   Robin Gong   MLK-23869-3: dmae...
1431
1432
1433
  	/* free channel0 bd */
  	if (sdma->iram_pool)
  		gen_pool_free(sdma->iram_pool, (unsigned long)sdma->bd0,
e961d76bb   Robin Gong   MLK-25116-1: dmae...
1434
  			      sizeof(struct sdma_buffer_descriptor));
5763d3189   Robin Gong   MLK-23869-3: dmae...
1435
  	else
e961d76bb   Robin Gong   MLK-25116-1: dmae...
1436
1437
1438
  		dma_free_coherent(sdma->dev,
  				  sizeof(struct sdma_buffer_descriptor),
  				  sdma->bd0, sdma->bd0_phys);
5763d3189   Robin Gong   MLK-23869-3: dmae...
1439

0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
1440
1441
1442
1443
1444
1445
1446
  	return 0;
  }
  
  static int sdma_runtime_resume(struct device *dev)
  {
  	struct platform_device *pdev = to_platform_device(dev);
  	struct sdma_engine *sdma = platform_get_drvdata(pdev);
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
1447
  	int i, ret;
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
  
  	ret = clk_enable(sdma->clk_ipg);
  	if (ret)
  		return ret;
  	ret = clk_enable(sdma->clk_ahb);
  	if (ret)
  		goto disable_clk_ipg;
  
  	/* Be sure SDMA has not started yet */
  	writel_relaxed(0, sdma->regs + SDMA_H_C0PTR);
  
  	/* disable all channels */
  	for (i = 0; i < sdma->drvdata->num_events; i++)
  		writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i));
  
  	/* All channels have priority 0 */
  	for (i = 0; i < MAX_DMA_CHANNELS; i++)
  		writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
  
  	ret = sdma_request_channel0(sdma);
  	if (ret)
  		return ret;
  
  	sdma_config_ownership(&sdma->channel[0], false, true, false);
  
  	/* Set Command Channel (Channel Zero) */
  	writel_relaxed(0x4050, sdma->regs + SDMA_CHN0ADDR);
  
  	/* Set bits of CONFIG register but with static context switching */
  	if (sdma->clk_ratio)
  		writel_relaxed(SDMA_H_CONFIG_ACR, sdma->regs + SDMA_H_CONFIG);
  	else
  		writel_relaxed(0, sdma->regs + SDMA_H_CONFIG);
  
  	writel_relaxed(sdma->ccb_phys, sdma->regs + SDMA_H_C0PTR);
  
  	/* Initializes channel's priorities */
  	sdma_set_channel_priority(&sdma->channel[0], 7);
5763d3189   Robin Gong   MLK-23869-3: dmae...
1486
1487
1488
1489
  	if (sdma->drvdata->pm_runtime)
  		ret = sdma_get_firmware_wait(sdma, sdma->fw_name);
  	else
  		ret = sdma_get_firmware(sdma, sdma->fw_name);
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
1490
1491
1492
  	if (ret)
  		dev_warn(sdma->dev, "failed to get firmware.
  ");
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
1493
  	sdma->is_on = true;
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
1494
1495
1496
1497
1498
1499
1500
1501
1502
  	return 0;
  
  disable_clk_ipg:
  	clk_disable(sdma->clk_ipg);
  	dev_err(sdma->dev, "initialisation failed with %d
  ", ret);
  
  	return ret;
  }
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1503
1504
1505
1506
  static int sdma_alloc_chan_resources(struct dma_chan *chan)
  {
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
  	struct imx_dma_data *data = chan->private;
0f06c0275   Robin Gong   dmaengine: imx-sd...
1507
  	struct imx_dma_data mem_data;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1508
  	int prio, ret;
0f06c0275   Robin Gong   dmaengine: imx-sd...
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
  	/*
  	 * MEMCPY may never setup chan->private by filter function such as
  	 * dmatest, thus create 'struct imx_dma_data mem_data' for this case.
  	 * Please note in any other slave case, you have to setup chan->private
  	 * with 'struct imx_dma_data' in your own filter function if you want to
  	 * request dma channel by dma_request_channel() rather than
  	 * dma_request_slave_channel(). Othwise, 'MEMCPY in case?' will appear
  	 * to warn you to correct your filter function.
  	 */
  	if (!data) {
  		dev_dbg(sdmac->sdma->dev, "MEMCPY in case?
  ");
  		mem_data.priority = 2;
  		mem_data.peripheral_type = IMX_DMATYPE_MEMORY;
  		mem_data.dma_request = 0;
  		mem_data.dma_request2 = 0;
  		data = &mem_data;
  
  		sdma_get_pc(sdmac, IMX_DMATYPE_MEMORY);
  	}
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
  
  	switch (data->priority) {
  	case DMA_PRIO_HIGH:
  		prio = 3;
  		break;
  	case DMA_PRIO_MEDIUM:
  		prio = 2;
  		break;
  	case DMA_PRIO_LOW:
  	default:
  		prio = 1;
  		break;
  	}
  
  	sdmac->peripheral_type = data->peripheral_type;
  	sdmac->event_id0 = data->dma_request;
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
1545
  	sdmac->event_id1 = data->dma_request2;
883a39c56   Shengjiu Wang   MLK-11259-1: dmae...
1546
1547
  	sdmac->src_dualfifo = data->src_dualfifo;
  	sdmac->dst_dualfifo = data->dst_dualfifo;
d431de8fb   Robin Gong   dmaengine: imx-sd...
1548
1549
1550
1551
1552
  	/* Get software done selector if sw_done enabled */
  	if (data->done_sel & BIT(31)) {
  		sdmac->sw_done = true;
  		sdmac->sw_done_sel = (data->done_sel >> 8) & 0xff;
  	}
c2c744d3a   Richard Zhao   dma/imx-sdma: mov...
1553

0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
1554
  	pm_runtime_get_sync(sdmac->sdma->dev);
c2c744d3a   Richard Zhao   dma/imx-sdma: mov...
1555

3bb5e7caf   Richard Zhao   dma/imx-sdma: cal...
1556
  	ret = sdma_set_channel_priority(sdmac, prio);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1557
  	if (ret)
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
1558
  		return ret;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1559

1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1560
1561
1562
1563
1564
1565
1566
  	return 0;
  }
  
  static void sdma_free_chan_resources(struct dma_chan *chan)
  {
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
  	struct sdma_engine *sdma = sdmac->sdma;
a80f2787f   Sascha Hauer   dmaengine: imx-sd...
1567
  	sdma_terminate_all(chan);
b8603d2a5   Lucas Stach   dmaengine: imx-sd...
1568
1569
  
  	sdma_channel_synchronize(chan);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1570

2f57b8d57   Fabio Estevam   dmaengine: imx-sd...
1571
  	sdma_event_disable(sdmac, sdmac->event_id0);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1572
1573
1574
1575
1576
1577
1578
  	if (sdmac->event_id1)
  		sdma_event_disable(sdmac, sdmac->event_id1);
  
  	sdmac->event_id0 = 0;
  	sdmac->event_id1 = 0;
  
  	sdma_set_channel_priority(sdmac, 0);
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
1579
  	pm_runtime_put_sync(sdma->dev);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1580
  }
21420841a   Robin Gong   dmaengine: imx-sd...
1581
1582
1583
1584
  static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
  				enum dma_transfer_direction direction, u32 bds)
  {
  	struct sdma_desc *desc;
57d1ed37c   Robin Gong   dmaengine: imx-sd...
1585
1586
1587
1588
1589
  	if (!sdmac->sdma->fw_loaded && sdmac->is_ram_script) {
  		dev_err(sdmac->sdma->dev, "sdma firmware not ready!
  ");
  		goto err_out;
  	}
21420841a   Robin Gong   dmaengine: imx-sd...
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
  	desc = kzalloc((sizeof(*desc)), GFP_NOWAIT);
  	if (!desc)
  		goto err_out;
  
  	sdmac->status = DMA_IN_PROGRESS;
  	sdmac->direction = direction;
  	sdmac->flags = 0;
  
  	desc->chn_count = 0;
  	desc->chn_real_count = 0;
  	desc->buf_tail = 0;
  	desc->buf_ptail = 0;
  	desc->sdmac = sdmac;
  	desc->num_bd = bds;
6a56d5a92   Shengjiu Wang   dma: imx-sdma: Fi...
1604
  	if (bds && sdma_alloc_bd(desc))
21420841a   Robin Gong   dmaengine: imx-sd...
1605
  		goto err_desc_out;
0f06c0275   Robin Gong   dmaengine: imx-sd...
1606
1607
1608
  	/* No slave_config called in MEMCPY case, so do here */
  	if (direction == DMA_MEM_TO_MEM)
  		sdma_config_ownership(sdmac, false, true, false);
21420841a   Robin Gong   dmaengine: imx-sd...
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
  	if (sdma_load_context(sdmac))
  		goto err_desc_out;
  
  	return desc;
  
  err_desc_out:
  	kfree(desc);
  err_out:
  	return NULL;
  }
0f06c0275   Robin Gong   dmaengine: imx-sd...
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
  static struct dma_async_tx_descriptor *sdma_prep_memcpy(
  		struct dma_chan *chan, dma_addr_t dma_dst,
  		dma_addr_t dma_src, size_t len, unsigned long flags)
  {
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
  	struct sdma_engine *sdma = sdmac->sdma;
  	int channel = sdmac->channel;
  	size_t count;
  	int i = 0, param;
  	struct sdma_buffer_descriptor *bd;
  	struct sdma_desc *desc;
  
  	if (!chan || !len)
  		return NULL;
  
  	dev_dbg(sdma->dev, "memcpy: %pad->%pad, len=%zu, channel=%d.
  ",
  		&dma_src, &dma_dst, len, channel);
  
  	desc = sdma_transfer_init(sdmac, DMA_MEM_TO_MEM,
  					len / SDMA_BD_MAX_CNT + 1);
  	if (!desc)
  		return NULL;
  
  	do {
  		count = min_t(size_t, len, SDMA_BD_MAX_CNT);
  		bd = &desc->bd[i];
  		bd->buffer_addr = dma_src;
  		bd->ext_buffer_addr = dma_dst;
  		bd->mode.count = count;
  		desc->chn_count += count;
  		bd->mode.command = 0;
  
  		dma_src += count;
  		dma_dst += count;
  		len -= count;
  		i++;
  
  		param = BD_DONE | BD_EXTD | BD_CONT;
  		/* last bd */
  		if (!len) {
  			param |= BD_INTR;
  			param |= BD_LAST;
  			param &= ~BD_CONT;
  		}
  
  		dev_dbg(sdma->dev, "entry %d: count: %zd dma: 0x%x %s%s
  ",
  				i, count, bd->buffer_addr,
  				param & BD_WRAP ? "wrap" : "",
  				param & BD_INTR ? " intr" : "");
  
  		bd->mode.status = param;
  	} while (len);
  
  	return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
  }
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1676
1677
  static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
  		struct dma_chan *chan, struct scatterlist *sgl,
db8196df4   Vinod Koul   dmaengine: move d...
1678
  		unsigned int sg_len, enum dma_transfer_direction direction,
185ecb5f4   Alexandre Bounine   dmaengine: add co...
1679
  		unsigned long flags, void *context)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1680
1681
1682
  {
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
  	struct sdma_engine *sdma = sdmac->sdma;
ad78b000f   Vinod Koul   dmaengine: imx-sd...
1683
  	int i, count;
23889c635   Sascha Hauer   dmaengine i.MX SD...
1684
  	int channel = sdmac->channel;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1685
  	struct scatterlist *sg;
57b772b86   Robin Gong   dmaengine: imx-sd...
1686
  	struct sdma_desc *desc;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1687

107d06441   Vinod Koul   dmaengine: imx-sd...
1688
  	sdma_config_write(chan, &sdmac->slave_config, direction);
21420841a   Robin Gong   dmaengine: imx-sd...
1689
  	desc = sdma_transfer_init(sdmac, direction, sg_len);
57b772b86   Robin Gong   dmaengine: imx-sd...
1690
1691
  	if (!desc)
  		goto err_out;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1692
1693
1694
  	dev_dbg(sdma->dev, "setting up %d entries for channel %d.
  ",
  			sg_len, channel);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1695
  	for_each_sg(sgl, sg, sg_len, i) {
76c33d270   Sascha Hauer   dmaengine: imx-sd...
1696
  		struct sdma_buffer_descriptor *bd = &desc->bd[i];
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1697
  		int param;
d2f5c276e   Anatolij Gustschin   dmaengine: imx-sd...
1698
  		bd->buffer_addr = sg->dma_address;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1699

fdaf9c4b2   Lars-Peter Clausen   dmaengine: Use dm...
1700
  		count = sg_dma_len(sg);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1701

4a6b2e8a9   Robin Gong   dmaengine: imx-sd...
1702
  		if (count > SDMA_BD_MAX_CNT) {
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1703
1704
  			dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d
  ",
4a6b2e8a9   Robin Gong   dmaengine: imx-sd...
1705
  					channel, count, SDMA_BD_MAX_CNT);
57b772b86   Robin Gong   dmaengine: imx-sd...
1706
  			goto err_bd_out;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1707
1708
1709
  		}
  
  		bd->mode.count = count;
76c33d270   Sascha Hauer   dmaengine: imx-sd...
1710
  		desc->chn_count += count;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1711

ad78b000f   Vinod Koul   dmaengine: imx-sd...
1712
  		if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES)
57b772b86   Robin Gong   dmaengine: imx-sd...
1713
  			goto err_bd_out;
1fa81c270   Sascha Hauer   dmaengine i.MX sd...
1714
1715
1716
  
  		switch (sdmac->word_size) {
  		case DMA_SLAVE_BUSWIDTH_4_BYTES:
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1717
  			bd->mode.command = 0;
1fa81c270   Sascha Hauer   dmaengine i.MX sd...
1718
  			if (count & 3 || sg->dma_address & 3)
57b772b86   Robin Gong   dmaengine: imx-sd...
1719
  				goto err_bd_out;
1fa81c270   Sascha Hauer   dmaengine i.MX sd...
1720
  			break;
b2b37f7f5   Shengjiu Wang   MLK-22239-1: dmae...
1721
1722
1723
  		case DMA_SLAVE_BUSWIDTH_3_BYTES:
  			bd->mode.command = 3;
  			break;
1fa81c270   Sascha Hauer   dmaengine i.MX sd...
1724
1725
1726
  		case DMA_SLAVE_BUSWIDTH_2_BYTES:
  			bd->mode.command = 2;
  			if (count & 1 || sg->dma_address & 1)
57b772b86   Robin Gong   dmaengine: imx-sd...
1727
  				goto err_bd_out;
1fa81c270   Sascha Hauer   dmaengine i.MX sd...
1728
1729
1730
1731
1732
  			break;
  		case DMA_SLAVE_BUSWIDTH_1_BYTE:
  			bd->mode.command = 1;
  			break;
  		default:
57b772b86   Robin Gong   dmaengine: imx-sd...
1733
  			goto err_bd_out;
1fa81c270   Sascha Hauer   dmaengine i.MX sd...
1734
  		}
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1735
1736
  
  		param = BD_DONE | BD_EXTD | BD_CONT;
341b9419a   Shawn Guo   dmaengine: imx-sd...
1737
  		if (i + 1 == sg_len) {
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1738
  			param |= BD_INTR;
341b9419a   Shawn Guo   dmaengine: imx-sd...
1739
1740
  			param |= BD_LAST;
  			param &= ~BD_CONT;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1741
  		}
c3cc74b24   Olof Johansson   dma: imx-sdma: Fi...
1742
1743
1744
  		dev_dbg(sdma->dev, "entry %d: count: %d dma: %#llx %s%s
  ",
  				i, count, (u64)sg->dma_address,
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1745
1746
1747
1748
1749
  				param & BD_WRAP ? "wrap" : "",
  				param & BD_INTR ? " intr" : "");
  
  		bd->mode.status = param;
  	}
57b772b86   Robin Gong   dmaengine: imx-sd...
1750
1751
1752
1753
  	return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
  err_bd_out:
  	sdma_free_bd(desc);
  	kfree(desc);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1754
  err_out:
4b2ce9ddb   Shawn Guo   dmaengine: imx-sd...
1755
  	sdmac->status = DMA_ERROR;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1756
1757
1758
1759
1760
  	return NULL;
  }
  
  static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
  		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
185ecb5f4   Alexandre Bounine   dmaengine: add co...
1761
  		size_t period_len, enum dma_transfer_direction direction,
31c1e5a13   Laurent Pinchart   dmaengine: Remove...
1762
  		unsigned long flags)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1763
1764
1765
  {
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
  	struct sdma_engine *sdma = sdmac->sdma;
3ec0b6819   Shengjiu Wang   dmaengine: imx-sd...
1766
  	int num_periods = 0;
23889c635   Sascha Hauer   dmaengine i.MX SD...
1767
  	int channel = sdmac->channel;
21420841a   Robin Gong   dmaengine: imx-sd...
1768
  	int i = 0, buf = 0;
57b772b86   Robin Gong   dmaengine: imx-sd...
1769
  	struct sdma_desc *desc;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1770
1771
1772
  
  	dev_dbg(sdma->dev, "%s channel: %d
  ", __func__, channel);
3ec0b6819   Shengjiu Wang   dmaengine: imx-sd...
1773
1774
  	if (sdmac->peripheral_type != IMX_DMATYPE_HDMI)
  		num_periods = buf_len / period_len;
107d06441   Vinod Koul   dmaengine: imx-sd...
1775
  	sdma_config_write(chan, &sdmac->slave_config, direction);
21420841a   Robin Gong   dmaengine: imx-sd...
1776
  	desc = sdma_transfer_init(sdmac, direction, num_periods);
57b772b86   Robin Gong   dmaengine: imx-sd...
1777
1778
  	if (!desc)
  		goto err_out;
76c33d270   Sascha Hauer   dmaengine: imx-sd...
1779
  	desc->period_len = period_len;
8e2e27c74   Richard Zhao   dma: imx-sdma: bu...
1780

1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1781
  	sdmac->flags |= IMX_DMA_SG_LOOP;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1782

4a6b2e8a9   Robin Gong   dmaengine: imx-sd...
1783
  	if (period_len > SDMA_BD_MAX_CNT) {
ba6ab3b35   Arvind Yadav   dmaengine: imx-sd...
1784
1785
  		dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %zu > %d
  ",
4a6b2e8a9   Robin Gong   dmaengine: imx-sd...
1786
  				channel, period_len, SDMA_BD_MAX_CNT);
57b772b86   Robin Gong   dmaengine: imx-sd...
1787
  		goto err_bd_out;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1788
  	}
3ec0b6819   Shengjiu Wang   dmaengine: imx-sd...
1789
1790
  	if (sdmac->peripheral_type == IMX_DMATYPE_HDMI)
  		return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1791
  	while (buf < buf_len) {
76c33d270   Sascha Hauer   dmaengine: imx-sd...
1792
  		struct sdma_buffer_descriptor *bd = &desc->bd[i];
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1793
1794
1795
1796
1797
1798
1799
  		int param;
  
  		bd->buffer_addr = dma_addr;
  
  		bd->mode.count = period_len;
  
  		if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES)
57b772b86   Robin Gong   dmaengine: imx-sd...
1800
  			goto err_bd_out;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1801
1802
1803
1804
1805
1806
1807
1808
  		if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES)
  			bd->mode.command = 0;
  		else
  			bd->mode.command = sdmac->word_size;
  
  		param = BD_DONE | BD_EXTD | BD_CONT | BD_INTR;
  		if (i + 1 == num_periods)
  			param |= BD_WRAP;
ba6ab3b35   Arvind Yadav   dmaengine: imx-sd...
1809
1810
  		dev_dbg(sdma->dev, "entry %d: count: %zu dma: %#llx %s%s
  ",
c3cc74b24   Olof Johansson   dma: imx-sdma: Fi...
1811
  				i, period_len, (u64)dma_addr,
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
  				param & BD_WRAP ? "wrap" : "",
  				param & BD_INTR ? " intr" : "");
  
  		bd->mode.status = param;
  
  		dma_addr += period_len;
  		buf += period_len;
  
  		i++;
  	}
57b772b86   Robin Gong   dmaengine: imx-sd...
1822
1823
1824
1825
  	return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
  err_bd_out:
  	sdma_free_bd(desc);
  	kfree(desc);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1826
1827
1828
1829
  err_out:
  	sdmac->status = DMA_ERROR;
  	return NULL;
  }
107d06441   Vinod Koul   dmaengine: imx-sd...
1830
1831
1832
  static int sdma_config_write(struct dma_chan *chan,
  		       struct dma_slave_config *dmaengine_cfg,
  		       enum dma_transfer_direction direction)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1833
1834
  {
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1835

d431de8fb   Robin Gong   dmaengine: imx-sd...
1836
  	sdmac->watermark_level = 0;
b32477240   Robin Gong   LF-246: dmaengine...
1837
  	sdmac->is_ram_script = false;
d431de8fb   Robin Gong   dmaengine: imx-sd...
1838

107d06441   Vinod Koul   dmaengine: imx-sd...
1839
  	if (direction == DMA_DEV_TO_MEM) {
7b350ab0f   Maxime Ripard   dmaengine: imx-sd...
1840
1841
1842
1843
  		sdmac->per_address = dmaengine_cfg->src_addr;
  		sdmac->watermark_level = dmaengine_cfg->src_maxburst *
  			dmaengine_cfg->src_addr_width;
  		sdmac->word_size = dmaengine_cfg->src_addr_width;
d431de8fb   Robin Gong   dmaengine: imx-sd...
1844
  		sdmac->fifo_num =  dmaengine_cfg->src_fifo_num;
107d06441   Vinod Koul   dmaengine: imx-sd...
1845
  	} else if (direction == DMA_DEV_TO_DEV) {
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
1846
1847
1848
1849
1850
1851
1852
  		sdmac->per_address2 = dmaengine_cfg->src_addr;
  		sdmac->per_address = dmaengine_cfg->dst_addr;
  		sdmac->watermark_level = dmaengine_cfg->src_maxburst &
  			SDMA_WATERMARK_LEVEL_LWML;
  		sdmac->watermark_level |= (dmaengine_cfg->dst_maxburst << 16) &
  			SDMA_WATERMARK_LEVEL_HWML;
  		sdmac->word_size = dmaengine_cfg->dst_addr_width;
3ec0b6819   Shengjiu Wang   dmaengine: imx-sd...
1853
1854
1855
1856
  	} else if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) {
  			sdmac->per_address = dmaengine_cfg->dst_addr;
  			sdmac->per_address2 = dmaengine_cfg->src_addr;
  			sdmac->watermark_level = 0;
7b350ab0f   Maxime Ripard   dmaengine: imx-sd...
1857
1858
1859
1860
1861
  	} else {
  		sdmac->per_address = dmaengine_cfg->dst_addr;
  		sdmac->watermark_level = dmaengine_cfg->dst_maxburst *
  			dmaengine_cfg->dst_addr_width;
  		sdmac->word_size = dmaengine_cfg->dst_addr_width;
d431de8fb   Robin Gong   dmaengine: imx-sd...
1862
  		sdmac->fifo_num =  dmaengine_cfg->dst_fifo_num;
7b350ab0f   Maxime Ripard   dmaengine: imx-sd...
1863
  	}
107d06441   Vinod Koul   dmaengine: imx-sd...
1864
  	sdmac->direction = direction;
7b350ab0f   Maxime Ripard   dmaengine: imx-sd...
1865
  	return sdma_config_channel(chan);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1866
  }
107d06441   Vinod Koul   dmaengine: imx-sd...
1867
1868
1869
1870
1871
1872
1873
1874
  static int sdma_config(struct dma_chan *chan,
  		       struct dma_slave_config *dmaengine_cfg)
  {
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
  
  	memcpy(&sdmac->slave_config, dmaengine_cfg, sizeof(*dmaengine_cfg));
  
  	/* Set ENBLn earlier to make sure dma request triggered after that */
2f57b8d57   Fabio Estevam   dmaengine: imx-sd...
1875
1876
1877
  	if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events)
  		return -EINVAL;
  	sdma_event_enable(sdmac, sdmac->event_id0);
107d06441   Vinod Koul   dmaengine: imx-sd...
1878
1879
1880
1881
1882
1883
1884
1885
1886
  
  	if (sdmac->event_id1) {
  		if (sdmac->event_id1 >= sdmac->sdma->drvdata->num_events)
  			return -EINVAL;
  		sdma_event_enable(sdmac, sdmac->event_id1);
  	}
  
  	return 0;
  }
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1887
  static enum dma_status sdma_tx_status(struct dma_chan *chan,
e8e3a7900   Andy Shevchenko   imx-sdma: remove ...
1888
1889
  				      dma_cookie_t cookie,
  				      struct dma_tx_state *txstate)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1890
1891
  {
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
a1ff6a07f   Sascha Hauer   dmaengine: imx-sd...
1892
  	struct sdma_desc *desc = NULL;
d1a792f3b   Russell King - ARM Linux   Update imx-sdma c...
1893
  	u32 residue;
57b772b86   Robin Gong   dmaengine: imx-sd...
1894
1895
1896
  	struct virt_dma_desc *vd;
  	enum dma_status ret;
  	unsigned long flags;
d1a792f3b   Russell King - ARM Linux   Update imx-sdma c...
1897

57b772b86   Robin Gong   dmaengine: imx-sd...
1898
1899
1900
1901
1902
  	ret = dma_cookie_status(chan, cookie, txstate);
  	if (ret == DMA_COMPLETE || !txstate)
  		return ret;
  
  	spin_lock_irqsave(&sdmac->vc.lock, flags);
a1ff6a07f   Sascha Hauer   dmaengine: imx-sd...
1903

57b772b86   Robin Gong   dmaengine: imx-sd...
1904
  	vd = vchan_find_desc(&sdmac->vc, cookie);
a1ff6a07f   Sascha Hauer   dmaengine: imx-sd...
1905
  	if (vd)
57b772b86   Robin Gong   dmaengine: imx-sd...
1906
  		desc = to_sdma_desc(&vd->tx);
a1ff6a07f   Sascha Hauer   dmaengine: imx-sd...
1907
1908
1909
1910
  	else if (sdmac->desc && sdmac->desc->vd.tx.cookie == cookie)
  		desc = sdmac->desc;
  
  	if (desc) {
57b772b86   Robin Gong   dmaengine: imx-sd...
1911
1912
1913
1914
1915
  		if (sdmac->flags & IMX_DMA_SG_LOOP)
  			residue = (desc->num_bd - desc->buf_ptail) *
  				desc->period_len - desc->chn_real_count;
  		else
  			residue = desc->chn_count - desc->chn_real_count;
57b772b86   Robin Gong   dmaengine: imx-sd...
1916
1917
1918
  	} else {
  		residue = 0;
  	}
a1ff6a07f   Sascha Hauer   dmaengine: imx-sd...
1919

57b772b86   Robin Gong   dmaengine: imx-sd...
1920
  	spin_unlock_irqrestore(&sdmac->vc.lock, flags);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1921

e8e3a7900   Andy Shevchenko   imx-sdma: remove ...
1922
  	dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
d1a792f3b   Russell King - ARM Linux   Update imx-sdma c...
1923
  			 residue);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1924

8a9659114   Shawn Guo   dmaengine: imx-sd...
1925
  	return sdmac->status;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1926
1927
1928
1929
  }
  
  static void sdma_issue_pending(struct dma_chan *chan)
  {
2b4f130e0   Sascha Hauer   dma: imx-sdma: st...
1930
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
57b772b86   Robin Gong   dmaengine: imx-sd...
1931
  	unsigned long flags;
2b4f130e0   Sascha Hauer   dma: imx-sdma: st...
1932

57b772b86   Robin Gong   dmaengine: imx-sd...
1933
1934
1935
1936
  	spin_lock_irqsave(&sdmac->vc.lock, flags);
  	if (vchan_issue_pending(&sdmac->vc) && !sdmac->desc)
  		sdma_start_desc(sdmac);
  	spin_unlock_irqrestore(&sdmac->vc.lock, flags);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
1937
  }
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
1938
  #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1	34
cd72b8462   Nicolin Chen   dma: imx-sdma: Ad...
1939
  #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2	38
7803348e8   Fugang Duan   MLK-22972 dmaengi...
1940
1941
  #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3	45
  #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4	46
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
1942
1943
1944
1945
1946
1947
1948
  
  static void sdma_add_scripts(struct sdma_engine *sdma,
  		const struct sdma_script_start_addrs *addr)
  {
  	s32 *addr_arr = (u32 *)addr;
  	s32 *saddr_arr = (u32 *)sdma->script_addrs;
  	int i;
70dabaede   Nicolin Chen   dma: imx-sdma: As...
1949
1950
1951
  	/* use the default firmware in ROM if missing external firmware */
  	if (!sdma->script_number)
  		sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1;
bd73dfabd   Robin Gong   dmaengine: imx-sd...
1952
1953
1954
1955
1956
1957
1958
1959
  	if (sdma->script_number > sizeof(struct sdma_script_start_addrs)
  				  / sizeof(s32)) {
  		dev_err(sdma->dev,
  			"SDMA script number %d not match with firmware.
  ",
  			sdma->script_number);
  		return;
  	}
cd72b8462   Nicolin Chen   dma: imx-sdma: Ad...
1960
  	for (i = 0; i < sdma->script_number; i++)
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
1961
1962
1963
  		if (addr_arr[i] > 0)
  			saddr_arr[i] = addr_arr[i];
  }
7b4b88e06   Sascha Hauer   dmaengine i.MX SD...
1964
  static void sdma_load_firmware(const struct firmware *fw, void *context)
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
1965
  {
7b4b88e06   Sascha Hauer   dmaengine i.MX SD...
1966
  	struct sdma_engine *sdma = context;
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
1967
  	const struct sdma_firmware_header *header;
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
1968
1969
  	const struct sdma_script_start_addrs *addr;
  	unsigned short *ram_code;
7b4b88e06   Sascha Hauer   dmaengine i.MX SD...
1970
  	if (!fw) {
fec4cb374   Robin Gong   LF-301: dmaengine...
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
  		/* Load firmware once more time if timeout */
  		if (sdma->fw_fail)
  			dev_info(sdma->dev, "external firmware not found, using ROM firmware
  ");
  		else {
  			request_firmware_nowait(THIS_MODULE,
  					FW_ACTION_HOTPLUG, sdma->fw_name,
  					sdma->dev, GFP_KERNEL, sdma,
  					sdma_load_firmware);
  			sdma->fw_fail++;
  		}
7b4b88e06   Sascha Hauer   dmaengine i.MX SD...
1982
1983
  		return;
  	}
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
1984

57d1ed37c   Robin Gong   dmaengine: imx-sd...
1985
  	if (fw->size < sizeof(*header) || sdma->fw_loaded)
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
1986
1987
1988
1989
1990
1991
1992
1993
  		goto err_firmware;
  
  	header = (struct sdma_firmware_header *)fw->data;
  
  	if (header->magic != SDMA_FIRMWARE_MAGIC)
  		goto err_firmware;
  	if (header->ram_code_start + header->ram_code_size > fw->size)
  		goto err_firmware;
cd72b8462   Nicolin Chen   dma: imx-sdma: Ad...
1994
  	switch (header->version_major) {
681d15ecd   Asaf Vertz   dmaengine: imx-sd...
1995
1996
1997
1998
1999
2000
  	case 1:
  		sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1;
  		break;
  	case 2:
  		sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2;
  		break;
a572460be   Fabio Estevam   dmaengine: imx-sd...
2001
2002
2003
  	case 3:
  		sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3;
  		break;
b7d2648ac   Fabio Estevam   dmaengine: imx-sd...
2004
2005
2006
  	case 4:
  		sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4;
  		break;
681d15ecd   Asaf Vertz   dmaengine: imx-sd...
2007
2008
2009
2010
  	default:
  		dev_err(sdma->dev, "unknown firmware version
  ");
  		goto err_firmware;
cd72b8462   Nicolin Chen   dma: imx-sdma: Ad...
2011
  	}
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
2012
2013
2014
  
  	addr = (void *)header + header->script_addrs_start;
  	ram_code = (void *)header + header->ram_code_start;
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2015
  	sdma->ram_code_start = header->ram_code_start;
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
2016

5b28aa319   Sascha Hauer   dmaengine i.MX SD...
2017
2018
2019
  	/* download the RAM image for SDMA */
  	sdma_load_script(sdma, ram_code,
  			header->ram_code_size,
6866fd3b7   Sascha Hauer   dmaengine i.MX SD...
2020
  			addr->ram_code_start_addr);
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
2021
2022
  
  	sdma_add_scripts(sdma, addr);
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2023
  	sdma->fw_loaded = true;
5763d3189   Robin Gong   MLK-23869-3: dmae...
2024
2025
  	dev_info_once(sdma->dev, "loaded firmware %d.%d
  ",
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
2026
2027
2028
2029
2030
  			header->version_major,
  			header->version_minor);
  
  err_firmware:
  	release_firmware(fw);
7b4b88e06   Sascha Hauer   dmaengine i.MX SD...
2031
  }
d078cd1b4   Zidan Wang   dmaengine: imx-sd...
2032
  #define EVENT_REMAP_CELLS 3
29f493daf   Jason Liu   dmaengine: imx-sd...
2033
  static int sdma_event_remap(struct sdma_engine *sdma)
d078cd1b4   Zidan Wang   dmaengine: imx-sd...
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
  {
  	struct device_node *np = sdma->dev->of_node;
  	struct device_node *gpr_np = of_parse_phandle(np, "gpr", 0);
  	struct property *event_remap;
  	struct regmap *gpr;
  	char propname[] = "fsl,sdma-event-remap";
  	u32 reg, val, shift, num_map, i;
  	int ret = 0;
  
  	if (IS_ERR(np) || IS_ERR(gpr_np))
  		goto out;
  
  	event_remap = of_find_property(np, propname, NULL);
  	num_map = event_remap ? (event_remap->length / sizeof(u32)) : 0;
  	if (!num_map) {
ce078af76   Fabio Estevam   dmaengine: imx-sd...
2049
2050
  		dev_dbg(sdma->dev, "no event needs to be remapped
  ");
d078cd1b4   Zidan Wang   dmaengine: imx-sd...
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
  		goto out;
  	} else if (num_map % EVENT_REMAP_CELLS) {
  		dev_err(sdma->dev, "the property %s must modulo %d
  ",
  				propname, EVENT_REMAP_CELLS);
  		ret = -EINVAL;
  		goto out;
  	}
  
  	gpr = syscon_node_to_regmap(gpr_np);
  	if (IS_ERR(gpr)) {
  		dev_err(sdma->dev, "failed to get gpr regmap
  ");
  		ret = PTR_ERR(gpr);
  		goto out;
  	}
  
  	for (i = 0; i < num_map; i += EVENT_REMAP_CELLS) {
  		ret = of_property_read_u32_index(np, propname, i, &reg);
  		if (ret) {
  			dev_err(sdma->dev, "failed to read property %s index %d
  ",
  					propname, i);
  			goto out;
  		}
  
  		ret = of_property_read_u32_index(np, propname, i + 1, &shift);
  		if (ret) {
  			dev_err(sdma->dev, "failed to read property %s index %d
  ",
  					propname, i + 1);
  			goto out;
  		}
  
  		ret = of_property_read_u32_index(np, propname, i + 2, &val);
  		if (ret) {
  			dev_err(sdma->dev, "failed to read property %s index %d
  ",
  					propname, i + 2);
  			goto out;
  		}
  
  		regmap_update_bits(gpr, reg, BIT(shift), val << shift);
  	}
  
  out:
  	if (!IS_ERR(gpr_np))
  		of_node_put(gpr_np);
  
  	return ret;
  }
fe6cf2893   Arnd Bergmann   dma: imx-sdma: fi...
2102
  static int sdma_get_firmware(struct sdma_engine *sdma,
7b4b88e06   Sascha Hauer   dmaengine i.MX SD...
2103
2104
2105
2106
2107
2108
2109
  		const char *fw_name)
  {
  	int ret;
  
  	ret = request_firmware_nowait(THIS_MODULE,
  			FW_ACTION_HOTPLUG, fw_name, sdma->dev,
  			GFP_KERNEL, sdma, sdma_load_firmware);
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
2110
2111
2112
  
  	return ret;
  }
5763d3189   Robin Gong   MLK-23869-3: dmae...
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
  static int sdma_get_firmware_wait(struct sdma_engine *sdma,
  		const char *fw_name)
  {
  	const struct firmware *fw = NULL;
  	int ret;
  
  	ret = request_firmware(&fw, fw_name, sdma->dev);
  	if (ret < 0 || !fw) {
  		dev_err(sdma->dev, "unable to find firmware
  ");
  		return ret;
  	}
  
  	sdma_load_firmware(fw, (void *)sdma);
  
  	return 0;
  }
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
2130
  static int sdma_init_sw(struct sdma_engine *sdma)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2131
  {
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
2132
  	int ret, ccbsize;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2133

941acd566   Angus Ainslie (Purism)   dmaengine: imx-sd...
2134
2135
  	if (sdma->drvdata->check_ratio &&
  	    (clk_get_rate(sdma->clk_ahb) == clk_get_rate(sdma->clk_ipg)))
25aaa75df   Angus Ainslie (Purism)   dmaengine: imx-sd...
2136
  		sdma->clk_ratio = 1;
99c997755   Robin Gong   MLK-23005: dmaeng...
2137
2138
  	ccbsize = MAX_DMA_CHANNELS * (sizeof(struct sdma_channel_control)
  		+ sizeof(struct sdma_context_data));
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2139

dd7efc1f2   Nicolin Chen   dmaengine: imx-sd...
2140
2141
  	if (sdma->iram_pool)
  		sdma->channel_control = gen_pool_dma_alloc(sdma->iram_pool,
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
2142
  							   ccbsize, &sdma->ccb_phys);
dd7efc1f2   Nicolin Chen   dmaengine: imx-sd...
2143
2144
  	else
  		sdma->channel_control = dma_alloc_coherent(sdma->dev, ccbsize,
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
2145
  						&sdma->ccb_phys, GFP_KERNEL);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2146
2147
  	if (!sdma->channel_control) {
  		ret = -ENOMEM;
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
2148
  		return ret;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2149
2150
2151
2152
  	}
  
  	sdma->context = (void *)sdma->channel_control +
  		MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control);
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
2153
  	sdma->context_phys = sdma->ccb_phys +
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2154
  		MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2155
  	return 0;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2156
  }
9479e17c9   Shawn Guo   dma: imx-sdma: mo...
2157
2158
  static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param)
  {
0b3518652   Nicolin Chen   dmaengine: imx-sd...
2159
  	struct sdma_channel *sdmac = to_sdma_chan(chan);
9479e17c9   Shawn Guo   dma: imx-sdma: mo...
2160
2161
2162
2163
  	struct imx_dma_data *data = fn_param;
  
  	if (!imx_dma_is_general_purpose(chan))
  		return false;
0b3518652   Nicolin Chen   dmaengine: imx-sd...
2164
2165
  	sdmac->data = *data;
  	chan->private = &sdmac->data;
9479e17c9   Shawn Guo   dma: imx-sdma: mo...
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
  
  	return true;
  }
  
  static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec,
  				   struct of_dma *ofdma)
  {
  	struct sdma_engine *sdma = ofdma->of_dma_data;
  	dma_cap_mask_t mask = sdma->dma_device.cap_mask;
  	struct imx_dma_data data;
  
  	if (dma_spec->args_count != 3)
  		return NULL;
883a39c56   Shengjiu Wang   MLK-11259-1: dmae...
2179
  	memset(&data, 0, sizeof(data));
9479e17c9   Shawn Guo   dma: imx-sdma: mo...
2180
2181
  	data.dma_request = dma_spec->args[0];
  	data.peripheral_type = dma_spec->args[1];
d431de8fb   Robin Gong   dmaengine: imx-sd...
2182
2183
2184
2185
  	/* Get sw_done setting if sw_done enabled */
  	if (dma_spec->args[2] & BIT(31))
  		data.done_sel = dma_spec->args[2];
  	data.priority = dma_spec->args[2] & 0xff;
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
2186
2187
2188
2189
2190
2191
2192
2193
  	/*
  	 * init dma_request2 to zero, which is not used by the dts.
  	 * For P2P, dma_request2 is init from dma_request_channel(),
  	 * chan->private will point to the imx_dma_data, and in
  	 * device_alloc_chan_resources(), imx_dma_data.dma_request2 will
  	 * be set to sdmac->event_id1.
  	 */
  	data.dma_request2 = 0;
9479e17c9   Shawn Guo   dma: imx-sdma: mo...
2194

990c0b53b   Baolin Wang   dmaengine: imx-sd...
2195
2196
  	return __dma_request_channel(&mask, sdma_filter_fn, &data,
  				     ofdma->of_node);
9479e17c9   Shawn Guo   dma: imx-sdma: mo...
2197
  }
e34b731fa   Mark Brown   dma: imx-sdma: Re...
2198
  static int sdma_probe(struct platform_device *pdev)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2199
  {
580975d7f   Shawn Guo   dmaengine: imx-sd...
2200
2201
2202
  	const struct of_device_id *of_id =
  			of_match_device(sdma_dt_ids, &pdev->dev);
  	struct device_node *np = pdev->dev.of_node;
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
2203
  	struct device_node *spba_bus;
580975d7f   Shawn Guo   dmaengine: imx-sd...
2204
  	const char *fw_name;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2205
  	int ret;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2206
  	int irq;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2207
  	struct resource *iores;
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
2208
  	struct resource spba_res;
d4adcc016   Jingoo Han   dma: use dev_get_...
2209
  	struct sdma_platform_data *pdata = dev_get_platdata(&pdev->dev);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2210
  	int i;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2211
  	struct sdma_engine *sdma;
36e2f21ab   Sascha Hauer   dmaengine i.MX SD...
2212
  	s32 *saddr_arr;
17bba72f8   Sascha Hauer   dma: imx-sdma: Us...
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
  	const struct sdma_driver_data *drvdata = NULL;
  
  	if (of_id)
  		drvdata = of_id->data;
  	else if (pdev->id_entry)
  		drvdata = (void *)pdev->id_entry->driver_data;
  
  	if (!drvdata) {
  		dev_err(&pdev->dev, "unable to find driver data
  ");
  		return -EINVAL;
  	}
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2225

42536b9f9   Philippe Retornaz   ARM: 7857/1: dma:...
2226
2227
2228
  	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
  	if (ret)
  		return ret;
7f24e0ee0   Fabio Estevam   dmaengine: imx-sd...
2229
  	sdma = devm_kzalloc(&pdev->dev, sizeof(*sdma), GFP_KERNEL);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2230
2231
  	if (!sdma)
  		return -ENOMEM;
2ccaef052   Richard Zhao   dma: imx-sdma: ma...
2232
  	spin_lock_init(&sdma->channel_0_lock);
73eab978a   Sascha Hauer   dmaengine i.MX SD...
2233

1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2234
  	sdma->dev = &pdev->dev;
17bba72f8   Sascha Hauer   dma: imx-sdma: Us...
2235
  	sdma->drvdata = drvdata;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2236

1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2237
  	irq = platform_get_irq(pdev, 0);
7f24e0ee0   Fabio Estevam   dmaengine: imx-sd...
2238
  	if (irq < 0)
63c72e028   Fabio Estevam   dmaengine: imx-sd...
2239
  		return irq;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2240

7f24e0ee0   Fabio Estevam   dmaengine: imx-sd...
2241
2242
2243
2244
  	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	sdma->regs = devm_ioremap_resource(&pdev->dev, iores);
  	if (IS_ERR(sdma->regs))
  		return PTR_ERR(sdma->regs);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2245

7560e3f35   Sascha Hauer   dmaengine i.MX SD...
2246
  	sdma->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
7f24e0ee0   Fabio Estevam   dmaengine: imx-sd...
2247
2248
  	if (IS_ERR(sdma->clk_ipg))
  		return PTR_ERR(sdma->clk_ipg);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2249

7560e3f35   Sascha Hauer   dmaengine i.MX SD...
2250
  	sdma->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
7f24e0ee0   Fabio Estevam   dmaengine: imx-sd...
2251
2252
  	if (IS_ERR(sdma->clk_ahb))
  		return PTR_ERR(sdma->clk_ahb);
7560e3f35   Sascha Hauer   dmaengine i.MX SD...
2253

fb9caf370   Arvind Yadav   dmaengine: imx-sd...
2254
2255
2256
2257
2258
2259
2260
  	ret = clk_prepare(sdma->clk_ipg);
  	if (ret)
  		return ret;
  
  	ret = clk_prepare(sdma->clk_ahb);
  	if (ret)
  		goto err_clk;
7560e3f35   Sascha Hauer   dmaengine i.MX SD...
2261

7f24e0ee0   Fabio Estevam   dmaengine: imx-sd...
2262
2263
  	ret = devm_request_irq(&pdev->dev, irq, sdma_int_handler, 0, "sdma",
  			       sdma);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2264
  	if (ret)
fb9caf370   Arvind Yadav   dmaengine: imx-sd...
2265
  		goto err_irq;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2266

5bb9dbb5a   Vinod Koul   dmaengine: imx-sd...
2267
  	sdma->irq = irq;
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
2268
  	sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL);
fb9caf370   Arvind Yadav   dmaengine: imx-sd...
2269
2270
2271
2272
  	if (!sdma->script_addrs) {
  		ret = -ENOMEM;
  		goto err_irq;
  	}
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2273

36e2f21ab   Sascha Hauer   dmaengine i.MX SD...
2274
2275
  	/* initially no scripts available */
  	saddr_arr = (s32 *)sdma->script_addrs;
be4cf718c   Sascha Hauer   dmaengine: imx-sd...
2276
  	for (i = 0; i < sizeof(*sdma->script_addrs) / sizeof(s32); i++)
36e2f21ab   Sascha Hauer   dmaengine i.MX SD...
2277
  		saddr_arr[i] = -EINVAL;
7214a8b14   Sascha Hauer   dmaengine i.MX SD...
2278
2279
  	dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
  	dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
0f06c0275   Robin Gong   dmaengine: imx-sd...
2280
  	dma_cap_set(DMA_MEMCPY, sdma->dma_device.cap_mask);
7214a8b14   Sascha Hauer   dmaengine i.MX SD...
2281

1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2282
2283
2284
2285
2286
2287
  	INIT_LIST_HEAD(&sdma->dma_device.channels);
  	/* Initialize channel parameters */
  	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
  		struct sdma_channel *sdmac = &sdma->channel[i];
  
  		sdmac->sdma = sdma;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2288

1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2289
  		sdmac->channel = i;
57b772b86   Robin Gong   dmaengine: imx-sd...
2290
  		sdmac->vc.desc_free = sdma_desc_free;
24e30e721   Robin Gong   dmaengine: imx-sd...
2291
  		INIT_LIST_HEAD(&sdmac->terminated);
b8603d2a5   Lucas Stach   dmaengine: imx-sd...
2292
2293
  		INIT_WORK(&sdmac->terminate_worker,
  				sdma_channel_terminate_work);
23889c635   Sascha Hauer   dmaengine i.MX SD...
2294
2295
2296
2297
2298
2299
  		/*
  		 * Add the channel to the DMAC list. Do not add channel 0 though
  		 * because we need it internally in the SDMA driver. This also means
  		 * that channel 0 in dmaengine counting matches sdma channel 1.
  		 */
  		if (i)
57b772b86   Robin Gong   dmaengine: imx-sd...
2300
  			vchan_init(&sdmac->vc, &sdma->dma_device);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2301
  	}
319dbd97e   Robin Gong   MLK-25116-2: dmae...
2302
2303
2304
2305
2306
2307
  	if (np) {
  		sdma->iram_pool = of_gen_pool_get(np, "iram", 0);
  		if (sdma->iram_pool)
  			dev_info(&pdev->dev, "alloc bd from iram.
  ");
  	}
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
2308
  	ret = sdma_init_sw(sdma);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2309
2310
  	if (ret)
  		goto err_init;
d078cd1b4   Zidan Wang   dmaengine: imx-sd...
2311
2312
2313
  	ret = sdma_event_remap(sdma);
  	if (ret)
  		goto err_init;
dcfec3c09   Sascha Hauer   dma: imx-sdma: Ad...
2314
2315
  	if (sdma->drvdata->script_addrs)
  		sdma_add_scripts(sdma, sdma->drvdata->script_addrs);
580975d7f   Shawn Guo   dmaengine: imx-sd...
2316
  	if (pdata && pdata->script_addrs)
5b28aa319   Sascha Hauer   dmaengine i.MX SD...
2317
  		sdma_add_scripts(sdma, pdata->script_addrs);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2318
2319
2320
2321
2322
2323
2324
  	sdma->dma_device.dev = &pdev->dev;
  
  	sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources;
  	sdma->dma_device.device_free_chan_resources = sdma_free_chan_resources;
  	sdma->dma_device.device_tx_status = sdma_tx_status;
  	sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg;
  	sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic;
7b350ab0f   Maxime Ripard   dmaengine: imx-sd...
2325
  	sdma->dma_device.device_config = sdma_config;
a80f2787f   Sascha Hauer   dmaengine: imx-sd...
2326
  	sdma->dma_device.device_terminate_all = sdma_terminate_all;
b8603d2a5   Lucas Stach   dmaengine: imx-sd...
2327
  	sdma->dma_device.device_synchronize = sdma_channel_synchronize;
f9d4a398f   Nicolin Chen   dmaengine: imx-sd...
2328
2329
2330
  	sdma->dma_device.src_addr_widths = SDMA_DMA_BUSWIDTHS;
  	sdma->dma_device.dst_addr_widths = SDMA_DMA_BUSWIDTHS;
  	sdma->dma_device.directions = SDMA_DMA_DIRECTIONS;
6f3125ceb   Lucas Stach   dmaengine: imx-sd...
2331
  	sdma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
0f06c0275   Robin Gong   dmaengine: imx-sd...
2332
  	sdma->dma_device.device_prep_dma_memcpy = sdma_prep_memcpy;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2333
  	sdma->dma_device.device_issue_pending = sdma_issue_pending;
a3711d49b   Angus Ainslie (Purism)   dmaengine: imx-sd...
2334
  	sdma->dma_device.copy_align = 2;
4a6b2e8a9   Robin Gong   dmaengine: imx-sd...
2335
  	dma_set_max_seg_size(sdma->dma_device.dev, SDMA_BD_MAX_CNT);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2336

23e118113   Vignesh Raman   dma: imx-sdma: us...
2337
  	platform_set_drvdata(pdev, sdma);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2338
2339
2340
2341
2342
2343
  	ret = dma_async_device_register(&sdma->dma_device);
  	if (ret) {
  		dev_err(&pdev->dev, "unable to register
  ");
  		goto err_init;
  	}
9479e17c9   Shawn Guo   dma: imx-sdma: mo...
2344
2345
2346
2347
2348
2349
2350
  	if (np) {
  		ret = of_dma_controller_register(np, sdma_xlate, sdma);
  		if (ret) {
  			dev_err(&pdev->dev, "failed to register controller
  ");
  			goto err_register;
  		}
8391ecf46   Shengjiu Wang   dmaengine: imx-sd...
2351
2352
2353
2354
2355
2356
2357
2358
  
  		spba_bus = of_find_compatible_node(NULL, NULL, "fsl,spba-bus");
  		ret = of_address_to_resource(spba_bus, 0, &spba_res);
  		if (!ret) {
  			sdma->spba_start_addr = spba_res.start;
  			sdma->spba_end_addr = spba_res.end;
  		}
  		of_node_put(spba_bus);
9479e17c9   Shawn Guo   dma: imx-sdma: mo...
2359
  	}
2b8066c3d   Sven Van Asbroeck   dmaengine: imx-sd...
2360
  	if (pdata) {
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
2361
  		sdma->fw_name = pdata->fw_name;
2b8066c3d   Sven Van Asbroeck   dmaengine: imx-sd...
2362
2363
2364
2365
2366
2367
2368
2369
  	} else {
  		/*
  		 * Because that device tree does not encode ROM script address,
  		 * the RAM script in firmware is mandatory for device tree
  		 * probe, otherwise it fails.
  		 */
  		ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
  					      &fw_name);
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
2370
  		if (ret)
2b8066c3d   Sven Van Asbroeck   dmaengine: imx-sd...
2371
2372
  			dev_warn(&pdev->dev, "failed to get firmware name
  ");
7dad92fba   Robin Gong   MLK-23869-1 dmaen...
2373
2374
  		else
  			sdma->fw_name = fw_name;
2b8066c3d   Sven Van Asbroeck   dmaengine: imx-sd...
2375
  	}
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
2376
2377
2378
  	pm_runtime_enable(&pdev->dev);
  	if (!sdma->drvdata->pm_runtime)
  		pm_runtime_get_sync(&pdev->dev);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2379
  	return 0;
9479e17c9   Shawn Guo   dma: imx-sdma: mo...
2380
2381
  err_register:
  	dma_async_device_unregister(&sdma->dma_device);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2382
2383
  err_init:
  	kfree(sdma->script_addrs);
fb9caf370   Arvind Yadav   dmaengine: imx-sd...
2384
2385
2386
2387
  err_irq:
  	clk_unprepare(sdma->clk_ahb);
  err_clk:
  	clk_unprepare(sdma->clk_ipg);
939fd4f07   Shawn Guo   dmaengine: imx-sd...
2388
  	return ret;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2389
  }
1d1bbd305   Maxin B. John   dma: Remove erron...
2390
  static int sdma_remove(struct platform_device *pdev)
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2391
  {
23e118113   Vignesh Raman   dma: imx-sdma: us...
2392
  	struct sdma_engine *sdma = platform_get_drvdata(pdev);
c12fe4972   Vignesh Raman   dma: imx-sdma: Ad...
2393
  	int i;
23e118113   Vignesh Raman   dma: imx-sdma: us...
2394

5bb9dbb5a   Vinod Koul   dmaengine: imx-sd...
2395
  	devm_free_irq(&pdev->dev, sdma->irq, sdma);
23e118113   Vignesh Raman   dma: imx-sdma: us...
2396
2397
  	dma_async_device_unregister(&sdma->dma_device);
  	kfree(sdma->script_addrs);
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
2398
  	pm_runtime_put_sync_suspend(sdma->dev);
fb9caf370   Arvind Yadav   dmaengine: imx-sd...
2399
2400
  	clk_unprepare(sdma->clk_ahb);
  	clk_unprepare(sdma->clk_ipg);
c12fe4972   Vignesh Raman   dma: imx-sdma: Ad...
2401
2402
2403
  	/* Kill the tasklet */
  	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
  		struct sdma_channel *sdmac = &sdma->channel[i];
57b772b86   Robin Gong   dmaengine: imx-sd...
2404
2405
  		tasklet_kill(&sdmac->vc.task);
  		sdma_free_chan_resources(&sdmac->vc.chan);
c12fe4972   Vignesh Raman   dma: imx-sdma: Ad...
2406
  	}
23e118113   Vignesh Raman   dma: imx-sdma: us...
2407
2408
  
  	platform_set_drvdata(pdev, NULL);
23e118113   Vignesh Raman   dma: imx-sdma: us...
2409
  	return 0;
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2410
  }
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2411
2412
2413
2414
2415
2416
  #ifdef CONFIG_PM_SLEEP
  static int sdma_suspend(struct device *dev)
  {
  	struct platform_device *pdev = to_platform_device(dev);
  	struct sdma_engine *sdma = platform_get_drvdata(pdev);
  	int i, ret = 0;
9c485b715   Robin Gong   MLK-23400-1: dmae...
2417
  	/* Do nothing if not i.MX6SX or i.MX7D, i.MX8MP */
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2418
  	if (sdma->drvdata != &sdma_imx6sx && sdma->drvdata != &sdma_imx7d
9c485b715   Robin Gong   MLK-23400-1: dmae...
2419
  	   && sdma->drvdata != &sdma_imx6ul && sdma->drvdata != &sdma_imx8mp)
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2420
  		return 0;
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
2421
2422
  	if (!sdma->is_on)
  		return 0;
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2423
2424
2425
2426
2427
2428
2429
  
  	ret = sdma_save_restore_context(sdma, true);
  	if (ret) {
  		dev_err(sdma->dev, "save context error!
  ");
  		return ret;
  	}
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
2430

57d1ed37c   Robin Gong   dmaengine: imx-sd...
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
  	/* save regs */
  	for (i = 0; i < MXC_SDMA_SAVED_REG_NUM; i++) {
  		/*
  		 * 0x78(SDMA_XTRIG_CONF2+4)~0x100(SDMA_CHNPRI_O) registers are
  		 * reserved and can't be touched. Skip these regs.
  		 */
  		if (i > SDMA_XTRIG_CONF2 / 4)
  			sdma->save_regs[i] = readl_relaxed(sdma->regs +
  							   MXC_SDMA_RESERVED_REG
  							   + 4 * i);
  		else
  			sdma->save_regs[i] = readl_relaxed(sdma->regs + 4 * i);
  	}
ad57e9874   Robin Gong   MLK-23540 dmaengi...
2444
2445
2446
2447
2448
  	if (sdma->drvdata->has_done0) {
  		for (i = 0; i < 2; i++)
  			sdma->save_done0_regs[i] =
  			readl_relaxed(sdma->regs + SDMA_DONE0_CONFIG + 4 * i);
  	}
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2449
2450
2451
2452
2453
2454
2455
2456
2457
  	return 0;
  }
  
  static int sdma_resume(struct device *dev)
  {
  	struct platform_device *pdev = to_platform_device(dev);
  	struct sdma_engine *sdma = platform_get_drvdata(pdev);
  	unsigned long timeout = jiffies + msecs_to_jiffies(2);
  	int i, ret;
9c485b715   Robin Gong   MLK-23400-1: dmae...
2458
  	/* Do nothing if not i.MX6SX or i.MX7D, i.MX8MP*/
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2459
  	if (sdma->drvdata != &sdma_imx6sx && sdma->drvdata != &sdma_imx7d
9c485b715   Robin Gong   MLK-23400-1: dmae...
2460
  	    && sdma->drvdata != &sdma_imx6ul && sdma->drvdata != &sdma_imx8mp)
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2461
  		return 0;
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
2462
2463
  	if (!sdma->is_on)
  		return 0;
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2464
  	/* Do nothing if mega/fast mix not turned off */
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
2465
  	if (readl_relaxed(sdma->regs + SDMA_H_C0PTR))
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2466
  		return 0;
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
  
  	/* Firmware was lost, mark as "not ready" */
  	sdma->fw_loaded = false;
  
  	/* restore regs and load firmware */
  	for (i = 0; i < MXC_SDMA_SAVED_REG_NUM; i++) {
  		/*
  		 * 0x78(SDMA_XTRIG_CONF2+4)~0x100(SDMA_CHNPRI_O) registers are
  		 * reserved and can't be touched. Skip these regs.
  		 */
  		if (i > SDMA_XTRIG_CONF2 / 4)
  			writel_relaxed(sdma->save_regs[i], sdma->regs +
  				       MXC_SDMA_RESERVED_REG + 4 * i);
  		/* set static context switch  mode before channel0 running */
  		else if (i == SDMA_H_CONFIG / 4)
  			writel_relaxed(sdma->save_regs[i] & ~SDMA_H_CONFIG_CSM,
  					sdma->regs + SDMA_H_CONFIG);
  		else
  			writel_relaxed(sdma->save_regs[i], sdma->regs + 4 * i);
  	}
ad57e9874   Robin Gong   MLK-23540 dmaengi...
2487
2488
2489
2490
2491
2492
  	/* restore SDMA_DONEx_CONFIG */
  	if (sdma->drvdata->has_done0) {
  		for (i = 0; i < 2; i++)
  			writel_relaxed(sdma->save_done0_regs[i],
  				sdma->regs + SDMA_DONE0_CONFIG + 4 * i);
  	}
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2493
  	/* prepare priority for channel0 to start */
41fdb664e   Robin Gong   LF-3132: dmaengin...
2494
  	sdma_set_channel_priority(&sdma->channel[0], MXC_SDMA_MAX_PRIORITY);
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2495
2496
2497
2498
2499
  
  	ret = sdma_get_firmware(sdma, sdma->fw_name);
  	if (ret) {
  		dev_warn(&pdev->dev, "failed to get firmware
  ");
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
2500
  		return ret;
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
  	}
  	/* wait firmware loaded */
  	do {
  		if (time_after(jiffies, timeout)) {
  			dev_warn(&pdev->dev, "failed to load firmware
  ");
  			break;
  		}
  		usleep_range(50, 500);
  	} while (!sdma->fw_loaded);
  
  	ret = sdma_save_restore_context(sdma, false);
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
2513
  	if (ret)
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2514
2515
  		dev_err(sdma->dev, "restore context error!
  ");
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2516
2517
2518
2519
2520
2521
2522
  
  	return ret;
  }
  #endif
  
  static const struct dev_pm_ops sdma_pm_ops = {
  	SET_LATE_SYSTEM_SLEEP_PM_OPS(sdma_suspend, sdma_resume)
0e7ac52c3   Robin Gong   MLK-23869-2 dmaen...
2523
  	SET_RUNTIME_PM_OPS(sdma_runtime_suspend, sdma_runtime_resume, NULL)
57d1ed37c   Robin Gong   dmaengine: imx-sd...
2524
  };
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2525
2526
2527
  static struct platform_driver sdma_driver = {
  	.driver		= {
  		.name	= "imx-sdma",
580975d7f   Shawn Guo   dmaengine: imx-sd...
2528
  		.of_match_table = sdma_dt_ids,
f7fd47156   Shengjiu Wang   dma: imx-sdma: Ad...
2529
  		.pm = &sdma_pm_ops,
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2530
  	},
62550cd7c   Shawn Guo   dmaengine: imx-sd...
2531
  	.id_table	= sdma_devtypes,
1d1bbd305   Maxin B. John   dma: Remove erron...
2532
  	.remove		= sdma_remove,
23e118113   Vignesh Raman   dma: imx-sdma: us...
2533
  	.probe		= sdma_probe,
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2534
  };
23e118113   Vignesh Raman   dma: imx-sdma: us...
2535
  module_platform_driver(sdma_driver);
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2536
2537
2538
  
  MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
  MODULE_DESCRIPTION("i.MX SDMA driver");
c0879342e   Nicolas Chauvet   dmaengine: imx-sd...
2539
2540
2541
2542
2543
2544
  #if IS_ENABLED(CONFIG_SOC_IMX6Q)
  MODULE_FIRMWARE("imx/sdma/sdma-imx6q.bin");
  #endif
  #if IS_ENABLED(CONFIG_SOC_IMX7D)
  MODULE_FIRMWARE("imx/sdma/sdma-imx7d.bin");
  #endif
1ec1e82f2   Sascha Hauer   dmaengine: Add Fr...
2545
  MODULE_LICENSE("GPL");