blob: fab9c9c1b421be0df0f6aa7c04bd87d95af92571 [file] [log] [blame]
Rongjun Yingca21a142011-10-27 19:22:39 -07001/*
2 * DMA controller driver for CSR SiRFprimaII
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <linux/module.h>
10#include <linux/dmaengine.h>
11#include <linux/dma-mapping.h>
Barry Song2a766892013-07-30 17:44:34 +080012#include <linux/pm_runtime.h>
Rongjun Yingca21a142011-10-27 19:22:39 -070013#include <linux/interrupt.h>
14#include <linux/io.h>
15#include <linux/slab.h>
16#include <linux/of_irq.h>
17#include <linux/of_address.h>
18#include <linux/of_device.h>
19#include <linux/of_platform.h>
Barry Songa7e34062013-03-18 16:33:43 +080020#include <linux/clk.h>
Barry Song2e041c92014-03-27 15:49:31 +080021#include <linux/of_dma.h>
Rongjun Yingca21a142011-10-27 19:22:39 -070022#include <linux/sirfsoc_dma.h>
23
Vinod Koul949ff5b2012-03-13 11:58:12 +053024#include "dmaengine.h"
25
Rongjun Yingca21a142011-10-27 19:22:39 -070026#define SIRFSOC_DMA_DESCRIPTORS 16
27#define SIRFSOC_DMA_CHANNELS 16
28
29#define SIRFSOC_DMA_CH_ADDR 0x00
30#define SIRFSOC_DMA_CH_XLEN 0x04
31#define SIRFSOC_DMA_CH_YLEN 0x08
32#define SIRFSOC_DMA_CH_CTRL 0x0C
33
34#define SIRFSOC_DMA_WIDTH_0 0x100
35#define SIRFSOC_DMA_CH_VALID 0x140
36#define SIRFSOC_DMA_CH_INT 0x144
37#define SIRFSOC_DMA_INT_EN 0x148
Barry Songf7d935d2012-11-01 22:54:43 +080038#define SIRFSOC_DMA_INT_EN_CLR 0x14C
Rongjun Yingca21a142011-10-27 19:22:39 -070039#define SIRFSOC_DMA_CH_LOOP_CTRL 0x150
Barry Songf7d935d2012-11-01 22:54:43 +080040#define SIRFSOC_DMA_CH_LOOP_CTRL_CLR 0x15C
Rongjun Yingca21a142011-10-27 19:22:39 -070041
42#define SIRFSOC_DMA_MODE_CTRL_BIT 4
43#define SIRFSOC_DMA_DIR_CTRL_BIT 5
44
45/* xlen and dma_width register is in 4 bytes boundary */
46#define SIRFSOC_DMA_WORD_LEN 4
47
48struct sirfsoc_dma_desc {
49 struct dma_async_tx_descriptor desc;
50 struct list_head node;
51
52 /* SiRFprimaII 2D-DMA parameters */
53
54 int xlen; /* DMA xlen */
55 int ylen; /* DMA ylen */
56 int width; /* DMA width */
57 int dir;
58 bool cyclic; /* is loop DMA? */
59 u32 addr; /* DMA buffer address */
60};
61
62struct sirfsoc_dma_chan {
63 struct dma_chan chan;
64 struct list_head free;
65 struct list_head prepared;
66 struct list_head queued;
67 struct list_head active;
68 struct list_head completed;
Rongjun Yingca21a142011-10-27 19:22:39 -070069 unsigned long happened_cyclic;
70 unsigned long completed_cyclic;
71
72 /* Lock for this structure */
73 spinlock_t lock;
74
75 int mode;
76};
77
Barry Song2a766892013-07-30 17:44:34 +080078struct sirfsoc_dma_regs {
79 u32 ctrl[SIRFSOC_DMA_CHANNELS];
80 u32 interrupt_en;
81};
82
Rongjun Yingca21a142011-10-27 19:22:39 -070083struct sirfsoc_dma {
84 struct dma_device dma;
85 struct tasklet_struct tasklet;
86 struct sirfsoc_dma_chan channels[SIRFSOC_DMA_CHANNELS];
87 void __iomem *base;
88 int irq;
Barry Songa7e34062013-03-18 16:33:43 +080089 struct clk *clk;
Barry Songf7d935d2012-11-01 22:54:43 +080090 bool is_marco;
Barry Song2a766892013-07-30 17:44:34 +080091 struct sirfsoc_dma_regs regs_save;
Rongjun Yingca21a142011-10-27 19:22:39 -070092};
93
94#define DRV_NAME "sirfsoc_dma"
95
Barry Song2a766892013-07-30 17:44:34 +080096static int sirfsoc_dma_runtime_suspend(struct device *dev);
97
Rongjun Yingca21a142011-10-27 19:22:39 -070098/* Convert struct dma_chan to struct sirfsoc_dma_chan */
99static inline
100struct sirfsoc_dma_chan *dma_chan_to_sirfsoc_dma_chan(struct dma_chan *c)
101{
102 return container_of(c, struct sirfsoc_dma_chan, chan);
103}
104
105/* Convert struct dma_chan to struct sirfsoc_dma */
106static inline struct sirfsoc_dma *dma_chan_to_sirfsoc_dma(struct dma_chan *c)
107{
108 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(c);
109 return container_of(schan, struct sirfsoc_dma, channels[c->chan_id]);
110}
111
112/* Execute all queued DMA descriptors */
113static void sirfsoc_dma_execute(struct sirfsoc_dma_chan *schan)
114{
115 struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan);
116 int cid = schan->chan.chan_id;
117 struct sirfsoc_dma_desc *sdesc = NULL;
118
119 /*
120 * lock has been held by functions calling this, so we don't hold
121 * lock again
122 */
123
124 sdesc = list_first_entry(&schan->queued, struct sirfsoc_dma_desc,
125 node);
126 /* Move the first queued descriptor to active list */
Barry Song26fd1222012-09-27 16:36:10 +0800127 list_move_tail(&sdesc->node, &schan->active);
Rongjun Yingca21a142011-10-27 19:22:39 -0700128
129 /* Start the DMA transfer */
130 writel_relaxed(sdesc->width, sdma->base + SIRFSOC_DMA_WIDTH_0 +
131 cid * 4);
132 writel_relaxed(cid | (schan->mode << SIRFSOC_DMA_MODE_CTRL_BIT) |
133 (sdesc->dir << SIRFSOC_DMA_DIR_CTRL_BIT),
134 sdma->base + cid * 0x10 + SIRFSOC_DMA_CH_CTRL);
135 writel_relaxed(sdesc->xlen, sdma->base + cid * 0x10 +
136 SIRFSOC_DMA_CH_XLEN);
137 writel_relaxed(sdesc->ylen, sdma->base + cid * 0x10 +
138 SIRFSOC_DMA_CH_YLEN);
139 writel_relaxed(readl_relaxed(sdma->base + SIRFSOC_DMA_INT_EN) |
140 (1 << cid), sdma->base + SIRFSOC_DMA_INT_EN);
141
142 /*
143 * writel has an implict memory write barrier to make sure data is
144 * flushed into memory before starting DMA
145 */
146 writel(sdesc->addr >> 2, sdma->base + cid * 0x10 + SIRFSOC_DMA_CH_ADDR);
147
148 if (sdesc->cyclic) {
149 writel((1 << cid) | 1 << (cid + 16) |
150 readl_relaxed(sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL),
151 sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL);
152 schan->happened_cyclic = schan->completed_cyclic = 0;
153 }
154}
155
156/* Interrupt handler */
157static irqreturn_t sirfsoc_dma_irq(int irq, void *data)
158{
159 struct sirfsoc_dma *sdma = data;
160 struct sirfsoc_dma_chan *schan;
161 struct sirfsoc_dma_desc *sdesc = NULL;
162 u32 is;
163 int ch;
164
165 is = readl(sdma->base + SIRFSOC_DMA_CH_INT);
166 while ((ch = fls(is) - 1) >= 0) {
167 is &= ~(1 << ch);
168 writel_relaxed(1 << ch, sdma->base + SIRFSOC_DMA_CH_INT);
169 schan = &sdma->channels[ch];
170
171 spin_lock(&schan->lock);
172
173 sdesc = list_first_entry(&schan->active, struct sirfsoc_dma_desc,
174 node);
175 if (!sdesc->cyclic) {
176 /* Execute queued descriptors */
177 list_splice_tail_init(&schan->active, &schan->completed);
178 if (!list_empty(&schan->queued))
179 sirfsoc_dma_execute(schan);
180 } else
181 schan->happened_cyclic++;
182
183 spin_unlock(&schan->lock);
184 }
185
186 /* Schedule tasklet */
187 tasklet_schedule(&sdma->tasklet);
188
189 return IRQ_HANDLED;
190}
191
192/* process completed descriptors */
193static void sirfsoc_dma_process_completed(struct sirfsoc_dma *sdma)
194{
195 dma_cookie_t last_cookie = 0;
196 struct sirfsoc_dma_chan *schan;
197 struct sirfsoc_dma_desc *sdesc;
198 struct dma_async_tx_descriptor *desc;
199 unsigned long flags;
200 unsigned long happened_cyclic;
201 LIST_HEAD(list);
202 int i;
203
204 for (i = 0; i < sdma->dma.chancnt; i++) {
205 schan = &sdma->channels[i];
206
207 /* Get all completed descriptors */
208 spin_lock_irqsave(&schan->lock, flags);
209 if (!list_empty(&schan->completed)) {
210 list_splice_tail_init(&schan->completed, &list);
211 spin_unlock_irqrestore(&schan->lock, flags);
212
213 /* Execute callbacks and run dependencies */
214 list_for_each_entry(sdesc, &list, node) {
215 desc = &sdesc->desc;
216
217 if (desc->callback)
218 desc->callback(desc->callback_param);
219
220 last_cookie = desc->cookie;
221 dma_run_dependencies(desc);
222 }
223
224 /* Free descriptors */
225 spin_lock_irqsave(&schan->lock, flags);
226 list_splice_tail_init(&list, &schan->free);
Russell King - ARM Linux4d4e58d2012-03-06 22:34:06 +0000227 schan->chan.completed_cookie = last_cookie;
Rongjun Yingca21a142011-10-27 19:22:39 -0700228 spin_unlock_irqrestore(&schan->lock, flags);
229 } else {
230 /* for cyclic channel, desc is always in active list */
231 sdesc = list_first_entry(&schan->active, struct sirfsoc_dma_desc,
232 node);
233
234 if (!sdesc || (sdesc && !sdesc->cyclic)) {
235 /* without active cyclic DMA */
236 spin_unlock_irqrestore(&schan->lock, flags);
237 continue;
238 }
239
240 /* cyclic DMA */
241 happened_cyclic = schan->happened_cyclic;
242 spin_unlock_irqrestore(&schan->lock, flags);
243
244 desc = &sdesc->desc;
245 while (happened_cyclic != schan->completed_cyclic) {
246 if (desc->callback)
247 desc->callback(desc->callback_param);
248 schan->completed_cyclic++;
249 }
250 }
251 }
252}
253
254/* DMA Tasklet */
255static void sirfsoc_dma_tasklet(unsigned long data)
256{
257 struct sirfsoc_dma *sdma = (void *)data;
258
259 sirfsoc_dma_process_completed(sdma);
260}
261
262/* Submit descriptor to hardware */
263static dma_cookie_t sirfsoc_dma_tx_submit(struct dma_async_tx_descriptor *txd)
264{
265 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(txd->chan);
266 struct sirfsoc_dma_desc *sdesc;
267 unsigned long flags;
268 dma_cookie_t cookie;
269
270 sdesc = container_of(txd, struct sirfsoc_dma_desc, desc);
271
272 spin_lock_irqsave(&schan->lock, flags);
273
274 /* Move descriptor to queue */
275 list_move_tail(&sdesc->node, &schan->queued);
276
Russell King - ARM Linux884485e2012-03-06 22:34:46 +0000277 cookie = dma_cookie_assign(txd);
Rongjun Yingca21a142011-10-27 19:22:39 -0700278
279 spin_unlock_irqrestore(&schan->lock, flags);
280
281 return cookie;
282}
283
Maxime Riparded14a7c2014-11-17 14:42:34 +0100284static int sirfsoc_dma_slave_config(struct dma_chan *chan,
285 struct dma_slave_config *config)
Rongjun Yingca21a142011-10-27 19:22:39 -0700286{
Maxime Riparded14a7c2014-11-17 14:42:34 +0100287 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
Rongjun Yingca21a142011-10-27 19:22:39 -0700288 unsigned long flags;
289
290 if ((config->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
291 (config->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES))
292 return -EINVAL;
293
294 spin_lock_irqsave(&schan->lock, flags);
295 schan->mode = (config->src_maxburst == 4 ? 1 : 0);
296 spin_unlock_irqrestore(&schan->lock, flags);
297
298 return 0;
299}
300
Maxime Riparded14a7c2014-11-17 14:42:34 +0100301static int sirfsoc_dma_terminate_all(struct dma_chan *chan)
Rongjun Yingca21a142011-10-27 19:22:39 -0700302{
Maxime Riparded14a7c2014-11-17 14:42:34 +0100303 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
Rongjun Yingca21a142011-10-27 19:22:39 -0700304 struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan);
305 int cid = schan->chan.chan_id;
306 unsigned long flags;
307
Barry Song2b99c252012-12-14 11:06:58 +0000308 spin_lock_irqsave(&schan->lock, flags);
309
Barry Songf7d935d2012-11-01 22:54:43 +0800310 if (!sdma->is_marco) {
311 writel_relaxed(readl_relaxed(sdma->base + SIRFSOC_DMA_INT_EN) &
312 ~(1 << cid), sdma->base + SIRFSOC_DMA_INT_EN);
313 writel_relaxed(readl_relaxed(sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL)
314 & ~((1 << cid) | 1 << (cid + 16)),
Rongjun Yingca21a142011-10-27 19:22:39 -0700315 sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL);
Barry Songf7d935d2012-11-01 22:54:43 +0800316 } else {
317 writel_relaxed(1 << cid, sdma->base + SIRFSOC_DMA_INT_EN_CLR);
318 writel_relaxed((1 << cid) | 1 << (cid + 16),
319 sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL_CLR);
320 }
321
Rongjun Yingca21a142011-10-27 19:22:39 -0700322 writel_relaxed(1 << cid, sdma->base + SIRFSOC_DMA_CH_VALID);
323
Rongjun Yingca21a142011-10-27 19:22:39 -0700324 list_splice_tail_init(&schan->active, &schan->free);
325 list_splice_tail_init(&schan->queued, &schan->free);
Barry Song2b99c252012-12-14 11:06:58 +0000326
Rongjun Yingca21a142011-10-27 19:22:39 -0700327 spin_unlock_irqrestore(&schan->lock, flags);
328
329 return 0;
330}
331
Maxime Riparded14a7c2014-11-17 14:42:34 +0100332static int sirfsoc_dma_pause_chan(struct dma_chan *chan)
Barry Song2518d1d2012-12-14 10:59:22 +0000333{
Maxime Riparded14a7c2014-11-17 14:42:34 +0100334 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
Barry Song2518d1d2012-12-14 10:59:22 +0000335 struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan);
336 int cid = schan->chan.chan_id;
337 unsigned long flags;
338
339 spin_lock_irqsave(&schan->lock, flags);
340
341 if (!sdma->is_marco)
342 writel_relaxed(readl_relaxed(sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL)
343 & ~((1 << cid) | 1 << (cid + 16)),
344 sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL);
345 else
346 writel_relaxed((1 << cid) | 1 << (cid + 16),
347 sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL_CLR);
348
349 spin_unlock_irqrestore(&schan->lock, flags);
350
351 return 0;
352}
353
Maxime Riparded14a7c2014-11-17 14:42:34 +0100354static int sirfsoc_dma_resume_chan(struct dma_chan *chan)
Barry Song2518d1d2012-12-14 10:59:22 +0000355{
Maxime Riparded14a7c2014-11-17 14:42:34 +0100356 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
Barry Song2518d1d2012-12-14 10:59:22 +0000357 struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan);
358 int cid = schan->chan.chan_id;
359 unsigned long flags;
360
361 spin_lock_irqsave(&schan->lock, flags);
362
363 if (!sdma->is_marco)
364 writel_relaxed(readl_relaxed(sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL)
365 | ((1 << cid) | 1 << (cid + 16)),
366 sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL);
367 else
368 writel_relaxed((1 << cid) | 1 << (cid + 16),
369 sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL);
370
Rongjun Yingca21a142011-10-27 19:22:39 -0700371 spin_unlock_irqrestore(&schan->lock, flags);
372
373 return 0;
374}
375
Rongjun Yingca21a142011-10-27 19:22:39 -0700376/* Alloc channel resources */
377static int sirfsoc_dma_alloc_chan_resources(struct dma_chan *chan)
378{
379 struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan);
380 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
381 struct sirfsoc_dma_desc *sdesc;
382 unsigned long flags;
383 LIST_HEAD(descs);
384 int i;
385
Barry Song2a766892013-07-30 17:44:34 +0800386 pm_runtime_get_sync(sdma->dma.dev);
387
Rongjun Yingca21a142011-10-27 19:22:39 -0700388 /* Alloc descriptors for this channel */
389 for (i = 0; i < SIRFSOC_DMA_DESCRIPTORS; i++) {
390 sdesc = kzalloc(sizeof(*sdesc), GFP_KERNEL);
391 if (!sdesc) {
392 dev_notice(sdma->dma.dev, "Memory allocation error. "
393 "Allocated only %u descriptors\n", i);
394 break;
395 }
396
397 dma_async_tx_descriptor_init(&sdesc->desc, chan);
398 sdesc->desc.flags = DMA_CTRL_ACK;
399 sdesc->desc.tx_submit = sirfsoc_dma_tx_submit;
400
401 list_add_tail(&sdesc->node, &descs);
402 }
403
404 /* Return error only if no descriptors were allocated */
405 if (i == 0)
406 return -ENOMEM;
407
408 spin_lock_irqsave(&schan->lock, flags);
409
410 list_splice_tail_init(&descs, &schan->free);
411 spin_unlock_irqrestore(&schan->lock, flags);
412
413 return i;
414}
415
416/* Free channel resources */
417static void sirfsoc_dma_free_chan_resources(struct dma_chan *chan)
418{
419 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
Barry Song2a766892013-07-30 17:44:34 +0800420 struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan);
Rongjun Yingca21a142011-10-27 19:22:39 -0700421 struct sirfsoc_dma_desc *sdesc, *tmp;
422 unsigned long flags;
423 LIST_HEAD(descs);
424
425 spin_lock_irqsave(&schan->lock, flags);
426
427 /* Channel must be idle */
428 BUG_ON(!list_empty(&schan->prepared));
429 BUG_ON(!list_empty(&schan->queued));
430 BUG_ON(!list_empty(&schan->active));
431 BUG_ON(!list_empty(&schan->completed));
432
433 /* Move data */
434 list_splice_tail_init(&schan->free, &descs);
435
436 spin_unlock_irqrestore(&schan->lock, flags);
437
438 /* Free descriptors */
439 list_for_each_entry_safe(sdesc, tmp, &descs, node)
440 kfree(sdesc);
Barry Song2a766892013-07-30 17:44:34 +0800441
442 pm_runtime_put(sdma->dma.dev);
Rongjun Yingca21a142011-10-27 19:22:39 -0700443}
444
445/* Send pending descriptor to hardware */
446static void sirfsoc_dma_issue_pending(struct dma_chan *chan)
447{
448 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
449 unsigned long flags;
450
451 spin_lock_irqsave(&schan->lock, flags);
452
453 if (list_empty(&schan->active) && !list_empty(&schan->queued))
454 sirfsoc_dma_execute(schan);
455
456 spin_unlock_irqrestore(&schan->lock, flags);
457}
458
459/* Check request completion status */
460static enum dma_status
461sirfsoc_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
462 struct dma_tx_state *txstate)
463{
Rongjun Yingadd93b52013-05-14 23:03:20 +0800464 struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan);
Rongjun Yingca21a142011-10-27 19:22:39 -0700465 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
466 unsigned long flags;
Russell King - ARM Linux96a2af42012-03-06 22:35:27 +0000467 enum dma_status ret;
Rongjun Yingadd93b52013-05-14 23:03:20 +0800468 struct sirfsoc_dma_desc *sdesc;
469 int cid = schan->chan.chan_id;
470 unsigned long dma_pos;
471 unsigned long dma_request_bytes;
472 unsigned long residue;
Rongjun Yingca21a142011-10-27 19:22:39 -0700473
474 spin_lock_irqsave(&schan->lock, flags);
Rongjun Yingadd93b52013-05-14 23:03:20 +0800475
476 sdesc = list_first_entry(&schan->active, struct sirfsoc_dma_desc,
477 node);
478 dma_request_bytes = (sdesc->xlen + 1) * (sdesc->ylen + 1) *
479 (sdesc->width * SIRFSOC_DMA_WORD_LEN);
480
Russell King - ARM Linux96a2af42012-03-06 22:35:27 +0000481 ret = dma_cookie_status(chan, cookie, txstate);
Rongjun Yingadd93b52013-05-14 23:03:20 +0800482 dma_pos = readl_relaxed(sdma->base + cid * 0x10 + SIRFSOC_DMA_CH_ADDR)
483 << 2;
484 residue = dma_request_bytes - (dma_pos - sdesc->addr);
485 dma_set_residue(txstate, residue);
486
Rongjun Yingca21a142011-10-27 19:22:39 -0700487 spin_unlock_irqrestore(&schan->lock, flags);
488
Russell King - ARM Linux96a2af42012-03-06 22:35:27 +0000489 return ret;
Rongjun Yingca21a142011-10-27 19:22:39 -0700490}
491
492static struct dma_async_tx_descriptor *sirfsoc_dma_prep_interleaved(
493 struct dma_chan *chan, struct dma_interleaved_template *xt,
494 unsigned long flags)
495{
496 struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan);
497 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
498 struct sirfsoc_dma_desc *sdesc = NULL;
499 unsigned long iflags;
500 int ret;
501
Barry Song5997e082012-09-27 16:35:38 +0800502 if ((xt->dir != DMA_MEM_TO_DEV) && (xt->dir != DMA_DEV_TO_MEM)) {
Rongjun Yingca21a142011-10-27 19:22:39 -0700503 ret = -EINVAL;
504 goto err_dir;
505 }
506
507 /* Get free descriptor */
508 spin_lock_irqsave(&schan->lock, iflags);
509 if (!list_empty(&schan->free)) {
510 sdesc = list_first_entry(&schan->free, struct sirfsoc_dma_desc,
511 node);
512 list_del(&sdesc->node);
513 }
514 spin_unlock_irqrestore(&schan->lock, iflags);
515
516 if (!sdesc) {
517 /* try to free completed descriptors */
518 sirfsoc_dma_process_completed(sdma);
519 ret = 0;
520 goto no_desc;
521 }
522
523 /* Place descriptor in prepared list */
524 spin_lock_irqsave(&schan->lock, iflags);
525
526 /*
527 * Number of chunks in a frame can only be 1 for prima2
528 * and ylen (number of frame - 1) must be at least 0
529 */
530 if ((xt->frame_size == 1) && (xt->numf > 0)) {
531 sdesc->cyclic = 0;
532 sdesc->xlen = xt->sgl[0].size / SIRFSOC_DMA_WORD_LEN;
533 sdesc->width = (xt->sgl[0].size + xt->sgl[0].icg) /
534 SIRFSOC_DMA_WORD_LEN;
535 sdesc->ylen = xt->numf - 1;
536 if (xt->dir == DMA_MEM_TO_DEV) {
537 sdesc->addr = xt->src_start;
538 sdesc->dir = 1;
539 } else {
540 sdesc->addr = xt->dst_start;
541 sdesc->dir = 0;
542 }
543
544 list_add_tail(&sdesc->node, &schan->prepared);
545 } else {
546 pr_err("sirfsoc DMA Invalid xfer\n");
547 ret = -EINVAL;
548 goto err_xfer;
549 }
550 spin_unlock_irqrestore(&schan->lock, iflags);
551
552 return &sdesc->desc;
553err_xfer:
554 spin_unlock_irqrestore(&schan->lock, iflags);
555no_desc:
556err_dir:
557 return ERR_PTR(ret);
558}
559
560static struct dma_async_tx_descriptor *
561sirfsoc_dma_prep_cyclic(struct dma_chan *chan, dma_addr_t addr,
562 size_t buf_len, size_t period_len,
Laurent Pinchart31c1e5a2014-08-01 12:20:10 +0200563 enum dma_transfer_direction direction, unsigned long flags)
Rongjun Yingca21a142011-10-27 19:22:39 -0700564{
565 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
566 struct sirfsoc_dma_desc *sdesc = NULL;
567 unsigned long iflags;
568
569 /*
570 * we only support cycle transfer with 2 period
571 * If the X-length is set to 0, it would be the loop mode.
572 * The DMA address keeps increasing until reaching the end of a loop
573 * area whose size is defined by (DMA_WIDTH x (Y_LENGTH + 1)). Then
574 * the DMA address goes back to the beginning of this area.
575 * In loop mode, the DMA data region is divided into two parts, BUFA
576 * and BUFB. DMA controller generates interrupts twice in each loop:
577 * when the DMA address reaches the end of BUFA or the end of the
578 * BUFB
579 */
580 if (buf_len != 2 * period_len)
581 return ERR_PTR(-EINVAL);
582
583 /* Get free descriptor */
584 spin_lock_irqsave(&schan->lock, iflags);
585 if (!list_empty(&schan->free)) {
586 sdesc = list_first_entry(&schan->free, struct sirfsoc_dma_desc,
587 node);
588 list_del(&sdesc->node);
589 }
590 spin_unlock_irqrestore(&schan->lock, iflags);
591
592 if (!sdesc)
Jingoo Han696b4ff2013-08-06 19:37:56 +0900593 return NULL;
Rongjun Yingca21a142011-10-27 19:22:39 -0700594
595 /* Place descriptor in prepared list */
596 spin_lock_irqsave(&schan->lock, iflags);
597 sdesc->addr = addr;
598 sdesc->cyclic = 1;
599 sdesc->xlen = 0;
600 sdesc->ylen = buf_len / SIRFSOC_DMA_WORD_LEN - 1;
601 sdesc->width = 1;
602 list_add_tail(&sdesc->node, &schan->prepared);
603 spin_unlock_irqrestore(&schan->lock, iflags);
604
605 return &sdesc->desc;
606}
607
608/*
609 * The DMA controller consists of 16 independent DMA channels.
610 * Each channel is allocated to a different function
611 */
612bool sirfsoc_dma_filter_id(struct dma_chan *chan, void *chan_id)
613{
614 unsigned int ch_nr = (unsigned int) chan_id;
615
616 if (ch_nr == chan->chan_id +
617 chan->device->dev_id * SIRFSOC_DMA_CHANNELS)
618 return true;
619
620 return false;
621}
622EXPORT_SYMBOL(sirfsoc_dma_filter_id);
623
Rongjun Yingba07d812013-12-23 20:19:21 +0800624#define SIRFSOC_DMA_BUSWIDTHS \
625 (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \
626 BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
627 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
628 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
629 BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
630
631static int sirfsoc_dma_device_slave_caps(struct dma_chan *dchan,
632 struct dma_slave_caps *caps)
633{
634 caps->src_addr_widths = SIRFSOC_DMA_BUSWIDTHS;
Maxime Ripardceacbdb2014-11-17 14:41:57 +0100635 caps->dst_addr_widths = SIRFSOC_DMA_BUSWIDTHS;
Rongjun Yingba07d812013-12-23 20:19:21 +0800636 caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
637 caps->cmd_pause = true;
638 caps->cmd_terminate = true;
639
640 return 0;
641}
642
Barry Song2e041c92014-03-27 15:49:31 +0800643static struct dma_chan *of_dma_sirfsoc_xlate(struct of_phandle_args *dma_spec,
644 struct of_dma *ofdma)
645{
646 struct sirfsoc_dma *sdma = ofdma->of_dma_data;
647 unsigned int request = dma_spec->args[0];
648
Dan Carpenterf3817e72014-04-03 10:29:33 +0300649 if (request >= SIRFSOC_DMA_CHANNELS)
Barry Song2e041c92014-03-27 15:49:31 +0800650 return NULL;
651
652 return dma_get_slave_channel(&sdma->channels[request].chan);
653}
654
Bill Pemberton463a1f82012-11-19 13:22:55 -0500655static int sirfsoc_dma_probe(struct platform_device *op)
Rongjun Yingca21a142011-10-27 19:22:39 -0700656{
657 struct device_node *dn = op->dev.of_node;
658 struct device *dev = &op->dev;
659 struct dma_device *dma;
660 struct sirfsoc_dma *sdma;
661 struct sirfsoc_dma_chan *schan;
662 struct resource res;
663 ulong regs_start, regs_size;
664 u32 id;
665 int ret, i;
666
667 sdma = devm_kzalloc(dev, sizeof(*sdma), GFP_KERNEL);
668 if (!sdma) {
669 dev_err(dev, "Memory exhausted!\n");
670 return -ENOMEM;
671 }
672
Barry Songf7d935d2012-11-01 22:54:43 +0800673 if (of_device_is_compatible(dn, "sirf,marco-dmac"))
674 sdma->is_marco = true;
675
Rongjun Yingca21a142011-10-27 19:22:39 -0700676 if (of_property_read_u32(dn, "cell-index", &id)) {
677 dev_err(dev, "Fail to get DMAC index\n");
Julia Lawall94d39012012-08-04 10:35:30 +0200678 return -ENODEV;
Rongjun Yingca21a142011-10-27 19:22:39 -0700679 }
680
681 sdma->irq = irq_of_parse_and_map(dn, 0);
682 if (sdma->irq == NO_IRQ) {
683 dev_err(dev, "Error mapping IRQ!\n");
Julia Lawall94d39012012-08-04 10:35:30 +0200684 return -EINVAL;
Rongjun Yingca21a142011-10-27 19:22:39 -0700685 }
686
Barry Songa7e34062013-03-18 16:33:43 +0800687 sdma->clk = devm_clk_get(dev, NULL);
688 if (IS_ERR(sdma->clk)) {
689 dev_err(dev, "failed to get a clock.\n");
690 return PTR_ERR(sdma->clk);
691 }
692
Rongjun Yingca21a142011-10-27 19:22:39 -0700693 ret = of_address_to_resource(dn, 0, &res);
694 if (ret) {
695 dev_err(dev, "Error parsing memory region!\n");
Julia Lawall94d39012012-08-04 10:35:30 +0200696 goto irq_dispose;
Rongjun Yingca21a142011-10-27 19:22:39 -0700697 }
698
699 regs_start = res.start;
700 regs_size = resource_size(&res);
701
702 sdma->base = devm_ioremap(dev, regs_start, regs_size);
703 if (!sdma->base) {
704 dev_err(dev, "Error mapping memory region!\n");
705 ret = -ENOMEM;
706 goto irq_dispose;
707 }
708
Julia Lawall94d39012012-08-04 10:35:30 +0200709 ret = request_irq(sdma->irq, &sirfsoc_dma_irq, 0, DRV_NAME, sdma);
Rongjun Yingca21a142011-10-27 19:22:39 -0700710 if (ret) {
711 dev_err(dev, "Error requesting IRQ!\n");
712 ret = -EINVAL;
Julia Lawall94d39012012-08-04 10:35:30 +0200713 goto irq_dispose;
Rongjun Yingca21a142011-10-27 19:22:39 -0700714 }
715
716 dma = &sdma->dma;
717 dma->dev = dev;
Rongjun Yingca21a142011-10-27 19:22:39 -0700718
719 dma->device_alloc_chan_resources = sirfsoc_dma_alloc_chan_resources;
720 dma->device_free_chan_resources = sirfsoc_dma_free_chan_resources;
721 dma->device_issue_pending = sirfsoc_dma_issue_pending;
Maxime Riparded14a7c2014-11-17 14:42:34 +0100722 dma->device_config = sirfsoc_dma_slave_config;
723 dma->device_pause = sirfsoc_dma_pause_chan;
724 dma->device_resume = sirfsoc_dma_resume_chan;
725 dma->device_terminate_all = sirfsoc_dma_terminate_all;
Rongjun Yingca21a142011-10-27 19:22:39 -0700726 dma->device_tx_status = sirfsoc_dma_tx_status;
727 dma->device_prep_interleaved_dma = sirfsoc_dma_prep_interleaved;
728 dma->device_prep_dma_cyclic = sirfsoc_dma_prep_cyclic;
Rongjun Yingba07d812013-12-23 20:19:21 +0800729 dma->device_slave_caps = sirfsoc_dma_device_slave_caps;
Rongjun Yingca21a142011-10-27 19:22:39 -0700730
731 INIT_LIST_HEAD(&dma->channels);
732 dma_cap_set(DMA_SLAVE, dma->cap_mask);
733 dma_cap_set(DMA_CYCLIC, dma->cap_mask);
734 dma_cap_set(DMA_INTERLEAVE, dma->cap_mask);
735 dma_cap_set(DMA_PRIVATE, dma->cap_mask);
736
Maxime Ripard35202452014-10-16 11:01:02 +0200737 for (i = 0; i < SIRFSOC_DMA_CHANNELS; i++) {
Rongjun Yingca21a142011-10-27 19:22:39 -0700738 schan = &sdma->channels[i];
739
740 schan->chan.device = dma;
Russell King - ARM Linuxd3ee98cdc2012-03-06 22:35:47 +0000741 dma_cookie_init(&schan->chan);
Rongjun Yingca21a142011-10-27 19:22:39 -0700742
743 INIT_LIST_HEAD(&schan->free);
744 INIT_LIST_HEAD(&schan->prepared);
745 INIT_LIST_HEAD(&schan->queued);
746 INIT_LIST_HEAD(&schan->active);
747 INIT_LIST_HEAD(&schan->completed);
748
749 spin_lock_init(&schan->lock);
750 list_add_tail(&schan->chan.device_node, &dma->channels);
751 }
752
753 tasklet_init(&sdma->tasklet, sirfsoc_dma_tasklet, (unsigned long)sdma);
754
755 /* Register DMA engine */
756 dev_set_drvdata(dev, sdma);
Barry Song2a766892013-07-30 17:44:34 +0800757
Rongjun Yingca21a142011-10-27 19:22:39 -0700758 ret = dma_async_device_register(dma);
759 if (ret)
760 goto free_irq;
761
Barry Song2e041c92014-03-27 15:49:31 +0800762 /* Device-tree DMA controller registration */
763 ret = of_dma_controller_register(dn, of_dma_sirfsoc_xlate, sdma);
764 if (ret) {
765 dev_err(dev, "failed to register DMA controller\n");
766 goto unreg_dma_dev;
767 }
768
Barry Song2a766892013-07-30 17:44:34 +0800769 pm_runtime_enable(&op->dev);
Rongjun Yingca21a142011-10-27 19:22:39 -0700770 dev_info(dev, "initialized SIRFSOC DMAC driver\n");
771
772 return 0;
773
Barry Song2e041c92014-03-27 15:49:31 +0800774unreg_dma_dev:
775 dma_async_device_unregister(dma);
Rongjun Yingca21a142011-10-27 19:22:39 -0700776free_irq:
Julia Lawall94d39012012-08-04 10:35:30 +0200777 free_irq(sdma->irq, sdma);
Rongjun Yingca21a142011-10-27 19:22:39 -0700778irq_dispose:
779 irq_dispose_mapping(sdma->irq);
Rongjun Yingca21a142011-10-27 19:22:39 -0700780 return ret;
781}
782
Greg Kroah-Hartman4bf27b82012-12-21 15:09:59 -0800783static int sirfsoc_dma_remove(struct platform_device *op)
Rongjun Yingca21a142011-10-27 19:22:39 -0700784{
785 struct device *dev = &op->dev;
786 struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
787
Barry Song2e041c92014-03-27 15:49:31 +0800788 of_dma_controller_free(op->dev.of_node);
Rongjun Yingca21a142011-10-27 19:22:39 -0700789 dma_async_device_unregister(&sdma->dma);
Julia Lawall94d39012012-08-04 10:35:30 +0200790 free_irq(sdma->irq, sdma);
Rongjun Yingca21a142011-10-27 19:22:39 -0700791 irq_dispose_mapping(sdma->irq);
Barry Song2a766892013-07-30 17:44:34 +0800792 pm_runtime_disable(&op->dev);
793 if (!pm_runtime_status_suspended(&op->dev))
794 sirfsoc_dma_runtime_suspend(&op->dev);
795
Rongjun Yingca21a142011-10-27 19:22:39 -0700796 return 0;
797}
798
Barry Song2a766892013-07-30 17:44:34 +0800799static int sirfsoc_dma_runtime_suspend(struct device *dev)
800{
801 struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
802
803 clk_disable_unprepare(sdma->clk);
804 return 0;
805}
806
807static int sirfsoc_dma_runtime_resume(struct device *dev)
808{
809 struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
810 int ret;
811
812 ret = clk_prepare_enable(sdma->clk);
813 if (ret < 0) {
814 dev_err(dev, "clk_enable failed: %d\n", ret);
815 return ret;
816 }
817 return 0;
818}
819
Jingoo Han33339682014-10-27 21:35:13 +0900820#ifdef CONFIG_PM_SLEEP
Barry Song2a766892013-07-30 17:44:34 +0800821static int sirfsoc_dma_pm_suspend(struct device *dev)
822{
823 struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
824 struct sirfsoc_dma_regs *save = &sdma->regs_save;
825 struct sirfsoc_dma_desc *sdesc;
826 struct sirfsoc_dma_chan *schan;
827 int ch;
828 int ret;
829
830 /*
831 * if we were runtime-suspended before, resume to enable clock
832 * before accessing register
833 */
834 if (pm_runtime_status_suspended(dev)) {
835 ret = sirfsoc_dma_runtime_resume(dev);
836 if (ret < 0)
837 return ret;
838 }
839
840 /*
841 * DMA controller will lose all registers while suspending
842 * so we need to save registers for active channels
843 */
844 for (ch = 0; ch < SIRFSOC_DMA_CHANNELS; ch++) {
845 schan = &sdma->channels[ch];
846 if (list_empty(&schan->active))
847 continue;
848 sdesc = list_first_entry(&schan->active,
849 struct sirfsoc_dma_desc,
850 node);
851 save->ctrl[ch] = readl_relaxed(sdma->base +
852 ch * 0x10 + SIRFSOC_DMA_CH_CTRL);
853 }
854 save->interrupt_en = readl_relaxed(sdma->base + SIRFSOC_DMA_INT_EN);
855
856 /* Disable clock */
857 sirfsoc_dma_runtime_suspend(dev);
858
859 return 0;
860}
861
862static int sirfsoc_dma_pm_resume(struct device *dev)
863{
864 struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
865 struct sirfsoc_dma_regs *save = &sdma->regs_save;
866 struct sirfsoc_dma_desc *sdesc;
867 struct sirfsoc_dma_chan *schan;
868 int ch;
869 int ret;
870
871 /* Enable clock before accessing register */
872 ret = sirfsoc_dma_runtime_resume(dev);
873 if (ret < 0)
874 return ret;
875
876 writel_relaxed(save->interrupt_en, sdma->base + SIRFSOC_DMA_INT_EN);
877 for (ch = 0; ch < SIRFSOC_DMA_CHANNELS; ch++) {
878 schan = &sdma->channels[ch];
879 if (list_empty(&schan->active))
880 continue;
881 sdesc = list_first_entry(&schan->active,
882 struct sirfsoc_dma_desc,
883 node);
884 writel_relaxed(sdesc->width,
885 sdma->base + SIRFSOC_DMA_WIDTH_0 + ch * 4);
886 writel_relaxed(sdesc->xlen,
887 sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_XLEN);
888 writel_relaxed(sdesc->ylen,
889 sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_YLEN);
890 writel_relaxed(save->ctrl[ch],
891 sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_CTRL);
892 writel_relaxed(sdesc->addr >> 2,
893 sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_ADDR);
894 }
895
896 /* if we were runtime-suspended before, suspend again */
897 if (pm_runtime_status_suspended(dev))
898 sirfsoc_dma_runtime_suspend(dev);
899
900 return 0;
901}
Jingoo Han33339682014-10-27 21:35:13 +0900902#endif
Barry Song2a766892013-07-30 17:44:34 +0800903
904static const struct dev_pm_ops sirfsoc_dma_pm_ops = {
905 SET_RUNTIME_PM_OPS(sirfsoc_dma_runtime_suspend, sirfsoc_dma_runtime_resume, NULL)
906 SET_SYSTEM_SLEEP_PM_OPS(sirfsoc_dma_pm_suspend, sirfsoc_dma_pm_resume)
907};
908
Rongjun Yingca21a142011-10-27 19:22:39 -0700909static struct of_device_id sirfsoc_dma_match[] = {
910 { .compatible = "sirf,prima2-dmac", },
Barry Songf7d935d2012-11-01 22:54:43 +0800911 { .compatible = "sirf,marco-dmac", },
Rongjun Yingca21a142011-10-27 19:22:39 -0700912 {},
913};
914
915static struct platform_driver sirfsoc_dma_driver = {
916 .probe = sirfsoc_dma_probe,
Bill Pembertona7d6e3e2012-11-19 13:20:04 -0500917 .remove = sirfsoc_dma_remove,
Rongjun Yingca21a142011-10-27 19:22:39 -0700918 .driver = {
919 .name = DRV_NAME,
Barry Song2a766892013-07-30 17:44:34 +0800920 .pm = &sirfsoc_dma_pm_ops,
Rongjun Yingca21a142011-10-27 19:22:39 -0700921 .of_match_table = sirfsoc_dma_match,
922 },
923};
924
Barry Song42361f22013-04-11 14:09:28 +0800925static __init int sirfsoc_dma_init(void)
926{
927 return platform_driver_register(&sirfsoc_dma_driver);
928}
929
930static void __exit sirfsoc_dma_exit(void)
931{
932 platform_driver_unregister(&sirfsoc_dma_driver);
933}
934
935subsys_initcall(sirfsoc_dma_init);
936module_exit(sirfsoc_dma_exit);
Rongjun Yingca21a142011-10-27 19:22:39 -0700937
938MODULE_AUTHOR("Rongjun Ying <rongjun.ying@csr.com>, "
939 "Barry Song <baohua.song@csr.com>");
940MODULE_DESCRIPTION("SIRFSOC DMA control driver");
941MODULE_LICENSE("GPL v2");