Blame view

drivers/dma/imx-dma.c 34 KB
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1
2
3
4
5
6
7
  /*
   * drivers/dma/imx-dma.c
   *
   * This file contains a driver for the Freescale i.MX DMA engine
   * found on i.MX1/21/27
   *
   * Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
9e15db7ce   Javier Martin   dmaengine: Add su...
8
   * Copyright 2012 Javier Martin, Vista Silicon <javier.martin@vista-silicon.com>
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
9
10
11
12
13
14
15
16
   *
   * The code contained herein is licensed under the GNU General Public
   * License. You may obtain a copy of the GNU General Public License
   * Version 2 or later at the following locations:
   *
   * http://www.opensource.org/licenses/gpl-license.html
   * http://www.gnu.org/copyleft/gpl.html
   */
7331205a9   Thierry Reding   dma: Convert to d...
17
  #include <linux/err.h>
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
18
19
20
21
22
23
24
25
26
  #include <linux/init.h>
  #include <linux/types.h>
  #include <linux/mm.h>
  #include <linux/interrupt.h>
  #include <linux/spinlock.h>
  #include <linux/device.h>
  #include <linux/dma-mapping.h>
  #include <linux/slab.h>
  #include <linux/platform_device.h>
6bd081277   Javier Martin   dmaengine: imx-dm...
27
  #include <linux/clk.h>
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
28
  #include <linux/dmaengine.h>
5c45ad77f   Paul Gortmaker   drivers/dma: Add ...
29
  #include <linux/module.h>
290ad0f9d   Markus Pargmann   dma: imx-dma: Add...
30
31
  #include <linux/of_device.h>
  #include <linux/of_dma.h>
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
32
33
  
  #include <asm/irq.h>
82906b13a   Arnd Bergmann   ARM: imx: move pl...
34
  #include <linux/platform_data/dma-imx.h>
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
35

d2ebfb335   Russell King - ARM Linux   dmaengine: add pr...
36
  #include "dmaengine.h"
9e15db7ce   Javier Martin   dmaengine: Add su...
37
  #define IMXDMA_MAX_CHAN_DESCRIPTORS	16
6bd081277   Javier Martin   dmaengine: imx-dm...
38
  #define IMX_DMA_CHANNELS  16
f606ab897   Javier Martin   dmaengine: i.MX: ...
39
40
41
  #define IMX_DMA_2D_SLOTS	2
  #define IMX_DMA_2D_SLOT_A	0
  #define IMX_DMA_2D_SLOT_B	1
6bd081277   Javier Martin   dmaengine: imx-dm...
42
43
44
45
46
47
48
49
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
77
78
79
80
81
82
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
  #define IMX_DMA_LENGTH_LOOP	((unsigned int)-1)
  #define IMX_DMA_MEMSIZE_32	(0 << 4)
  #define IMX_DMA_MEMSIZE_8	(1 << 4)
  #define IMX_DMA_MEMSIZE_16	(2 << 4)
  #define IMX_DMA_TYPE_LINEAR	(0 << 10)
  #define IMX_DMA_TYPE_2D		(1 << 10)
  #define IMX_DMA_TYPE_FIFO	(2 << 10)
  
  #define IMX_DMA_ERR_BURST     (1 << 0)
  #define IMX_DMA_ERR_REQUEST   (1 << 1)
  #define IMX_DMA_ERR_TRANSFER  (1 << 2)
  #define IMX_DMA_ERR_BUFFER    (1 << 3)
  #define IMX_DMA_ERR_TIMEOUT   (1 << 4)
  
  #define DMA_DCR     0x00		/* Control Register */
  #define DMA_DISR    0x04		/* Interrupt status Register */
  #define DMA_DIMR    0x08		/* Interrupt mask Register */
  #define DMA_DBTOSR  0x0c		/* Burst timeout status Register */
  #define DMA_DRTOSR  0x10		/* Request timeout Register */
  #define DMA_DSESR   0x14		/* Transfer Error Status Register */
  #define DMA_DBOSR   0x18		/* Buffer overflow status Register */
  #define DMA_DBTOCR  0x1c		/* Burst timeout control Register */
  #define DMA_WSRA    0x40		/* W-Size Register A */
  #define DMA_XSRA    0x44		/* X-Size Register A */
  #define DMA_YSRA    0x48		/* Y-Size Register A */
  #define DMA_WSRB    0x4c		/* W-Size Register B */
  #define DMA_XSRB    0x50		/* X-Size Register B */
  #define DMA_YSRB    0x54		/* Y-Size Register B */
  #define DMA_SAR(x)  (0x80 + ((x) << 6))	/* Source Address Registers */
  #define DMA_DAR(x)  (0x84 + ((x) << 6))	/* Destination Address Registers */
  #define DMA_CNTR(x) (0x88 + ((x) << 6))	/* Count Registers */
  #define DMA_CCR(x)  (0x8c + ((x) << 6))	/* Control Registers */
  #define DMA_RSSR(x) (0x90 + ((x) << 6))	/* Request source select Registers */
  #define DMA_BLR(x)  (0x94 + ((x) << 6))	/* Burst length Registers */
  #define DMA_RTOR(x) (0x98 + ((x) << 6))	/* Request timeout Registers */
  #define DMA_BUCR(x) (0x98 + ((x) << 6))	/* Bus Utilization Registers */
  #define DMA_CCNR(x) (0x9C + ((x) << 6))	/* Channel counter Registers */
  
  #define DCR_DRST           (1<<1)
  #define DCR_DEN            (1<<0)
  #define DBTOCR_EN          (1<<15)
  #define DBTOCR_CNT(x)      ((x) & 0x7fff)
  #define CNTR_CNT(x)        ((x) & 0xffffff)
  #define CCR_ACRPT          (1<<14)
  #define CCR_DMOD_LINEAR    (0x0 << 12)
  #define CCR_DMOD_2D        (0x1 << 12)
  #define CCR_DMOD_FIFO      (0x2 << 12)
  #define CCR_DMOD_EOBFIFO   (0x3 << 12)
  #define CCR_SMOD_LINEAR    (0x0 << 10)
  #define CCR_SMOD_2D        (0x1 << 10)
  #define CCR_SMOD_FIFO      (0x2 << 10)
  #define CCR_SMOD_EOBFIFO   (0x3 << 10)
  #define CCR_MDIR_DEC       (1<<9)
  #define CCR_MSEL_B         (1<<8)
  #define CCR_DSIZ_32        (0x0 << 6)
  #define CCR_DSIZ_8         (0x1 << 6)
  #define CCR_DSIZ_16        (0x2 << 6)
  #define CCR_SSIZ_32        (0x0 << 4)
  #define CCR_SSIZ_8         (0x1 << 4)
  #define CCR_SSIZ_16        (0x2 << 4)
  #define CCR_REN            (1<<3)
  #define CCR_RPT            (1<<2)
  #define CCR_FRC            (1<<1)
  #define CCR_CEN            (1<<0)
  #define RTOR_EN            (1<<15)
  #define RTOR_CLK           (1<<14)
  #define RTOR_PSC           (1<<13)
9e15db7ce   Javier Martin   dmaengine: Add su...
109
110
111
112
113
114
115
  
  enum  imxdma_prep_type {
  	IMXDMA_DESC_MEMCPY,
  	IMXDMA_DESC_INTERLEAVED,
  	IMXDMA_DESC_SLAVE_SG,
  	IMXDMA_DESC_CYCLIC,
  };
f606ab897   Javier Martin   dmaengine: i.MX: ...
116
117
118
119
120
121
  struct imx_dma_2d_config {
  	u16		xsr;
  	u16		ysr;
  	u16		wsr;
  	int		count;
  };
9e15db7ce   Javier Martin   dmaengine: Add su...
122
123
124
125
126
127
128
  struct imxdma_desc {
  	struct list_head		node;
  	struct dma_async_tx_descriptor	desc;
  	enum dma_status			status;
  	dma_addr_t			src;
  	dma_addr_t			dest;
  	size_t				len;
2efc3449d   Javier Martin   dmaengine: imx-dm...
129
  	enum dma_transfer_direction	direction;
9e15db7ce   Javier Martin   dmaengine: Add su...
130
131
132
133
134
135
136
137
138
139
140
141
  	enum imxdma_prep_type		type;
  	/* For memcpy and interleaved */
  	unsigned int			config_port;
  	unsigned int			config_mem;
  	/* For interleaved transfers */
  	unsigned int			x;
  	unsigned int			y;
  	unsigned int			w;
  	/* For slave sg and cyclic */
  	struct scatterlist		*sg;
  	unsigned int			sgcount;
  };
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
142
  struct imxdma_channel {
2d9c2fc59   Javier Martin   dmaengine: imx-dm...
143
144
  	int				hw_chaining;
  	struct timer_list		watchdog;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
145
146
  	struct imxdma_engine		*imxdma;
  	unsigned int			channel;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
147

9e15db7ce   Javier Martin   dmaengine: Add su...
148
149
150
151
152
  	struct tasklet_struct		dma_tasklet;
  	struct list_head		ld_free;
  	struct list_head		ld_queue;
  	struct list_head		ld_active;
  	int				descs_allocated;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
153
154
155
156
  	enum dma_slave_buswidth		word_size;
  	dma_addr_t			per_address;
  	u32				watermark_level;
  	struct dma_chan			chan;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
157
  	struct dma_async_tx_descriptor	desc;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
158
159
160
  	enum dma_status			status;
  	int				dma_request;
  	struct scatterlist		*sg_list;
359291a1a   Javier Martin   dmaengine: imx-dm...
161
162
  	u32				ccr_from_device;
  	u32				ccr_to_device;
f606ab897   Javier Martin   dmaengine: i.MX: ...
163
164
  	bool				enabled_2d;
  	int				slot_2d;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
165
  };
e51d0f0ac   Shawn Guo   dma: imx-dma: rem...
166
167
168
169
170
  enum imx_dma_type {
  	IMX1_DMA,
  	IMX21_DMA,
  	IMX27_DMA,
  };
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
171
172
  struct imxdma_engine {
  	struct device			*dev;
1e070a609   Sascha Hauer   dmaengine i.MX dm...
173
  	struct device_dma_parameters	dma_parms;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
174
  	struct dma_device		dma_device;
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
175
  	void __iomem			*base;
a2367db2e   Fabio Estevam   dma: imx-dma: Fix...
176
177
  	struct clk			*dma_ahb;
  	struct clk			*dma_ipg;
f606ab897   Javier Martin   dmaengine: i.MX: ...
178
179
  	spinlock_t			lock;
  	struct imx_dma_2d_config	slots_2d[IMX_DMA_2D_SLOTS];
6bd081277   Javier Martin   dmaengine: imx-dm...
180
  	struct imxdma_channel		channel[IMX_DMA_CHANNELS];
e51d0f0ac   Shawn Guo   dma: imx-dma: rem...
181
  	enum imx_dma_type		devtype;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
182
  };
290ad0f9d   Markus Pargmann   dma: imx-dma: Add...
183
184
185
186
  struct imxdma_filter_data {
  	struct imxdma_engine	*imxdma;
  	int			 request;
  };
e51d0f0ac   Shawn Guo   dma: imx-dma: rem...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  static struct platform_device_id imx_dma_devtype[] = {
  	{
  		.name = "imx1-dma",
  		.driver_data = IMX1_DMA,
  	}, {
  		.name = "imx21-dma",
  		.driver_data = IMX21_DMA,
  	}, {
  		.name = "imx27-dma",
  		.driver_data = IMX27_DMA,
  	}, {
  		/* sentinel */
  	}
  };
  MODULE_DEVICE_TABLE(platform, imx_dma_devtype);
290ad0f9d   Markus Pargmann   dma: imx-dma: Add...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  static const struct of_device_id imx_dma_of_dev_id[] = {
  	{
  		.compatible = "fsl,imx1-dma",
  		.data = &imx_dma_devtype[IMX1_DMA],
  	}, {
  		.compatible = "fsl,imx21-dma",
  		.data = &imx_dma_devtype[IMX21_DMA],
  	}, {
  		.compatible = "fsl,imx27-dma",
  		.data = &imx_dma_devtype[IMX27_DMA],
  	}, {
  		/* sentinel */
  	}
  };
  MODULE_DEVICE_TABLE(of, imx_dma_of_dev_id);
e51d0f0ac   Shawn Guo   dma: imx-dma: rem...
217
218
219
220
221
222
223
224
225
226
227
228
229
230
  static inline int is_imx1_dma(struct imxdma_engine *imxdma)
  {
  	return imxdma->devtype == IMX1_DMA;
  }
  
  static inline int is_imx21_dma(struct imxdma_engine *imxdma)
  {
  	return imxdma->devtype == IMX21_DMA;
  }
  
  static inline int is_imx27_dma(struct imxdma_engine *imxdma)
  {
  	return imxdma->devtype == IMX27_DMA;
  }
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
231
232
233
234
  static struct imxdma_channel *to_imxdma_chan(struct dma_chan *chan)
  {
  	return container_of(chan, struct imxdma_channel, chan);
  }
9e15db7ce   Javier Martin   dmaengine: Add su...
235
  static inline bool imxdma_chan_is_doing_cyclic(struct imxdma_channel *imxdmac)
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
236
  {
9e15db7ce   Javier Martin   dmaengine: Add su...
237
238
239
240
241
242
243
244
245
  	struct imxdma_desc *desc;
  
  	if (!list_empty(&imxdmac->ld_active)) {
  		desc = list_first_entry(&imxdmac->ld_active, struct imxdma_desc,
  					node);
  		if (desc->type == IMXDMA_DESC_CYCLIC)
  			return true;
  	}
  	return false;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
246
  }
6bd081277   Javier Martin   dmaengine: imx-dm...
247

cd5cf9da0   Javier Martin   dmaengine: imx-dm...
248
249
250
  
  static void imx_dmav1_writel(struct imxdma_engine *imxdma, unsigned val,
  			     unsigned offset)
6bd081277   Javier Martin   dmaengine: imx-dm...
251
  {
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
252
  	__raw_writel(val, imxdma->base + offset);
6bd081277   Javier Martin   dmaengine: imx-dm...
253
  }
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
254
  static unsigned imx_dmav1_readl(struct imxdma_engine *imxdma, unsigned offset)
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
255
  {
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
256
  	return __raw_readl(imxdma->base + offset);
6bd081277   Javier Martin   dmaengine: imx-dm...
257
  }
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
258

2d9c2fc59   Javier Martin   dmaengine: imx-dm...
259
  static int imxdma_hw_chain(struct imxdma_channel *imxdmac)
6bd081277   Javier Martin   dmaengine: imx-dm...
260
  {
e51d0f0ac   Shawn Guo   dma: imx-dma: rem...
261
262
263
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
  
  	if (is_imx27_dma(imxdma))
2d9c2fc59   Javier Martin   dmaengine: imx-dm...
264
  		return imxdmac->hw_chaining;
6bd081277   Javier Martin   dmaengine: imx-dm...
265
266
267
268
269
270
271
  	else
  		return 0;
  }
  
  /*
   * imxdma_sg_next - prepare next chunk for scatter-gather DMA emulation
   */
a6cbb2d87   Javier Martin   dmaengine: imx-dm...
272
  static inline int imxdma_sg_next(struct imxdma_desc *d)
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
273
  {
2efc3449d   Javier Martin   dmaengine: imx-dm...
274
  	struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
275
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
a6cbb2d87   Javier Martin   dmaengine: imx-dm...
276
  	struct scatterlist *sg = d->sg;
6bd081277   Javier Martin   dmaengine: imx-dm...
277
  	unsigned long now;
fdaf9c4b2   Lars-Peter Clausen   dmaengine: Use dm...
278
  	now = min(d->len, sg_dma_len(sg));
6b0e2f55e   Javier Martin   dmaengine: imx-dm...
279
280
  	if (d->len != IMX_DMA_LENGTH_LOOP)
  		d->len -= now;
6bd081277   Javier Martin   dmaengine: imx-dm...
281

2efc3449d   Javier Martin   dmaengine: imx-dm...
282
  	if (d->direction == DMA_DEV_TO_MEM)
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
283
284
  		imx_dmav1_writel(imxdma, sg->dma_address,
  				 DMA_DAR(imxdmac->channel));
6bd081277   Javier Martin   dmaengine: imx-dm...
285
  	else
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
286
287
  		imx_dmav1_writel(imxdma, sg->dma_address,
  				 DMA_SAR(imxdmac->channel));
6bd081277   Javier Martin   dmaengine: imx-dm...
288

cd5cf9da0   Javier Martin   dmaengine: imx-dm...
289
  	imx_dmav1_writel(imxdma, now, DMA_CNTR(imxdmac->channel));
6bd081277   Javier Martin   dmaengine: imx-dm...
290

f9b283a6e   Javier Martin   dmaengine: imx-dm...
291
292
293
  	dev_dbg(imxdma->dev, " %s channel: %d dst 0x%08x, src 0x%08x, "
  		"size 0x%08x
  ", __func__, imxdmac->channel,
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
294
295
296
  		 imx_dmav1_readl(imxdma, DMA_DAR(imxdmac->channel)),
  		 imx_dmav1_readl(imxdma, DMA_SAR(imxdmac->channel)),
  		 imx_dmav1_readl(imxdma, DMA_CNTR(imxdmac->channel)));
6bd081277   Javier Martin   dmaengine: imx-dm...
297
298
  
  	return now;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
299
  }
2efc3449d   Javier Martin   dmaengine: imx-dm...
300
  static void imxdma_enable_hw(struct imxdma_desc *d)
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
301
  {
2efc3449d   Javier Martin   dmaengine: imx-dm...
302
  	struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
303
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
6bd081277   Javier Martin   dmaengine: imx-dm...
304
305
  	int channel = imxdmac->channel;
  	unsigned long flags;
f9b283a6e   Javier Martin   dmaengine: imx-dm...
306
307
  	dev_dbg(imxdma->dev, "%s channel %d
  ", __func__, channel);
6bd081277   Javier Martin   dmaengine: imx-dm...
308

6bd081277   Javier Martin   dmaengine: imx-dm...
309
  	local_irq_save(flags);
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
310
311
312
313
314
  	imx_dmav1_writel(imxdma, 1 << channel, DMA_DISR);
  	imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_DIMR) &
  			 ~(1 << channel), DMA_DIMR);
  	imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_CCR(channel)) |
  			 CCR_CEN | CCR_ACRPT, DMA_CCR(channel));
6bd081277   Javier Martin   dmaengine: imx-dm...
315

e51d0f0ac   Shawn Guo   dma: imx-dma: rem...
316
  	if (!is_imx1_dma(imxdma) &&
2d9c2fc59   Javier Martin   dmaengine: imx-dm...
317
  			d->sg && imxdma_hw_chain(imxdmac)) {
833bc03bf   Javier Martin   dmaengine: imx-dm...
318
319
  		d->sg = sg_next(d->sg);
  		if (d->sg) {
6bd081277   Javier Martin   dmaengine: imx-dm...
320
  			u32 tmp;
a6cbb2d87   Javier Martin   dmaengine: imx-dm...
321
  			imxdma_sg_next(d);
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
322
323
324
  			tmp = imx_dmav1_readl(imxdma, DMA_CCR(channel));
  			imx_dmav1_writel(imxdma, tmp | CCR_RPT | CCR_ACRPT,
  					 DMA_CCR(channel));
6bd081277   Javier Martin   dmaengine: imx-dm...
325
326
  		}
  	}
6bd081277   Javier Martin   dmaengine: imx-dm...
327
328
329
330
331
332
  
  	local_irq_restore(flags);
  }
  
  static void imxdma_disable_hw(struct imxdma_channel *imxdmac)
  {
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
333
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
6bd081277   Javier Martin   dmaengine: imx-dm...
334
335
  	int channel = imxdmac->channel;
  	unsigned long flags;
f9b283a6e   Javier Martin   dmaengine: imx-dm...
336
337
  	dev_dbg(imxdma->dev, "%s channel %d
  ", __func__, channel);
6bd081277   Javier Martin   dmaengine: imx-dm...
338

2d9c2fc59   Javier Martin   dmaengine: imx-dm...
339
340
  	if (imxdma_hw_chain(imxdmac))
  		del_timer(&imxdmac->watchdog);
6bd081277   Javier Martin   dmaengine: imx-dm...
341
342
  
  	local_irq_save(flags);
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
343
344
345
346
347
  	imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_DIMR) |
  			 (1 << channel), DMA_DIMR);
  	imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_CCR(channel)) &
  			 ~CCR_CEN, DMA_CCR(channel));
  	imx_dmav1_writel(imxdma, 1 << channel, DMA_DISR);
6bd081277   Javier Martin   dmaengine: imx-dm...
348
349
  	local_irq_restore(flags);
  }
6bd081277   Javier Martin   dmaengine: imx-dm...
350
  static void imxdma_watchdog(unsigned long data)
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
351
  {
6bd081277   Javier Martin   dmaengine: imx-dm...
352
  	struct imxdma_channel *imxdmac = (struct imxdma_channel *)data;
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
353
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
6bd081277   Javier Martin   dmaengine: imx-dm...
354
  	int channel = imxdmac->channel;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
355

cd5cf9da0   Javier Martin   dmaengine: imx-dm...
356
  	imx_dmav1_writel(imxdma, 0, DMA_CCR(channel));
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
357

6bd081277   Javier Martin   dmaengine: imx-dm...
358
  	/* Tasklet watchdog error handler */
9e15db7ce   Javier Martin   dmaengine: Add su...
359
  	tasklet_schedule(&imxdmac->dma_tasklet);
f9b283a6e   Javier Martin   dmaengine: imx-dm...
360
361
362
  	dev_dbg(imxdma->dev, "channel %d: watchdog timeout!
  ",
  		imxdmac->channel);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
363
  }
6bd081277   Javier Martin   dmaengine: imx-dm...
364
  static irqreturn_t imxdma_err_handler(int irq, void *dev_id)
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
365
  {
6bd081277   Javier Martin   dmaengine: imx-dm...
366
  	struct imxdma_engine *imxdma = dev_id;
6bd081277   Javier Martin   dmaengine: imx-dm...
367
368
369
  	unsigned int err_mask;
  	int i, disr;
  	int errcode;
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
370
  	disr = imx_dmav1_readl(imxdma, DMA_DISR);
6bd081277   Javier Martin   dmaengine: imx-dm...
371

cd5cf9da0   Javier Martin   dmaengine: imx-dm...
372
373
374
375
  	err_mask = imx_dmav1_readl(imxdma, DMA_DBTOSR) |
  		   imx_dmav1_readl(imxdma, DMA_DRTOSR) |
  		   imx_dmav1_readl(imxdma, DMA_DSESR)  |
  		   imx_dmav1_readl(imxdma, DMA_DBOSR);
6bd081277   Javier Martin   dmaengine: imx-dm...
376
377
378
  
  	if (!err_mask)
  		return IRQ_HANDLED;
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
379
  	imx_dmav1_writel(imxdma, disr & err_mask, DMA_DISR);
6bd081277   Javier Martin   dmaengine: imx-dm...
380
381
382
383
  
  	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
  		if (!(err_mask & (1 << i)))
  			continue;
6bd081277   Javier Martin   dmaengine: imx-dm...
384
  		errcode = 0;
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
385
386
  		if (imx_dmav1_readl(imxdma, DMA_DBTOSR) & (1 << i)) {
  			imx_dmav1_writel(imxdma, 1 << i, DMA_DBTOSR);
6bd081277   Javier Martin   dmaengine: imx-dm...
387
388
  			errcode |= IMX_DMA_ERR_BURST;
  		}
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
389
390
  		if (imx_dmav1_readl(imxdma, DMA_DRTOSR) & (1 << i)) {
  			imx_dmav1_writel(imxdma, 1 << i, DMA_DRTOSR);
6bd081277   Javier Martin   dmaengine: imx-dm...
391
392
  			errcode |= IMX_DMA_ERR_REQUEST;
  		}
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
393
394
  		if (imx_dmav1_readl(imxdma, DMA_DSESR) & (1 << i)) {
  			imx_dmav1_writel(imxdma, 1 << i, DMA_DSESR);
6bd081277   Javier Martin   dmaengine: imx-dm...
395
396
  			errcode |= IMX_DMA_ERR_TRANSFER;
  		}
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
397
398
  		if (imx_dmav1_readl(imxdma, DMA_DBOSR) & (1 << i)) {
  			imx_dmav1_writel(imxdma, 1 << i, DMA_DBOSR);
6bd081277   Javier Martin   dmaengine: imx-dm...
399
400
401
402
  			errcode |= IMX_DMA_ERR_BUFFER;
  		}
  		/* Tasklet error handler */
  		tasklet_schedule(&imxdma->channel[i].dma_tasklet);
1d94fe060   Alexander Shiyan   dma: imx-dma: Rep...
403
404
405
406
407
408
409
  		dev_warn(imxdma->dev,
  			 "DMA timeout on channel %d -%s%s%s%s
  ", i,
  			 errcode & IMX_DMA_ERR_BURST ?    " burst" : "",
  			 errcode & IMX_DMA_ERR_REQUEST ?  " request" : "",
  			 errcode & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
  			 errcode & IMX_DMA_ERR_BUFFER ?   " buffer" : "");
6bd081277   Javier Martin   dmaengine: imx-dm...
410
411
  	}
  	return IRQ_HANDLED;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
412
  }
6bd081277   Javier Martin   dmaengine: imx-dm...
413
  static void dma_irq_handle_channel(struct imxdma_channel *imxdmac)
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
414
  {
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
415
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
6bd081277   Javier Martin   dmaengine: imx-dm...
416
  	int chno = imxdmac->channel;
2efc3449d   Javier Martin   dmaengine: imx-dm...
417
  	struct imxdma_desc *desc;
5a276fa6b   Michael Grzeschik   dmaengine: imx-dm...
418
  	unsigned long flags;
6bd081277   Javier Martin   dmaengine: imx-dm...
419

5a276fa6b   Michael Grzeschik   dmaengine: imx-dm...
420
  	spin_lock_irqsave(&imxdma->lock, flags);
833bc03bf   Javier Martin   dmaengine: imx-dm...
421
  	if (list_empty(&imxdmac->ld_active)) {
5a276fa6b   Michael Grzeschik   dmaengine: imx-dm...
422
  		spin_unlock_irqrestore(&imxdma->lock, flags);
833bc03bf   Javier Martin   dmaengine: imx-dm...
423
424
  		goto out;
  	}
2efc3449d   Javier Martin   dmaengine: imx-dm...
425

833bc03bf   Javier Martin   dmaengine: imx-dm...
426
427
428
  	desc = list_first_entry(&imxdmac->ld_active,
  				struct imxdma_desc,
  				node);
5a276fa6b   Michael Grzeschik   dmaengine: imx-dm...
429
  	spin_unlock_irqrestore(&imxdma->lock, flags);
2efc3449d   Javier Martin   dmaengine: imx-dm...
430

833bc03bf   Javier Martin   dmaengine: imx-dm...
431
432
433
  	if (desc->sg) {
  		u32 tmp;
  		desc->sg = sg_next(desc->sg);
2efc3449d   Javier Martin   dmaengine: imx-dm...
434

833bc03bf   Javier Martin   dmaengine: imx-dm...
435
  		if (desc->sg) {
a6cbb2d87   Javier Martin   dmaengine: imx-dm...
436
  			imxdma_sg_next(desc);
6bd081277   Javier Martin   dmaengine: imx-dm...
437

cd5cf9da0   Javier Martin   dmaengine: imx-dm...
438
  			tmp = imx_dmav1_readl(imxdma, DMA_CCR(chno));
6bd081277   Javier Martin   dmaengine: imx-dm...
439

2d9c2fc59   Javier Martin   dmaengine: imx-dm...
440
  			if (imxdma_hw_chain(imxdmac)) {
6bd081277   Javier Martin   dmaengine: imx-dm...
441
442
443
  				/* FIXME: The timeout should probably be
  				 * configurable
  				 */
2d9c2fc59   Javier Martin   dmaengine: imx-dm...
444
  				mod_timer(&imxdmac->watchdog,
6bd081277   Javier Martin   dmaengine: imx-dm...
445
446
447
  					jiffies + msecs_to_jiffies(500));
  
  				tmp |= CCR_CEN | CCR_RPT | CCR_ACRPT;
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
448
  				imx_dmav1_writel(imxdma, tmp, DMA_CCR(chno));
6bd081277   Javier Martin   dmaengine: imx-dm...
449
  			} else {
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
450
451
  				imx_dmav1_writel(imxdma, tmp & ~CCR_CEN,
  						 DMA_CCR(chno));
6bd081277   Javier Martin   dmaengine: imx-dm...
452
453
  				tmp |= CCR_CEN;
  			}
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
454
  			imx_dmav1_writel(imxdma, tmp, DMA_CCR(chno));
6bd081277   Javier Martin   dmaengine: imx-dm...
455
456
457
458
  
  			if (imxdma_chan_is_doing_cyclic(imxdmac))
  				/* Tasklet progression */
  				tasklet_schedule(&imxdmac->dma_tasklet);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
459

6bd081277   Javier Martin   dmaengine: imx-dm...
460
461
  			return;
  		}
2d9c2fc59   Javier Martin   dmaengine: imx-dm...
462
463
  		if (imxdma_hw_chain(imxdmac)) {
  			del_timer(&imxdmac->watchdog);
6bd081277   Javier Martin   dmaengine: imx-dm...
464
465
466
  			return;
  		}
  	}
2efc3449d   Javier Martin   dmaengine: imx-dm...
467
  out:
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
468
  	imx_dmav1_writel(imxdma, 0, DMA_CCR(chno));
6bd081277   Javier Martin   dmaengine: imx-dm...
469
  	/* Tasklet irq */
9e15db7ce   Javier Martin   dmaengine: Add su...
470
471
  	tasklet_schedule(&imxdmac->dma_tasklet);
  }
6bd081277   Javier Martin   dmaengine: imx-dm...
472
473
474
  static irqreturn_t dma_irq_handler(int irq, void *dev_id)
  {
  	struct imxdma_engine *imxdma = dev_id;
6bd081277   Javier Martin   dmaengine: imx-dm...
475
  	int i, disr;
e51d0f0ac   Shawn Guo   dma: imx-dma: rem...
476
  	if (!is_imx1_dma(imxdma))
6bd081277   Javier Martin   dmaengine: imx-dm...
477
  		imxdma_err_handler(irq, dev_id);
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
478
  	disr = imx_dmav1_readl(imxdma, DMA_DISR);
6bd081277   Javier Martin   dmaengine: imx-dm...
479

f9b283a6e   Javier Martin   dmaengine: imx-dm...
480
481
  	dev_dbg(imxdma->dev, "%s called, disr=0x%08x
  ", __func__, disr);
6bd081277   Javier Martin   dmaengine: imx-dm...
482

cd5cf9da0   Javier Martin   dmaengine: imx-dm...
483
  	imx_dmav1_writel(imxdma, disr, DMA_DISR);
6bd081277   Javier Martin   dmaengine: imx-dm...
484
  	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
2d9c2fc59   Javier Martin   dmaengine: imx-dm...
485
  		if (disr & (1 << i))
6bd081277   Javier Martin   dmaengine: imx-dm...
486
  			dma_irq_handle_channel(&imxdma->channel[i]);
6bd081277   Javier Martin   dmaengine: imx-dm...
487
488
489
490
  	}
  
  	return IRQ_HANDLED;
  }
9e15db7ce   Javier Martin   dmaengine: Add su...
491
492
493
  static int imxdma_xfer_desc(struct imxdma_desc *d)
  {
  	struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
3b4b6dfc2   Javier Martin   dmaengine: imx-dm...
494
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
f606ab897   Javier Martin   dmaengine: i.MX: ...
495
496
  	int slot = -1;
  	int i;
9e15db7ce   Javier Martin   dmaengine: Add su...
497
498
499
  
  	/* Configure and enable */
  	switch (d->type) {
f606ab897   Javier Martin   dmaengine: i.MX: ...
500
501
  	case IMXDMA_DESC_INTERLEAVED:
  		/* Try to get a free 2D slot */
f606ab897   Javier Martin   dmaengine: i.MX: ...
502
503
504
505
506
507
508
509
510
  		for (i = 0; i < IMX_DMA_2D_SLOTS; i++) {
  			if ((imxdma->slots_2d[i].count > 0) &&
  			((imxdma->slots_2d[i].xsr != d->x) ||
  			(imxdma->slots_2d[i].ysr != d->y) ||
  			(imxdma->slots_2d[i].wsr != d->w)))
  				continue;
  			slot = i;
  			break;
  		}
5a276fa6b   Michael Grzeschik   dmaengine: imx-dm...
511
  		if (slot < 0)
f606ab897   Javier Martin   dmaengine: i.MX: ...
512
513
514
515
516
517
518
519
520
  			return -EBUSY;
  
  		imxdma->slots_2d[slot].xsr = d->x;
  		imxdma->slots_2d[slot].ysr = d->y;
  		imxdma->slots_2d[slot].wsr = d->w;
  		imxdma->slots_2d[slot].count++;
  
  		imxdmac->slot_2d = slot;
  		imxdmac->enabled_2d = true;
f606ab897   Javier Martin   dmaengine: i.MX: ...
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
  
  		if (slot == IMX_DMA_2D_SLOT_A) {
  			d->config_mem &= ~CCR_MSEL_B;
  			d->config_port &= ~CCR_MSEL_B;
  			imx_dmav1_writel(imxdma, d->x, DMA_XSRA);
  			imx_dmav1_writel(imxdma, d->y, DMA_YSRA);
  			imx_dmav1_writel(imxdma, d->w, DMA_WSRA);
  		} else {
  			d->config_mem |= CCR_MSEL_B;
  			d->config_port |= CCR_MSEL_B;
  			imx_dmav1_writel(imxdma, d->x, DMA_XSRB);
  			imx_dmav1_writel(imxdma, d->y, DMA_YSRB);
  			imx_dmav1_writel(imxdma, d->w, DMA_WSRB);
  		}
  		/*
  		 * We fall-through here intentionally, since a 2D transfer is
  		 * similar to MEMCPY just adding the 2D slot configuration.
  		 */
9e15db7ce   Javier Martin   dmaengine: Add su...
539
  	case IMXDMA_DESC_MEMCPY:
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
540
541
542
  		imx_dmav1_writel(imxdma, d->src, DMA_SAR(imxdmac->channel));
  		imx_dmav1_writel(imxdma, d->dest, DMA_DAR(imxdmac->channel));
  		imx_dmav1_writel(imxdma, d->config_mem | (d->config_port << 2),
3b4b6dfc2   Javier Martin   dmaengine: imx-dm...
543
  			 DMA_CCR(imxdmac->channel));
6bd081277   Javier Martin   dmaengine: imx-dm...
544

cd5cf9da0   Javier Martin   dmaengine: imx-dm...
545
  		imx_dmav1_writel(imxdma, d->len, DMA_CNTR(imxdmac->channel));
3b4b6dfc2   Javier Martin   dmaengine: imx-dm...
546

ac806a1c8   Russell King   dmaengine: imx-dm...
547
548
549
550
551
552
  		dev_dbg(imxdma->dev,
  			"%s channel: %d dest=0x%08llx src=0x%08llx dma_length=%zu
  ",
  			__func__, imxdmac->channel,
  			(unsigned long long)d->dest,
  			(unsigned long long)d->src, d->len);
3b4b6dfc2   Javier Martin   dmaengine: imx-dm...
553
554
  
  		break;
6bd081277   Javier Martin   dmaengine: imx-dm...
555
  	/* Cyclic transfer is the same as slave_sg with special sg configuration. */
9e15db7ce   Javier Martin   dmaengine: Add su...
556
  	case IMXDMA_DESC_CYCLIC:
9e15db7ce   Javier Martin   dmaengine: Add su...
557
  	case IMXDMA_DESC_SLAVE_SG:
359291a1a   Javier Martin   dmaengine: imx-dm...
558
  		if (d->direction == DMA_DEV_TO_MEM) {
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
559
  			imx_dmav1_writel(imxdma, imxdmac->per_address,
359291a1a   Javier Martin   dmaengine: imx-dm...
560
  					 DMA_SAR(imxdmac->channel));
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
561
  			imx_dmav1_writel(imxdma, imxdmac->ccr_from_device,
359291a1a   Javier Martin   dmaengine: imx-dm...
562
  					 DMA_CCR(imxdmac->channel));
ac806a1c8   Russell King   dmaengine: imx-dm...
563
564
565
566
567
568
  			dev_dbg(imxdma->dev,
  				"%s channel: %d sg=%p sgcount=%d total length=%zu dev_addr=0x%08llx (dev2mem)
  ",
  				__func__, imxdmac->channel,
  				d->sg, d->sgcount, d->len,
  				(unsigned long long)imxdmac->per_address);
359291a1a   Javier Martin   dmaengine: imx-dm...
569
  		} else if (d->direction == DMA_MEM_TO_DEV) {
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
570
  			imx_dmav1_writel(imxdma, imxdmac->per_address,
359291a1a   Javier Martin   dmaengine: imx-dm...
571
  					 DMA_DAR(imxdmac->channel));
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
572
  			imx_dmav1_writel(imxdma, imxdmac->ccr_to_device,
359291a1a   Javier Martin   dmaengine: imx-dm...
573
  					 DMA_CCR(imxdmac->channel));
ac806a1c8   Russell King   dmaengine: imx-dm...
574
575
576
577
578
579
  			dev_dbg(imxdma->dev,
  				"%s channel: %d sg=%p sgcount=%d total length=%zu dev_addr=0x%08llx (mem2dev)
  ",
  				__func__, imxdmac->channel,
  				d->sg, d->sgcount, d->len,
  				(unsigned long long)imxdmac->per_address);
359291a1a   Javier Martin   dmaengine: imx-dm...
580
581
582
583
584
585
  		} else {
  			dev_err(imxdma->dev, "%s channel: %d bad dma mode
  ",
  				__func__, imxdmac->channel);
  			return -EINVAL;
  		}
a6cbb2d87   Javier Martin   dmaengine: imx-dm...
586
  		imxdma_sg_next(d);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
587

9e15db7ce   Javier Martin   dmaengine: Add su...
588
589
590
591
  		break;
  	default:
  		return -EINVAL;
  	}
2efc3449d   Javier Martin   dmaengine: imx-dm...
592
  	imxdma_enable_hw(d);
9e15db7ce   Javier Martin   dmaengine: Add su...
593
  	return 0;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
594
  }
9e15db7ce   Javier Martin   dmaengine: Add su...
595
  static void imxdma_tasklet(unsigned long data)
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
596
  {
9e15db7ce   Javier Martin   dmaengine: Add su...
597
598
599
  	struct imxdma_channel *imxdmac = (void *)data;
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
  	struct imxdma_desc *desc;
5a276fa6b   Michael Grzeschik   dmaengine: imx-dm...
600
  	unsigned long flags;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
601

5a276fa6b   Michael Grzeschik   dmaengine: imx-dm...
602
  	spin_lock_irqsave(&imxdma->lock, flags);
9e15db7ce   Javier Martin   dmaengine: Add su...
603
604
605
  
  	if (list_empty(&imxdmac->ld_active)) {
  		/* Someone might have called terminate all */
fcaaba6c7   Michael Grzeschik   dmaengine: imx-dm...
606
607
  		spin_unlock_irqrestore(&imxdma->lock, flags);
  		return;
9e15db7ce   Javier Martin   dmaengine: Add su...
608
609
  	}
  	desc = list_first_entry(&imxdmac->ld_active, struct imxdma_desc, node);
d73111c6d   Masanari Iida   dma: fix comments
610
611
  	/* If we are dealing with a cyclic descriptor, keep it on ld_active
  	 * and dont mark the descriptor as complete.
60f2951e3   Vinod Koul   dmaengine: imx-dm...
612
613
  	 * Only in non-cyclic cases it would be marked as complete
  	 */
9e15db7ce   Javier Martin   dmaengine: Add su...
614
615
  	if (imxdma_chan_is_doing_cyclic(imxdmac))
  		goto out;
60f2951e3   Vinod Koul   dmaengine: imx-dm...
616
617
  	else
  		dma_cookie_complete(&desc->desc);
9e15db7ce   Javier Martin   dmaengine: Add su...
618

f606ab897   Javier Martin   dmaengine: i.MX: ...
619
620
621
622
623
  	/* Free 2D slot if it was an interleaved transfer */
  	if (imxdmac->enabled_2d) {
  		imxdma->slots_2d[imxdmac->slot_2d].count--;
  		imxdmac->enabled_2d = false;
  	}
9e15db7ce   Javier Martin   dmaengine: Add su...
624
625
626
627
628
629
630
631
632
633
634
635
  	list_move_tail(imxdmac->ld_active.next, &imxdmac->ld_free);
  
  	if (!list_empty(&imxdmac->ld_queue)) {
  		desc = list_first_entry(&imxdmac->ld_queue, struct imxdma_desc,
  					node);
  		list_move_tail(imxdmac->ld_queue.next, &imxdmac->ld_active);
  		if (imxdma_xfer_desc(desc) < 0)
  			dev_warn(imxdma->dev, "%s: channel: %d couldn't xfer desc
  ",
  				 __func__, imxdmac->channel);
  	}
  out:
5a276fa6b   Michael Grzeschik   dmaengine: imx-dm...
636
  	spin_unlock_irqrestore(&imxdma->lock, flags);
fcaaba6c7   Michael Grzeschik   dmaengine: imx-dm...
637
638
639
  
  	if (desc->desc.callback)
  		desc->desc.callback(desc->desc.callback_param);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
640
641
642
643
644
645
646
  }
  
  static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
  		unsigned long arg)
  {
  	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
  	struct dma_slave_config *dmaengine_cfg = (void *)arg;
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
647
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
9e15db7ce   Javier Martin   dmaengine: Add su...
648
  	unsigned long flags;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
649
650
651
652
  	unsigned int mode = 0;
  
  	switch (cmd) {
  	case DMA_TERMINATE_ALL:
6bd081277   Javier Martin   dmaengine: imx-dm...
653
  		imxdma_disable_hw(imxdmac);
9e15db7ce   Javier Martin   dmaengine: Add su...
654

f606ab897   Javier Martin   dmaengine: i.MX: ...
655
  		spin_lock_irqsave(&imxdma->lock, flags);
9e15db7ce   Javier Martin   dmaengine: Add su...
656
657
  		list_splice_tail_init(&imxdmac->ld_active, &imxdmac->ld_free);
  		list_splice_tail_init(&imxdmac->ld_queue, &imxdmac->ld_free);
f606ab897   Javier Martin   dmaengine: i.MX: ...
658
  		spin_unlock_irqrestore(&imxdma->lock, flags);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
659
660
  		return 0;
  	case DMA_SLAVE_CONFIG:
db8196df4   Vinod Koul   dmaengine: move d...
661
  		if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
  			imxdmac->per_address = dmaengine_cfg->src_addr;
  			imxdmac->watermark_level = dmaengine_cfg->src_maxburst;
  			imxdmac->word_size = dmaengine_cfg->src_addr_width;
  		} else {
  			imxdmac->per_address = dmaengine_cfg->dst_addr;
  			imxdmac->watermark_level = dmaengine_cfg->dst_maxburst;
  			imxdmac->word_size = dmaengine_cfg->dst_addr_width;
  		}
  
  		switch (imxdmac->word_size) {
  		case DMA_SLAVE_BUSWIDTH_1_BYTE:
  			mode = IMX_DMA_MEMSIZE_8;
  			break;
  		case DMA_SLAVE_BUSWIDTH_2_BYTES:
  			mode = IMX_DMA_MEMSIZE_16;
  			break;
  		default:
  		case DMA_SLAVE_BUSWIDTH_4_BYTES:
  			mode = IMX_DMA_MEMSIZE_32;
  			break;
  		}
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
683

bef2a8d3f   Javier Martin   dmaengine: imx-dm...
684
  		imxdmac->hw_chaining = 0;
359291a1a   Javier Martin   dmaengine: imx-dm...
685
  		imxdmac->ccr_from_device = (mode | IMX_DMA_TYPE_FIFO) |
bdc0c7534   Javier Martin   dmaengine: imx-dm...
686
687
  			((IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR) << 2) |
  			CCR_REN;
359291a1a   Javier Martin   dmaengine: imx-dm...
688
  		imxdmac->ccr_to_device =
bdc0c7534   Javier Martin   dmaengine: imx-dm...
689
690
  			(IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR) |
  			((mode | IMX_DMA_TYPE_FIFO) << 2) | CCR_REN;
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
691
  		imx_dmav1_writel(imxdma, imxdmac->dma_request,
bdc0c7534   Javier Martin   dmaengine: imx-dm...
692
  				 DMA_RSSR(imxdmac->channel));
6bd081277   Javier Martin   dmaengine: imx-dm...
693
  		/* Set burst length */
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
694
695
  		imx_dmav1_writel(imxdma, imxdmac->watermark_level *
  				imxdmac->word_size, DMA_BLR(imxdmac->channel));
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
696
697
698
699
700
701
702
703
704
705
706
707
708
  
  		return 0;
  	default:
  		return -ENOSYS;
  	}
  
  	return -EINVAL;
  }
  
  static enum dma_status imxdma_tx_status(struct dma_chan *chan,
  					    dma_cookie_t cookie,
  					    struct dma_tx_state *txstate)
  {
96a2af41c   Russell King - ARM Linux   dmaengine: consol...
709
  	return dma_cookie_status(chan, cookie, txstate);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
710
711
712
713
714
  }
  
  static dma_cookie_t imxdma_tx_submit(struct dma_async_tx_descriptor *tx)
  {
  	struct imxdma_channel *imxdmac = to_imxdma_chan(tx->chan);
f606ab897   Javier Martin   dmaengine: i.MX: ...
715
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
716
  	dma_cookie_t cookie;
9e15db7ce   Javier Martin   dmaengine: Add su...
717
  	unsigned long flags;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
718

f606ab897   Javier Martin   dmaengine: i.MX: ...
719
  	spin_lock_irqsave(&imxdma->lock, flags);
660cd0dd9   Javier Martin   dmaengine: i.MX: ...
720
  	list_move_tail(imxdmac->ld_free.next, &imxdmac->ld_queue);
884485e1f   Russell King - ARM Linux   dmaengine: consol...
721
  	cookie = dma_cookie_assign(tx);
f606ab897   Javier Martin   dmaengine: i.MX: ...
722
  	spin_unlock_irqrestore(&imxdma->lock, flags);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
723
724
725
726
727
728
729
730
  
  	return cookie;
  }
  
  static int imxdma_alloc_chan_resources(struct dma_chan *chan)
  {
  	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
  	struct imx_dma_data *data = chan->private;
6c05f0915   Javier Martin   dmaengine: Add su...
731
732
  	if (data != NULL)
  		imxdmac->dma_request = data->dma_request;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
733

9e15db7ce   Javier Martin   dmaengine: Add su...
734
735
  	while (imxdmac->descs_allocated < IMXDMA_MAX_CHAN_DESCRIPTORS) {
  		struct imxdma_desc *desc;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
736

9e15db7ce   Javier Martin   dmaengine: Add su...
737
738
739
740
741
742
743
744
  		desc = kzalloc(sizeof(*desc), GFP_KERNEL);
  		if (!desc)
  			break;
  		__memzero(&desc->desc, sizeof(struct dma_async_tx_descriptor));
  		dma_async_tx_descriptor_init(&desc->desc, chan);
  		desc->desc.tx_submit = imxdma_tx_submit;
  		/* txd.flags will be overwritten in prep funcs */
  		desc->desc.flags = DMA_CTRL_ACK;
3ded1ad14   Vinod Koul   dmaengine: imx-dm...
745
  		desc->status = DMA_COMPLETE;
9e15db7ce   Javier Martin   dmaengine: Add su...
746
747
748
749
  
  		list_add_tail(&desc->node, &imxdmac->ld_free);
  		imxdmac->descs_allocated++;
  	}
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
750

9e15db7ce   Javier Martin   dmaengine: Add su...
751
752
753
754
  	if (!imxdmac->descs_allocated)
  		return -ENOMEM;
  
  	return imxdmac->descs_allocated;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
755
756
757
758
759
  }
  
  static void imxdma_free_chan_resources(struct dma_chan *chan)
  {
  	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
f606ab897   Javier Martin   dmaengine: i.MX: ...
760
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
9e15db7ce   Javier Martin   dmaengine: Add su...
761
762
  	struct imxdma_desc *desc, *_desc;
  	unsigned long flags;
f606ab897   Javier Martin   dmaengine: i.MX: ...
763
  	spin_lock_irqsave(&imxdma->lock, flags);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
764

6bd081277   Javier Martin   dmaengine: imx-dm...
765
  	imxdma_disable_hw(imxdmac);
9e15db7ce   Javier Martin   dmaengine: Add su...
766
767
  	list_splice_tail_init(&imxdmac->ld_active, &imxdmac->ld_free);
  	list_splice_tail_init(&imxdmac->ld_queue, &imxdmac->ld_free);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
768

f606ab897   Javier Martin   dmaengine: i.MX: ...
769
  	spin_unlock_irqrestore(&imxdma->lock, flags);
9e15db7ce   Javier Martin   dmaengine: Add su...
770
771
772
773
774
775
  
  	list_for_each_entry_safe(desc, _desc, &imxdmac->ld_free, node) {
  		kfree(desc);
  		imxdmac->descs_allocated--;
  	}
  	INIT_LIST_HEAD(&imxdmac->ld_free);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
776

06f8db4b6   Sachin Kamat   dma: imx-dma: Rem...
777
778
  	kfree(imxdmac->sg_list);
  	imxdmac->sg_list = NULL;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
779
780
781
782
  }
  
  static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
  		struct dma_chan *chan, struct scatterlist *sgl,
db8196df4   Vinod Koul   dmaengine: move d...
783
  		unsigned int sg_len, enum dma_transfer_direction direction,
185ecb5f4   Alexandre Bounine   dmaengine: add co...
784
  		unsigned long flags, void *context)
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
785
786
787
  {
  	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
  	struct scatterlist *sg;
9e15db7ce   Javier Martin   dmaengine: Add su...
788
789
  	int i, dma_length = 0;
  	struct imxdma_desc *desc;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
790

9e15db7ce   Javier Martin   dmaengine: Add su...
791
792
  	if (list_empty(&imxdmac->ld_free) ||
  	    imxdma_chan_is_doing_cyclic(imxdmac))
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
793
  		return NULL;
9e15db7ce   Javier Martin   dmaengine: Add su...
794
  	desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
795
796
  
  	for_each_sg(sgl, sg, sg_len, i) {
fdaf9c4b2   Lars-Peter Clausen   dmaengine: Use dm...
797
  		dma_length += sg_dma_len(sg);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
798
  	}
d07102a1b   Sascha Hauer   dmaengine i.MX dm...
799
800
  	switch (imxdmac->word_size) {
  	case DMA_SLAVE_BUSWIDTH_4_BYTES:
fdaf9c4b2   Lars-Peter Clausen   dmaengine: Use dm...
801
  		if (sg_dma_len(sgl) & 3 || sgl->dma_address & 3)
d07102a1b   Sascha Hauer   dmaengine i.MX dm...
802
803
804
  			return NULL;
  		break;
  	case DMA_SLAVE_BUSWIDTH_2_BYTES:
fdaf9c4b2   Lars-Peter Clausen   dmaengine: Use dm...
805
  		if (sg_dma_len(sgl) & 1 || sgl->dma_address & 1)
d07102a1b   Sascha Hauer   dmaengine i.MX dm...
806
807
808
809
810
811
812
  			return NULL;
  		break;
  	case DMA_SLAVE_BUSWIDTH_1_BYTE:
  		break;
  	default:
  		return NULL;
  	}
9e15db7ce   Javier Martin   dmaengine: Add su...
813
814
815
816
  	desc->type = IMXDMA_DESC_SLAVE_SG;
  	desc->sg = sgl;
  	desc->sgcount = sg_len;
  	desc->len = dma_length;
2efc3449d   Javier Martin   dmaengine: imx-dm...
817
  	desc->direction = direction;
9e15db7ce   Javier Martin   dmaengine: Add su...
818
  	if (direction == DMA_DEV_TO_MEM) {
9e15db7ce   Javier Martin   dmaengine: Add su...
819
820
  		desc->src = imxdmac->per_address;
  	} else {
9e15db7ce   Javier Martin   dmaengine: Add su...
821
822
823
824
  		desc->dest = imxdmac->per_address;
  	}
  	desc->desc.callback = NULL;
  	desc->desc.callback_param = NULL;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
825

9e15db7ce   Javier Martin   dmaengine: Add su...
826
  	return &desc->desc;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
827
828
829
830
  }
  
  static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
  		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
185ecb5f4   Alexandre Bounine   dmaengine: add co...
831
  		size_t period_len, enum dma_transfer_direction direction,
ec8b5e48c   Peter Ujfalusi   dmaengine: Pass f...
832
  		unsigned long flags, void *context)
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
833
834
835
  {
  	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
9e15db7ce   Javier Martin   dmaengine: Add su...
836
837
  	struct imxdma_desc *desc;
  	int i;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
838
  	unsigned int periods = buf_len / period_len;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
839

ac806a1c8   Russell King   dmaengine: imx-dm...
840
841
  	dev_dbg(imxdma->dev, "%s channel: %d buf_len=%zu period_len=%zu
  ",
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
842
  			__func__, imxdmac->channel, buf_len, period_len);
9e15db7ce   Javier Martin   dmaengine: Add su...
843
844
  	if (list_empty(&imxdmac->ld_free) ||
  	    imxdma_chan_is_doing_cyclic(imxdmac))
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
845
  		return NULL;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
846

9e15db7ce   Javier Martin   dmaengine: Add su...
847
  	desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
848

96a3713eb   Syam Sidhardhan   dma: imx-dma: Rem...
849
  	kfree(imxdmac->sg_list);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
850
851
  
  	imxdmac->sg_list = kcalloc(periods + 1,
edc530fe7   Michael Grzeschik   dmaengine: imx-dm...
852
  			sizeof(struct scatterlist), GFP_ATOMIC);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
853
854
855
856
857
858
859
860
861
  	if (!imxdmac->sg_list)
  		return NULL;
  
  	sg_init_table(imxdmac->sg_list, periods);
  
  	for (i = 0; i < periods; i++) {
  		imxdmac->sg_list[i].page_link = 0;
  		imxdmac->sg_list[i].offset = 0;
  		imxdmac->sg_list[i].dma_address = dma_addr;
fdaf9c4b2   Lars-Peter Clausen   dmaengine: Use dm...
862
  		sg_dma_len(&imxdmac->sg_list[i]) = period_len;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
863
864
865
866
867
  		dma_addr += period_len;
  	}
  
  	/* close the loop */
  	imxdmac->sg_list[periods].offset = 0;
fdaf9c4b2   Lars-Peter Clausen   dmaengine: Use dm...
868
  	sg_dma_len(&imxdmac->sg_list[periods]) = 0;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
869
870
  	imxdmac->sg_list[periods].page_link =
  		((unsigned long)imxdmac->sg_list | 0x01) & ~0x02;
9e15db7ce   Javier Martin   dmaengine: Add su...
871
872
873
874
  	desc->type = IMXDMA_DESC_CYCLIC;
  	desc->sg = imxdmac->sg_list;
  	desc->sgcount = periods;
  	desc->len = IMX_DMA_LENGTH_LOOP;
2efc3449d   Javier Martin   dmaengine: imx-dm...
875
  	desc->direction = direction;
9e15db7ce   Javier Martin   dmaengine: Add su...
876
  	if (direction == DMA_DEV_TO_MEM) {
9e15db7ce   Javier Martin   dmaengine: Add su...
877
878
  		desc->src = imxdmac->per_address;
  	} else {
9e15db7ce   Javier Martin   dmaengine: Add su...
879
880
881
882
  		desc->dest = imxdmac->per_address;
  	}
  	desc->desc.callback = NULL;
  	desc->desc.callback_param = NULL;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
883

9e15db7ce   Javier Martin   dmaengine: Add su...
884
  	return &desc->desc;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
885
  }
6c05f0915   Javier Martin   dmaengine: Add su...
886
887
888
889
890
891
  static struct dma_async_tx_descriptor *imxdma_prep_dma_memcpy(
  	struct dma_chan *chan, dma_addr_t dest,
  	dma_addr_t src, size_t len, unsigned long flags)
  {
  	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
9e15db7ce   Javier Martin   dmaengine: Add su...
892
  	struct imxdma_desc *desc;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
893

ac806a1c8   Russell King   dmaengine: imx-dm...
894
895
896
897
  	dev_dbg(imxdma->dev, "%s channel: %d src=0x%llx dst=0x%llx len=%zu
  ",
  		__func__, imxdmac->channel, (unsigned long long)src,
  		(unsigned long long)dest, len);
6c05f0915   Javier Martin   dmaengine: Add su...
898

9e15db7ce   Javier Martin   dmaengine: Add su...
899
900
  	if (list_empty(&imxdmac->ld_free) ||
  	    imxdma_chan_is_doing_cyclic(imxdmac))
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
901
  		return NULL;
9e15db7ce   Javier Martin   dmaengine: Add su...
902
  	desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
6c05f0915   Javier Martin   dmaengine: Add su...
903

9e15db7ce   Javier Martin   dmaengine: Add su...
904
905
906
907
  	desc->type = IMXDMA_DESC_MEMCPY;
  	desc->src = src;
  	desc->dest = dest;
  	desc->len = len;
2efc3449d   Javier Martin   dmaengine: imx-dm...
908
  	desc->direction = DMA_MEM_TO_MEM;
9e15db7ce   Javier Martin   dmaengine: Add su...
909
910
911
912
  	desc->config_port = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR;
  	desc->config_mem = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR;
  	desc->desc.callback = NULL;
  	desc->desc.callback_param = NULL;
6c05f0915   Javier Martin   dmaengine: Add su...
913

9e15db7ce   Javier Martin   dmaengine: Add su...
914
  	return &desc->desc;
6c05f0915   Javier Martin   dmaengine: Add su...
915
  }
f606ab897   Javier Martin   dmaengine: i.MX: ...
916
917
918
919
920
921
922
  static struct dma_async_tx_descriptor *imxdma_prep_dma_interleaved(
  	struct dma_chan *chan, struct dma_interleaved_template *xt,
  	unsigned long flags)
  {
  	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
  	struct imxdma_desc *desc;
ac806a1c8   Russell King   dmaengine: imx-dm...
923
924
925
926
927
928
  	dev_dbg(imxdma->dev, "%s channel: %d src_start=0x%llx dst_start=0x%llx
  "
  		"   src_sgl=%s dst_sgl=%s numf=%zu frame_size=%zu
  ", __func__,
  		imxdmac->channel, (unsigned long long)xt->src_start,
  		(unsigned long long) xt->dst_start,
f606ab897   Javier Martin   dmaengine: i.MX: ...
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
  		xt->src_sgl ? "true" : "false", xt->dst_sgl ? "true" : "false",
  		xt->numf, xt->frame_size);
  
  	if (list_empty(&imxdmac->ld_free) ||
  	    imxdma_chan_is_doing_cyclic(imxdmac))
  		return NULL;
  
  	if (xt->frame_size != 1 || xt->numf <= 0 || xt->dir != DMA_MEM_TO_MEM)
  		return NULL;
  
  	desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
  
  	desc->type = IMXDMA_DESC_INTERLEAVED;
  	desc->src = xt->src_start;
  	desc->dest = xt->dst_start;
  	desc->x = xt->sgl[0].size;
  	desc->y = xt->numf;
  	desc->w = xt->sgl[0].icg + desc->x;
  	desc->len = desc->x * desc->y;
  	desc->direction = DMA_MEM_TO_MEM;
  	desc->config_port = IMX_DMA_MEMSIZE_32;
  	desc->config_mem = IMX_DMA_MEMSIZE_32;
  	if (xt->src_sgl)
  		desc->config_mem |= IMX_DMA_TYPE_2D;
  	if (xt->dst_sgl)
  		desc->config_port |= IMX_DMA_TYPE_2D;
  	desc->desc.callback = NULL;
  	desc->desc.callback_param = NULL;
  
  	return &desc->desc;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
959
960
961
962
  }
  
  static void imxdma_issue_pending(struct dma_chan *chan)
  {
5b3168763   Sascha Hauer   dma: imx-dma: sta...
963
  	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
9e15db7ce   Javier Martin   dmaengine: Add su...
964
965
966
  	struct imxdma_engine *imxdma = imxdmac->imxdma;
  	struct imxdma_desc *desc;
  	unsigned long flags;
f606ab897   Javier Martin   dmaengine: i.MX: ...
967
  	spin_lock_irqsave(&imxdma->lock, flags);
9e15db7ce   Javier Martin   dmaengine: Add su...
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
  	if (list_empty(&imxdmac->ld_active) &&
  	    !list_empty(&imxdmac->ld_queue)) {
  		desc = list_first_entry(&imxdmac->ld_queue,
  					struct imxdma_desc, node);
  
  		if (imxdma_xfer_desc(desc) < 0) {
  			dev_warn(imxdma->dev,
  				 "%s: channel: %d couldn't issue DMA xfer
  ",
  				 __func__, imxdmac->channel);
  		} else {
  			list_move_tail(imxdmac->ld_queue.next,
  				       &imxdmac->ld_active);
  		}
  	}
f606ab897   Javier Martin   dmaengine: i.MX: ...
983
  	spin_unlock_irqrestore(&imxdma->lock, flags);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
984
  }
290ad0f9d   Markus Pargmann   dma: imx-dma: Add...
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
  static bool imxdma_filter_fn(struct dma_chan *chan, void *param)
  {
  	struct imxdma_filter_data *fdata = param;
  	struct imxdma_channel *imxdma_chan = to_imxdma_chan(chan);
  
  	if (chan->device->dev != fdata->imxdma->dev)
  		return false;
  
  	imxdma_chan->dma_request = fdata->request;
  	chan->private = NULL;
  
  	return true;
  }
  
  static struct dma_chan *imxdma_xlate(struct of_phandle_args *dma_spec,
  						struct of_dma *ofdma)
  {
  	int count = dma_spec->args_count;
  	struct imxdma_engine *imxdma = ofdma->of_dma_data;
  	struct imxdma_filter_data fdata = {
  		.imxdma = imxdma,
  	};
  
  	if (count != 1)
  		return NULL;
  
  	fdata.request = dma_spec->args[0];
  
  	return dma_request_channel(imxdma->dma_device.cap_mask,
  					imxdma_filter_fn, &fdata);
  }
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1016
  static int __init imxdma_probe(struct platform_device *pdev)
6bd081277   Javier Martin   dmaengine: imx-dm...
1017
  	{
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1018
  	struct imxdma_engine *imxdma;
73930eb31   Shawn Guo   dma: imx-dma: ret...
1019
  	struct resource *res;
290ad0f9d   Markus Pargmann   dma: imx-dma: Add...
1020
  	const struct of_device_id *of_id;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1021
  	int ret, i;
73930eb31   Shawn Guo   dma: imx-dma: ret...
1022
  	int irq, irq_err;
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
1023

290ad0f9d   Markus Pargmann   dma: imx-dma: Add...
1024
1025
1026
  	of_id = of_match_device(imx_dma_of_dev_id, &pdev->dev);
  	if (of_id)
  		pdev->id_entry = of_id->data;
04bbd8ef5   Shawn Guo   dma: imx-dma: use...
1027
  	imxdma = devm_kzalloc(&pdev->dev, sizeof(*imxdma), GFP_KERNEL);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1028
1029
  	if (!imxdma)
  		return -ENOMEM;
5c6b3e772   Markus Pargmann   DMA: imx-dma: imx...
1030
  	imxdma->dev = &pdev->dev;
e51d0f0ac   Shawn Guo   dma: imx-dma: rem...
1031
  	imxdma->devtype = pdev->id_entry->driver_data;
73930eb31   Shawn Guo   dma: imx-dma: ret...
1032
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
7331205a9   Thierry Reding   dma: Convert to d...
1033
1034
1035
  	imxdma->base = devm_ioremap_resource(&pdev->dev, res);
  	if (IS_ERR(imxdma->base))
  		return PTR_ERR(imxdma->base);
73930eb31   Shawn Guo   dma: imx-dma: ret...
1036
1037
1038
1039
  
  	irq = platform_get_irq(pdev, 0);
  	if (irq < 0)
  		return irq;
6bd081277   Javier Martin   dmaengine: imx-dm...
1040

a2367db2e   Fabio Estevam   dma: imx-dma: Fix...
1041
  	imxdma->dma_ipg = devm_clk_get(&pdev->dev, "ipg");
04bbd8ef5   Shawn Guo   dma: imx-dma: use...
1042
1043
  	if (IS_ERR(imxdma->dma_ipg))
  		return PTR_ERR(imxdma->dma_ipg);
a2367db2e   Fabio Estevam   dma: imx-dma: Fix...
1044
1045
  
  	imxdma->dma_ahb = devm_clk_get(&pdev->dev, "ahb");
04bbd8ef5   Shawn Guo   dma: imx-dma: use...
1046
1047
  	if (IS_ERR(imxdma->dma_ahb))
  		return PTR_ERR(imxdma->dma_ahb);
a2367db2e   Fabio Estevam   dma: imx-dma: Fix...
1048
1049
1050
  
  	clk_prepare_enable(imxdma->dma_ipg);
  	clk_prepare_enable(imxdma->dma_ahb);
6bd081277   Javier Martin   dmaengine: imx-dm...
1051
1052
  
  	/* reset DMA module */
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
1053
  	imx_dmav1_writel(imxdma, DCR_DRST, DMA_DCR);
6bd081277   Javier Martin   dmaengine: imx-dm...
1054

e51d0f0ac   Shawn Guo   dma: imx-dma: rem...
1055
  	if (is_imx1_dma(imxdma)) {
73930eb31   Shawn Guo   dma: imx-dma: ret...
1056
  		ret = devm_request_irq(&pdev->dev, irq,
04bbd8ef5   Shawn Guo   dma: imx-dma: use...
1057
  				       dma_irq_handler, 0, "DMA", imxdma);
6bd081277   Javier Martin   dmaengine: imx-dm...
1058
  		if (ret) {
f9b283a6e   Javier Martin   dmaengine: imx-dm...
1059
1060
  			dev_warn(imxdma->dev, "Can't register IRQ for DMA
  ");
04bbd8ef5   Shawn Guo   dma: imx-dma: use...
1061
  			goto err;
6bd081277   Javier Martin   dmaengine: imx-dm...
1062
  		}
73930eb31   Shawn Guo   dma: imx-dma: ret...
1063
1064
1065
1066
1067
1068
1069
  		irq_err = platform_get_irq(pdev, 1);
  		if (irq_err < 0) {
  			ret = irq_err;
  			goto err;
  		}
  
  		ret = devm_request_irq(&pdev->dev, irq_err,
04bbd8ef5   Shawn Guo   dma: imx-dma: use...
1070
  				       imxdma_err_handler, 0, "DMA", imxdma);
6bd081277   Javier Martin   dmaengine: imx-dm...
1071
  		if (ret) {
f9b283a6e   Javier Martin   dmaengine: imx-dm...
1072
1073
  			dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA
  ");
04bbd8ef5   Shawn Guo   dma: imx-dma: use...
1074
  			goto err;
6bd081277   Javier Martin   dmaengine: imx-dm...
1075
1076
1077
1078
  		}
  	}
  
  	/* enable DMA module */
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
1079
  	imx_dmav1_writel(imxdma, DCR_DEN, DMA_DCR);
6bd081277   Javier Martin   dmaengine: imx-dm...
1080
1081
  
  	/* clear all interrupts */
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
1082
  	imx_dmav1_writel(imxdma, (1 << IMX_DMA_CHANNELS) - 1, DMA_DISR);
6bd081277   Javier Martin   dmaengine: imx-dm...
1083
1084
  
  	/* disable interrupts */
cd5cf9da0   Javier Martin   dmaengine: imx-dm...
1085
  	imx_dmav1_writel(imxdma, (1 << IMX_DMA_CHANNELS) - 1, DMA_DIMR);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1086
1087
  
  	INIT_LIST_HEAD(&imxdma->dma_device.channels);
f8a356ff9   Sascha Hauer   dmaengine i.MX dm...
1088
1089
  	dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
  	dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);
6c05f0915   Javier Martin   dmaengine: Add su...
1090
  	dma_cap_set(DMA_MEMCPY, imxdma->dma_device.cap_mask);
f606ab897   Javier Martin   dmaengine: i.MX: ...
1091
1092
1093
1094
1095
1096
1097
  	dma_cap_set(DMA_INTERLEAVE, imxdma->dma_device.cap_mask);
  
  	/* Initialize 2D global parameters */
  	for (i = 0; i < IMX_DMA_2D_SLOTS; i++)
  		imxdma->slots_2d[i].count = 0;
  
  	spin_lock_init(&imxdma->lock);
f8a356ff9   Sascha Hauer   dmaengine i.MX dm...
1098

1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1099
  	/* Initialize channel parameters */
6bd081277   Javier Martin   dmaengine: imx-dm...
1100
  	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1101
  		struct imxdma_channel *imxdmac = &imxdma->channel[i];
e51d0f0ac   Shawn Guo   dma: imx-dma: rem...
1102
  		if (!is_imx1_dma(imxdma)) {
73930eb31   Shawn Guo   dma: imx-dma: ret...
1103
  			ret = devm_request_irq(&pdev->dev, irq + i,
6bd081277   Javier Martin   dmaengine: imx-dm...
1104
1105
  					dma_irq_handler, 0, "DMA", imxdma);
  			if (ret) {
f9b283a6e   Javier Martin   dmaengine: imx-dm...
1106
1107
1108
  				dev_warn(imxdma->dev, "Can't register IRQ %d "
  					 "for DMA channel %d
  ",
73930eb31   Shawn Guo   dma: imx-dma: ret...
1109
  					 irq + i, i);
04bbd8ef5   Shawn Guo   dma: imx-dma: use...
1110
  				goto err;
6bd081277   Javier Martin   dmaengine: imx-dm...
1111
  			}
2d9c2fc59   Javier Martin   dmaengine: imx-dm...
1112
1113
1114
  			init_timer(&imxdmac->watchdog);
  			imxdmac->watchdog.function = &imxdma_watchdog;
  			imxdmac->watchdog.data = (unsigned long)imxdmac;
8267f16e8   Sascha Hauer   dma: imx-dma: fix...
1115
  		}
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1116

1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1117
  		imxdmac->imxdma = imxdma;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1118

9e15db7ce   Javier Martin   dmaengine: Add su...
1119
1120
1121
1122
1123
1124
  		INIT_LIST_HEAD(&imxdmac->ld_queue);
  		INIT_LIST_HEAD(&imxdmac->ld_free);
  		INIT_LIST_HEAD(&imxdmac->ld_active);
  
  		tasklet_init(&imxdmac->dma_tasklet, imxdma_tasklet,
  			     (unsigned long)imxdmac);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1125
  		imxdmac->chan.device = &imxdma->dma_device;
8ac695463   Russell King - ARM Linux   dmaengine: ensure...
1126
  		dma_cookie_init(&imxdmac->chan);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1127
1128
1129
  		imxdmac->channel = i;
  
  		/* Add the channel to the DMAC list */
9e15db7ce   Javier Martin   dmaengine: Add su...
1130
1131
  		list_add_tail(&imxdmac->chan.device_node,
  			      &imxdma->dma_device.channels);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1132
  	}
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1133
1134
1135
1136
1137
1138
1139
  	imxdma->dma_device.dev = &pdev->dev;
  
  	imxdma->dma_device.device_alloc_chan_resources = imxdma_alloc_chan_resources;
  	imxdma->dma_device.device_free_chan_resources = imxdma_free_chan_resources;
  	imxdma->dma_device.device_tx_status = imxdma_tx_status;
  	imxdma->dma_device.device_prep_slave_sg = imxdma_prep_slave_sg;
  	imxdma->dma_device.device_prep_dma_cyclic = imxdma_prep_dma_cyclic;
6c05f0915   Javier Martin   dmaengine: Add su...
1140
  	imxdma->dma_device.device_prep_dma_memcpy = imxdma_prep_dma_memcpy;
f606ab897   Javier Martin   dmaengine: i.MX: ...
1141
  	imxdma->dma_device.device_prep_interleaved_dma = imxdma_prep_dma_interleaved;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1142
1143
1144
1145
  	imxdma->dma_device.device_control = imxdma_control;
  	imxdma->dma_device.device_issue_pending = imxdma_issue_pending;
  
  	platform_set_drvdata(pdev, imxdma);
6c05f0915   Javier Martin   dmaengine: Add su...
1146
  	imxdma->dma_device.copy_align = 2; /* 2^2 = 4 bytes alignment */
1e070a609   Sascha Hauer   dmaengine i.MX dm...
1147
1148
  	imxdma->dma_device.dev->dma_parms = &imxdma->dma_parms;
  	dma_set_max_seg_size(imxdma->dma_device.dev, 0xffffff);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1149
1150
1151
1152
  	ret = dma_async_device_register(&imxdma->dma_device);
  	if (ret) {
  		dev_err(&pdev->dev, "unable to register
  ");
04bbd8ef5   Shawn Guo   dma: imx-dma: use...
1153
  		goto err;
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1154
  	}
290ad0f9d   Markus Pargmann   dma: imx-dma: Add...
1155
1156
1157
1158
1159
1160
1161
1162
1163
  	if (pdev->dev.of_node) {
  		ret = of_dma_controller_register(pdev->dev.of_node,
  				imxdma_xlate, imxdma);
  		if (ret) {
  			dev_err(&pdev->dev, "unable to register of_dma_controller
  ");
  			goto err_of_dma_controller;
  		}
  	}
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1164
  	return 0;
290ad0f9d   Markus Pargmann   dma: imx-dma: Add...
1165
1166
  err_of_dma_controller:
  	dma_async_device_unregister(&imxdma->dma_device);
04bbd8ef5   Shawn Guo   dma: imx-dma: use...
1167
  err:
a2367db2e   Fabio Estevam   dma: imx-dma: Fix...
1168
1169
  	clk_disable_unprepare(imxdma->dma_ipg);
  	clk_disable_unprepare(imxdma->dma_ahb);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1170
1171
  	return ret;
  }
1d1bbd305   Maxin B. John   dma: Remove erron...
1172
  static int imxdma_remove(struct platform_device *pdev)
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1173
1174
  {
  	struct imxdma_engine *imxdma = platform_get_drvdata(pdev);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1175
1176
  
          dma_async_device_unregister(&imxdma->dma_device);
290ad0f9d   Markus Pargmann   dma: imx-dma: Add...
1177
1178
  	if (pdev->dev.of_node)
  		of_dma_controller_free(pdev->dev.of_node);
a2367db2e   Fabio Estevam   dma: imx-dma: Fix...
1179
1180
  	clk_disable_unprepare(imxdma->dma_ipg);
  	clk_disable_unprepare(imxdma->dma_ahb);
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1181
1182
1183
1184
1185
1186
1187
  
          return 0;
  }
  
  static struct platform_driver imxdma_driver = {
  	.driver		= {
  		.name	= "imx-dma",
4de9b3b04   Alexander Shiyan   dma: imx-dma: Add...
1188
  		.owner	= THIS_MODULE,
290ad0f9d   Markus Pargmann   dma: imx-dma: Add...
1189
  		.of_match_table = imx_dma_of_dev_id,
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1190
  	},
e51d0f0ac   Shawn Guo   dma: imx-dma: rem...
1191
  	.id_table	= imx_dma_devtype,
1d1bbd305   Maxin B. John   dma: Remove erron...
1192
  	.remove		= imxdma_remove,
1f1846c6c   Sascha Hauer   dmaengine: Add Fr...
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
  };
  
  static int __init imxdma_module_init(void)
  {
  	return platform_driver_probe(&imxdma_driver, imxdma_probe);
  }
  subsys_initcall(imxdma_module_init);
  
  MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
  MODULE_DESCRIPTION("i.MX dma driver");
  MODULE_LICENSE("GPL");