blob: 250bc7baa00a13f9166614c621ed433a8e481afd [file] [log] [blame]
Colin Cross4de3a8f2010-04-05 13:16:42 -07001/*
2 * arch/arm/mach-tegra/dma.c
3 *
4 * System DMA driver for NVIDIA Tegra SoCs
5 *
6 * Copyright (c) 2008-2009, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#include <linux/io.h>
24#include <linux/interrupt.h>
25#include <linux/module.h>
26#include <linux/spinlock.h>
27#include <linux/err.h>
28#include <linux/irq.h>
29#include <linux/delay.h>
30#include <mach/dma.h>
31#include <mach/irqs.h>
32#include <mach/iomap.h>
Colin Cross2ea67fd2010-10-04 08:49:49 -070033#include <mach/suspend.h>
Colin Cross4de3a8f2010-04-05 13:16:42 -070034
35#define APB_DMA_GEN 0x000
36#define GEN_ENABLE (1<<31)
37
38#define APB_DMA_CNTRL 0x010
39
40#define APB_DMA_IRQ_MASK 0x01c
41
42#define APB_DMA_IRQ_MASK_SET 0x020
43
44#define APB_DMA_CHAN_CSR 0x000
45#define CSR_ENB (1<<31)
46#define CSR_IE_EOC (1<<30)
47#define CSR_HOLD (1<<29)
48#define CSR_DIR (1<<28)
49#define CSR_ONCE (1<<27)
50#define CSR_FLOW (1<<21)
51#define CSR_REQ_SEL_SHIFT 16
52#define CSR_REQ_SEL_MASK (0x1F<<CSR_REQ_SEL_SHIFT)
53#define CSR_REQ_SEL_INVALID (31<<CSR_REQ_SEL_SHIFT)
54#define CSR_WCOUNT_SHIFT 2
55#define CSR_WCOUNT_MASK 0xFFFC
56
57#define APB_DMA_CHAN_STA 0x004
58#define STA_BUSY (1<<31)
59#define STA_ISE_EOC (1<<30)
60#define STA_HALT (1<<29)
61#define STA_PING_PONG (1<<28)
62#define STA_COUNT_SHIFT 2
63#define STA_COUNT_MASK 0xFFFC
64
65#define APB_DMA_CHAN_AHB_PTR 0x010
66
67#define APB_DMA_CHAN_AHB_SEQ 0x014
68#define AHB_SEQ_INTR_ENB (1<<31)
69#define AHB_SEQ_BUS_WIDTH_SHIFT 28
70#define AHB_SEQ_BUS_WIDTH_MASK (0x7<<AHB_SEQ_BUS_WIDTH_SHIFT)
71#define AHB_SEQ_BUS_WIDTH_8 (0<<AHB_SEQ_BUS_WIDTH_SHIFT)
72#define AHB_SEQ_BUS_WIDTH_16 (1<<AHB_SEQ_BUS_WIDTH_SHIFT)
73#define AHB_SEQ_BUS_WIDTH_32 (2<<AHB_SEQ_BUS_WIDTH_SHIFT)
74#define AHB_SEQ_BUS_WIDTH_64 (3<<AHB_SEQ_BUS_WIDTH_SHIFT)
75#define AHB_SEQ_BUS_WIDTH_128 (4<<AHB_SEQ_BUS_WIDTH_SHIFT)
76#define AHB_SEQ_DATA_SWAP (1<<27)
77#define AHB_SEQ_BURST_MASK (0x7<<24)
78#define AHB_SEQ_BURST_1 (4<<24)
79#define AHB_SEQ_BURST_4 (5<<24)
80#define AHB_SEQ_BURST_8 (6<<24)
81#define AHB_SEQ_DBL_BUF (1<<19)
82#define AHB_SEQ_WRAP_SHIFT 16
83#define AHB_SEQ_WRAP_MASK (0x7<<AHB_SEQ_WRAP_SHIFT)
84
85#define APB_DMA_CHAN_APB_PTR 0x018
86
87#define APB_DMA_CHAN_APB_SEQ 0x01c
88#define APB_SEQ_BUS_WIDTH_SHIFT 28
89#define APB_SEQ_BUS_WIDTH_MASK (0x7<<APB_SEQ_BUS_WIDTH_SHIFT)
90#define APB_SEQ_BUS_WIDTH_8 (0<<APB_SEQ_BUS_WIDTH_SHIFT)
91#define APB_SEQ_BUS_WIDTH_16 (1<<APB_SEQ_BUS_WIDTH_SHIFT)
92#define APB_SEQ_BUS_WIDTH_32 (2<<APB_SEQ_BUS_WIDTH_SHIFT)
93#define APB_SEQ_BUS_WIDTH_64 (3<<APB_SEQ_BUS_WIDTH_SHIFT)
94#define APB_SEQ_BUS_WIDTH_128 (4<<APB_SEQ_BUS_WIDTH_SHIFT)
95#define APB_SEQ_DATA_SWAP (1<<27)
96#define APB_SEQ_WRAP_SHIFT 16
97#define APB_SEQ_WRAP_MASK (0x7<<APB_SEQ_WRAP_SHIFT)
98
99#define TEGRA_SYSTEM_DMA_CH_NR 16
100#define TEGRA_SYSTEM_DMA_AVP_CH_NUM 4
101#define TEGRA_SYSTEM_DMA_CH_MIN 0
102#define TEGRA_SYSTEM_DMA_CH_MAX \
103 (TEGRA_SYSTEM_DMA_CH_NR - TEGRA_SYSTEM_DMA_AVP_CH_NUM - 1)
104
105#define NV_DMA_MAX_TRASFER_SIZE 0x10000
106
107const unsigned int ahb_addr_wrap_table[8] = {
108 0, 32, 64, 128, 256, 512, 1024, 2048
109};
110
111const unsigned int apb_addr_wrap_table[8] = {0, 1, 2, 4, 8, 16, 32, 64};
112
113const unsigned int bus_width_table[5] = {8, 16, 32, 64, 128};
114
115#define TEGRA_DMA_NAME_SIZE 16
116struct tegra_dma_channel {
117 struct list_head list;
118 int id;
119 spinlock_t lock;
120 char name[TEGRA_DMA_NAME_SIZE];
121 void __iomem *addr;
122 int mode;
123 int irq;
Colin Cross5789fee2010-08-18 00:19:12 -0700124 int req_transfer_count;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700125};
126
127#define NV_DMA_MAX_CHANNELS 32
128
Colin Cross5789fee2010-08-18 00:19:12 -0700129static DEFINE_MUTEX(tegra_dma_lock);
130
Colin Cross4de3a8f2010-04-05 13:16:42 -0700131static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS);
132static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS];
133
134static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
135 struct tegra_dma_req *req);
136static void tegra_dma_update_hw_partial(struct tegra_dma_channel *ch,
137 struct tegra_dma_req *req);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700138static void tegra_dma_stop(struct tegra_dma_channel *ch);
139
140void tegra_dma_flush(struct tegra_dma_channel *ch)
141{
142}
143EXPORT_SYMBOL(tegra_dma_flush);
144
145void tegra_dma_dequeue(struct tegra_dma_channel *ch)
146{
147 struct tegra_dma_req *req;
148
Colin Cross5789fee2010-08-18 00:19:12 -0700149 if (tegra_dma_is_empty(ch))
150 return;
151
Colin Cross4de3a8f2010-04-05 13:16:42 -0700152 req = list_entry(ch->list.next, typeof(*req), node);
153
154 tegra_dma_dequeue_req(ch, req);
155 return;
156}
157
158void tegra_dma_stop(struct tegra_dma_channel *ch)
159{
Colin Cross5789fee2010-08-18 00:19:12 -0700160 u32 csr;
161 u32 status;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700162
Colin Cross5789fee2010-08-18 00:19:12 -0700163 csr = readl(ch->addr + APB_DMA_CHAN_CSR);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700164 csr &= ~CSR_IE_EOC;
165 writel(csr, ch->addr + APB_DMA_CHAN_CSR);
166
167 csr &= ~CSR_ENB;
168 writel(csr, ch->addr + APB_DMA_CHAN_CSR);
169
170 status = readl(ch->addr + APB_DMA_CHAN_STA);
171 if (status & STA_ISE_EOC)
172 writel(status, ch->addr + APB_DMA_CHAN_STA);
173}
174
175int tegra_dma_cancel(struct tegra_dma_channel *ch)
176{
Colin Cross5789fee2010-08-18 00:19:12 -0700177 u32 csr;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700178 unsigned long irq_flags;
179
180 spin_lock_irqsave(&ch->lock, irq_flags);
181 while (!list_empty(&ch->list))
182 list_del(ch->list.next);
183
Colin Cross5789fee2010-08-18 00:19:12 -0700184 csr = readl(ch->addr + APB_DMA_CHAN_CSR);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700185 csr &= ~CSR_REQ_SEL_MASK;
186 csr |= CSR_REQ_SEL_INVALID;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700187 writel(csr, ch->addr + APB_DMA_CHAN_CSR);
188
189 tegra_dma_stop(ch);
190
191 spin_unlock_irqrestore(&ch->lock, irq_flags);
192 return 0;
193}
194
195int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
196 struct tegra_dma_req *_req)
197{
198 unsigned int csr;
199 unsigned int status;
200 struct tegra_dma_req *req = NULL;
201 int found = 0;
202 unsigned long irq_flags;
203 int to_transfer;
204 int req_transfer_count;
205
206 spin_lock_irqsave(&ch->lock, irq_flags);
207 list_for_each_entry(req, &ch->list, node) {
208 if (req == _req) {
209 list_del(&req->node);
210 found = 1;
211 break;
212 }
213 }
214 if (!found) {
215 spin_unlock_irqrestore(&ch->lock, irq_flags);
216 return 0;
217 }
218
219 /* STOP the DMA and get the transfer count.
220 * Getting the transfer count is tricky.
221 * - Change the source selector to invalid to stop the DMA from
222 * FIFO to memory.
223 * - Read the status register to know the number of pending
224 * bytes to be transfered.
225 * - Finally stop or program the DMA to the next buffer in the
226 * list.
227 */
Colin Cross5789fee2010-08-18 00:19:12 -0700228 csr = readl(ch->addr + APB_DMA_CHAN_CSR);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700229 csr &= ~CSR_REQ_SEL_MASK;
230 csr |= CSR_REQ_SEL_INVALID;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700231 writel(csr, ch->addr + APB_DMA_CHAN_CSR);
232
233 /* Get the transfer count */
234 status = readl(ch->addr + APB_DMA_CHAN_STA);
235 to_transfer = (status & STA_COUNT_MASK) >> STA_COUNT_SHIFT;
Colin Cross5789fee2010-08-18 00:19:12 -0700236 req_transfer_count = ch->req_transfer_count;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700237 req_transfer_count += 1;
238 to_transfer += 1;
239
240 req->bytes_transferred = req_transfer_count;
241
242 if (status & STA_BUSY)
243 req->bytes_transferred -= to_transfer;
244
245 /* In continous transfer mode, DMA only tracks the count of the
246 * half DMA buffer. So, if the DMA already finished half the DMA
247 * then add the half buffer to the completed count.
248 *
249 * FIXME: There can be a race here. What if the req to
250 * dequue happens at the same time as the DMA just moved to
251 * the new buffer and SW didn't yet received the interrupt?
252 */
253 if (ch->mode & TEGRA_DMA_MODE_CONTINOUS)
254 if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
255 req->bytes_transferred += req_transfer_count;
256
257 req->bytes_transferred *= 4;
258
259 tegra_dma_stop(ch);
260 if (!list_empty(&ch->list)) {
261 /* if the list is not empty, queue the next request */
262 struct tegra_dma_req *next_req;
263 next_req = list_entry(ch->list.next,
264 typeof(*next_req), node);
265 tegra_dma_update_hw(ch, next_req);
266 }
267 req->status = -TEGRA_DMA_REQ_ERROR_ABORTED;
268
269 spin_unlock_irqrestore(&ch->lock, irq_flags);
270
271 /* Callback should be called without any lock */
272 req->complete(req);
273 return 0;
274}
275EXPORT_SYMBOL(tegra_dma_dequeue_req);
276
277bool tegra_dma_is_empty(struct tegra_dma_channel *ch)
278{
279 unsigned long irq_flags;
280 bool is_empty;
281
282 spin_lock_irqsave(&ch->lock, irq_flags);
283 if (list_empty(&ch->list))
284 is_empty = true;
285 else
286 is_empty = false;
287 spin_unlock_irqrestore(&ch->lock, irq_flags);
288 return is_empty;
289}
290EXPORT_SYMBOL(tegra_dma_is_empty);
291
292bool tegra_dma_is_req_inflight(struct tegra_dma_channel *ch,
293 struct tegra_dma_req *_req)
294{
295 unsigned long irq_flags;
296 struct tegra_dma_req *req;
297
298 spin_lock_irqsave(&ch->lock, irq_flags);
299 list_for_each_entry(req, &ch->list, node) {
300 if (req == _req) {
301 spin_unlock_irqrestore(&ch->lock, irq_flags);
302 return true;
303 }
304 }
305 spin_unlock_irqrestore(&ch->lock, irq_flags);
306 return false;
307}
308EXPORT_SYMBOL(tegra_dma_is_req_inflight);
309
310int tegra_dma_enqueue_req(struct tegra_dma_channel *ch,
311 struct tegra_dma_req *req)
312{
313 unsigned long irq_flags;
314 int start_dma = 0;
315
316 if (req->size > NV_DMA_MAX_TRASFER_SIZE ||
317 req->source_addr & 0x3 || req->dest_addr & 0x3) {
318 pr_err("Invalid DMA request for channel %d\n", ch->id);
319 return -EINVAL;
320 }
321
322 spin_lock_irqsave(&ch->lock, irq_flags);
323
324 req->bytes_transferred = 0;
325 req->status = 0;
326 req->buffer_status = 0;
327 if (list_empty(&ch->list))
328 start_dma = 1;
329
330 list_add_tail(&req->node, &ch->list);
331
332 if (start_dma)
333 tegra_dma_update_hw(ch, req);
334
335 spin_unlock_irqrestore(&ch->lock, irq_flags);
336
337 return 0;
338}
339EXPORT_SYMBOL(tegra_dma_enqueue_req);
340
341struct tegra_dma_channel *tegra_dma_allocate_channel(int mode)
342{
343 int channel;
Colin Cross5789fee2010-08-18 00:19:12 -0700344 struct tegra_dma_channel *ch = NULL;
345
346 mutex_lock(&tegra_dma_lock);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700347
348 /* first channel is the shared channel */
349 if (mode & TEGRA_DMA_SHARED) {
350 channel = TEGRA_SYSTEM_DMA_CH_MIN;
351 } else {
352 channel = find_first_zero_bit(channel_usage,
353 ARRAY_SIZE(dma_channels));
354 if (channel >= ARRAY_SIZE(dma_channels))
Colin Cross5789fee2010-08-18 00:19:12 -0700355 goto out;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700356 }
357 __set_bit(channel, channel_usage);
358 ch = &dma_channels[channel];
359 ch->mode = mode;
Colin Cross5789fee2010-08-18 00:19:12 -0700360
361out:
362 mutex_unlock(&tegra_dma_lock);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700363 return ch;
364}
365EXPORT_SYMBOL(tegra_dma_allocate_channel);
366
367void tegra_dma_free_channel(struct tegra_dma_channel *ch)
368{
369 if (ch->mode & TEGRA_DMA_SHARED)
370 return;
371 tegra_dma_cancel(ch);
Colin Cross5789fee2010-08-18 00:19:12 -0700372 mutex_lock(&tegra_dma_lock);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700373 __clear_bit(ch->id, channel_usage);
Colin Cross5789fee2010-08-18 00:19:12 -0700374 mutex_unlock(&tegra_dma_lock);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700375}
376EXPORT_SYMBOL(tegra_dma_free_channel);
377
378static void tegra_dma_update_hw_partial(struct tegra_dma_channel *ch,
379 struct tegra_dma_req *req)
380{
Colin Cross5789fee2010-08-18 00:19:12 -0700381 u32 apb_ptr;
382 u32 ahb_ptr;
383
Colin Cross4de3a8f2010-04-05 13:16:42 -0700384 if (req->to_memory) {
Colin Cross5789fee2010-08-18 00:19:12 -0700385 apb_ptr = req->source_addr;
386 ahb_ptr = req->dest_addr;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700387 } else {
Colin Cross5789fee2010-08-18 00:19:12 -0700388 apb_ptr = req->dest_addr;
389 ahb_ptr = req->source_addr;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700390 }
Colin Cross5789fee2010-08-18 00:19:12 -0700391 writel(apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
392 writel(ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700393
394 req->status = TEGRA_DMA_REQ_INFLIGHT;
395 return;
396}
397
398static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
399 struct tegra_dma_req *req)
400{
401 int ahb_addr_wrap;
402 int apb_addr_wrap;
403 int ahb_bus_width;
404 int apb_bus_width;
405 int index;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700406
Colin Cross5789fee2010-08-18 00:19:12 -0700407 u32 ahb_seq;
408 u32 apb_seq;
409 u32 ahb_ptr;
410 u32 apb_ptr;
411 u32 csr;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700412
Colin Cross5789fee2010-08-18 00:19:12 -0700413 csr = CSR_IE_EOC | CSR_FLOW;
414 ahb_seq = AHB_SEQ_INTR_ENB | AHB_SEQ_BURST_1;
415 apb_seq = 0;
416
417 csr |= req->req_sel << CSR_REQ_SEL_SHIFT;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700418
419 /* One shot mode is always single buffered,
420 * continuous mode is always double buffered
421 * */
422 if (ch->mode & TEGRA_DMA_MODE_ONESHOT) {
Colin Cross5789fee2010-08-18 00:19:12 -0700423 csr |= CSR_ONCE;
424 ch->req_transfer_count = (req->size >> 2) - 1;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700425 } else {
Colin Cross5789fee2010-08-18 00:19:12 -0700426 ahb_seq |= AHB_SEQ_DBL_BUF;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700427
428 /* In double buffered mode, we set the size to half the
429 * requested size and interrupt when half the buffer
430 * is full */
Colin Cross5789fee2010-08-18 00:19:12 -0700431 ch->req_transfer_count = (req->size >> 3) - 1;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700432 }
433
Colin Cross5789fee2010-08-18 00:19:12 -0700434 csr |= ch->req_transfer_count << CSR_WCOUNT_SHIFT;
435
Colin Cross4de3a8f2010-04-05 13:16:42 -0700436 if (req->to_memory) {
Colin Cross5789fee2010-08-18 00:19:12 -0700437 apb_ptr = req->source_addr;
438 ahb_ptr = req->dest_addr;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700439
440 apb_addr_wrap = req->source_wrap;
441 ahb_addr_wrap = req->dest_wrap;
442 apb_bus_width = req->source_bus_width;
443 ahb_bus_width = req->dest_bus_width;
444
445 } else {
Colin Cross5789fee2010-08-18 00:19:12 -0700446 csr |= CSR_DIR;
447 apb_ptr = req->dest_addr;
448 ahb_ptr = req->source_addr;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700449
450 apb_addr_wrap = req->dest_wrap;
451 ahb_addr_wrap = req->source_wrap;
452 apb_bus_width = req->dest_bus_width;
453 ahb_bus_width = req->source_bus_width;
454 }
455
456 apb_addr_wrap >>= 2;
457 ahb_addr_wrap >>= 2;
458
459 /* set address wrap for APB size */
460 index = 0;
461 do {
462 if (apb_addr_wrap_table[index] == apb_addr_wrap)
463 break;
464 index++;
465 } while (index < ARRAY_SIZE(apb_addr_wrap_table));
466 BUG_ON(index == ARRAY_SIZE(apb_addr_wrap_table));
Colin Cross5789fee2010-08-18 00:19:12 -0700467 apb_seq |= index << APB_SEQ_WRAP_SHIFT;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700468
469 /* set address wrap for AHB size */
470 index = 0;
471 do {
472 if (ahb_addr_wrap_table[index] == ahb_addr_wrap)
473 break;
474 index++;
475 } while (index < ARRAY_SIZE(ahb_addr_wrap_table));
476 BUG_ON(index == ARRAY_SIZE(ahb_addr_wrap_table));
Colin Cross5789fee2010-08-18 00:19:12 -0700477 ahb_seq |= index << AHB_SEQ_WRAP_SHIFT;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700478
479 for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) {
480 if (bus_width_table[index] == ahb_bus_width)
481 break;
482 }
483 BUG_ON(index == ARRAY_SIZE(bus_width_table));
Colin Cross5789fee2010-08-18 00:19:12 -0700484 ahb_seq |= index << AHB_SEQ_BUS_WIDTH_SHIFT;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700485
486 for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) {
487 if (bus_width_table[index] == apb_bus_width)
488 break;
489 }
490 BUG_ON(index == ARRAY_SIZE(bus_width_table));
Colin Cross5789fee2010-08-18 00:19:12 -0700491 apb_seq |= index << APB_SEQ_BUS_WIDTH_SHIFT;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700492
Colin Cross5789fee2010-08-18 00:19:12 -0700493 writel(csr, ch->addr + APB_DMA_CHAN_CSR);
494 writel(apb_seq, ch->addr + APB_DMA_CHAN_APB_SEQ);
495 writel(apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
496 writel(ahb_seq, ch->addr + APB_DMA_CHAN_AHB_SEQ);
497 writel(ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700498
Colin Cross5789fee2010-08-18 00:19:12 -0700499 csr |= CSR_ENB;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700500 writel(csr, ch->addr + APB_DMA_CHAN_CSR);
501
502 req->status = TEGRA_DMA_REQ_INFLIGHT;
503}
504
Colin Cross4de3a8f2010-04-05 13:16:42 -0700505static void handle_oneshot_dma(struct tegra_dma_channel *ch)
506{
507 struct tegra_dma_req *req;
Colin Cross5789fee2010-08-18 00:19:12 -0700508 unsigned long irq_flags;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700509
Colin Cross5789fee2010-08-18 00:19:12 -0700510 spin_lock_irqsave(&ch->lock, irq_flags);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700511 if (list_empty(&ch->list)) {
Colin Cross5789fee2010-08-18 00:19:12 -0700512 spin_unlock_irqrestore(&ch->lock, irq_flags);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700513 return;
514 }
515
516 req = list_entry(ch->list.next, typeof(*req), node);
517 if (req) {
518 int bytes_transferred;
519
Colin Cross5789fee2010-08-18 00:19:12 -0700520 bytes_transferred = ch->req_transfer_count;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700521 bytes_transferred += 1;
522 bytes_transferred <<= 2;
523
524 list_del(&req->node);
525 req->bytes_transferred = bytes_transferred;
526 req->status = TEGRA_DMA_REQ_SUCCESS;
527
Colin Cross5789fee2010-08-18 00:19:12 -0700528 spin_unlock_irqrestore(&ch->lock, irq_flags);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700529 /* Callback should be called without any lock */
530 pr_debug("%s: transferred %d bytes\n", __func__,
531 req->bytes_transferred);
532 req->complete(req);
Colin Cross5789fee2010-08-18 00:19:12 -0700533 spin_lock_irqsave(&ch->lock, irq_flags);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700534 }
535
536 if (!list_empty(&ch->list)) {
537 req = list_entry(ch->list.next, typeof(*req), node);
538 /* the complete function we just called may have enqueued
539 another req, in which case dma has already started */
540 if (req->status != TEGRA_DMA_REQ_INFLIGHT)
541 tegra_dma_update_hw(ch, req);
542 }
Colin Cross5789fee2010-08-18 00:19:12 -0700543 spin_unlock_irqrestore(&ch->lock, irq_flags);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700544}
545
546static void handle_continuous_dma(struct tegra_dma_channel *ch)
547{
548 struct tegra_dma_req *req;
Colin Cross5789fee2010-08-18 00:19:12 -0700549 unsigned long irq_flags;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700550
Colin Cross5789fee2010-08-18 00:19:12 -0700551 spin_lock_irqsave(&ch->lock, irq_flags);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700552 if (list_empty(&ch->list)) {
Colin Cross5789fee2010-08-18 00:19:12 -0700553 spin_unlock_irqrestore(&ch->lock, irq_flags);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700554 return;
555 }
556
557 req = list_entry(ch->list.next, typeof(*req), node);
558 if (req) {
559 if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_EMPTY) {
Colin Cross5789fee2010-08-18 00:19:12 -0700560 bool is_dma_ping_complete;
561 is_dma_ping_complete = (readl(ch->addr + APB_DMA_CHAN_STA)
562 & STA_PING_PONG) ? true : false;
563 if (req->to_memory)
564 is_dma_ping_complete = !is_dma_ping_complete;
565 /* Out of sync - Release current buffer */
566 if (!is_dma_ping_complete) {
567 int bytes_transferred;
568
569 bytes_transferred = ch->req_transfer_count;
570 bytes_transferred += 1;
571 bytes_transferred <<= 3;
572 req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_FULL;
573 req->bytes_transferred = bytes_transferred;
574 req->status = TEGRA_DMA_REQ_SUCCESS;
575 tegra_dma_stop(ch);
576
577 if (!list_is_last(&req->node, &ch->list)) {
578 struct tegra_dma_req *next_req;
579
580 next_req = list_entry(req->node.next,
581 typeof(*next_req), node);
582 tegra_dma_update_hw(ch, next_req);
583 }
584
585 list_del(&req->node);
586
587 /* DMA lock is NOT held when callbak is called */
588 spin_unlock_irqrestore(&ch->lock, irq_flags);
589 req->complete(req);
590 return;
591 }
Colin Cross4de3a8f2010-04-05 13:16:42 -0700592 /* Load the next request into the hardware, if available
593 * */
594 if (!list_is_last(&req->node, &ch->list)) {
595 struct tegra_dma_req *next_req;
596
597 next_req = list_entry(req->node.next,
598 typeof(*next_req), node);
599 tegra_dma_update_hw_partial(ch, next_req);
600 }
601 req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL;
602 req->status = TEGRA_DMA_REQ_SUCCESS;
603 /* DMA lock is NOT held when callback is called */
Colin Cross5789fee2010-08-18 00:19:12 -0700604 spin_unlock_irqrestore(&ch->lock, irq_flags);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700605 if (likely(req->threshold))
606 req->threshold(req);
607 return;
608
609 } else if (req->buffer_status ==
610 TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) {
611 /* Callback when the buffer is completely full (i.e on
612 * the second interrupt */
613 int bytes_transferred;
614
Colin Cross5789fee2010-08-18 00:19:12 -0700615 bytes_transferred = ch->req_transfer_count;
Colin Cross4de3a8f2010-04-05 13:16:42 -0700616 bytes_transferred += 1;
617 bytes_transferred <<= 3;
618
619 req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_FULL;
620 req->bytes_transferred = bytes_transferred;
621 req->status = TEGRA_DMA_REQ_SUCCESS;
622 list_del(&req->node);
623
624 /* DMA lock is NOT held when callbak is called */
Colin Cross5789fee2010-08-18 00:19:12 -0700625 spin_unlock_irqrestore(&ch->lock, irq_flags);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700626 req->complete(req);
627 return;
628
629 } else {
630 BUG();
631 }
632 }
Colin Cross5789fee2010-08-18 00:19:12 -0700633 spin_unlock_irqrestore(&ch->lock, irq_flags);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700634}
635
636static irqreturn_t dma_isr(int irq, void *data)
637{
638 struct tegra_dma_channel *ch = data;
639 unsigned long status;
640
641 status = readl(ch->addr + APB_DMA_CHAN_STA);
642 if (status & STA_ISE_EOC)
643 writel(status, ch->addr + APB_DMA_CHAN_STA);
644 else {
645 pr_warning("Got a spurious ISR for DMA channel %d\n", ch->id);
646 return IRQ_HANDLED;
647 }
648 return IRQ_WAKE_THREAD;
649}
650
651static irqreturn_t dma_thread_fn(int irq, void *data)
652{
653 struct tegra_dma_channel *ch = data;
654
655 if (ch->mode & TEGRA_DMA_MODE_ONESHOT)
656 handle_oneshot_dma(ch);
657 else
658 handle_continuous_dma(ch);
659
660
661 return IRQ_HANDLED;
662}
663
664int __init tegra_dma_init(void)
665{
666 int ret = 0;
667 int i;
668 unsigned int irq;
669 void __iomem *addr;
670
671 addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
672 writel(GEN_ENABLE, addr + APB_DMA_GEN);
673 writel(0, addr + APB_DMA_CNTRL);
674 writel(0xFFFFFFFFul >> (31 - TEGRA_SYSTEM_DMA_CH_MAX),
675 addr + APB_DMA_IRQ_MASK_SET);
676
677 memset(channel_usage, 0, sizeof(channel_usage));
678 memset(dma_channels, 0, sizeof(dma_channels));
679
680 /* Reserve all the channels we are not supposed to touch */
681 for (i = 0; i < TEGRA_SYSTEM_DMA_CH_MIN; i++)
682 __set_bit(i, channel_usage);
683
684 for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) {
685 struct tegra_dma_channel *ch = &dma_channels[i];
686
687 __clear_bit(i, channel_usage);
688
689 ch->id = i;
690 snprintf(ch->name, TEGRA_DMA_NAME_SIZE, "dma_channel_%d", i);
691
692 ch->addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
693 TEGRA_APB_DMA_CH0_SIZE * i);
694
695 spin_lock_init(&ch->lock);
696 INIT_LIST_HEAD(&ch->list);
Colin Cross4de3a8f2010-04-05 13:16:42 -0700697
698 irq = INT_APB_DMA_CH0 + i;
699 ret = request_threaded_irq(irq, dma_isr, dma_thread_fn, 0,
700 dma_channels[i].name, ch);
701 if (ret) {
702 pr_err("Failed to register IRQ %d for DMA %d\n",
703 irq, i);
704 goto fail;
705 }
706 ch->irq = irq;
707 }
708 /* mark the shared channel allocated */
709 __set_bit(TEGRA_SYSTEM_DMA_CH_MIN, channel_usage);
710
711 for (i = TEGRA_SYSTEM_DMA_CH_MAX+1; i < NV_DMA_MAX_CHANNELS; i++)
712 __set_bit(i, channel_usage);
713
714 return ret;
715fail:
716 writel(0, addr + APB_DMA_GEN);
717 for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) {
718 struct tegra_dma_channel *ch = &dma_channels[i];
719 if (ch->irq)
720 free_irq(ch->irq, ch);
721 }
722 return ret;
723}
724
725#ifdef CONFIG_PM
726static u32 apb_dma[5*TEGRA_SYSTEM_DMA_CH_NR + 3];
727
728void tegra_dma_suspend(void)
729{
730 void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
731 u32 *ctx = apb_dma;
732 int i;
733
734 *ctx++ = readl(addr + APB_DMA_GEN);
735 *ctx++ = readl(addr + APB_DMA_CNTRL);
736 *ctx++ = readl(addr + APB_DMA_IRQ_MASK);
737
738 for (i = 0; i < TEGRA_SYSTEM_DMA_CH_NR; i++) {
739 addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
740 TEGRA_APB_DMA_CH0_SIZE * i);
741
742 *ctx++ = readl(addr + APB_DMA_CHAN_CSR);
743 *ctx++ = readl(addr + APB_DMA_CHAN_AHB_PTR);
744 *ctx++ = readl(addr + APB_DMA_CHAN_AHB_SEQ);
745 *ctx++ = readl(addr + APB_DMA_CHAN_APB_PTR);
746 *ctx++ = readl(addr + APB_DMA_CHAN_APB_SEQ);
747 }
748}
749
750void tegra_dma_resume(void)
751{
752 void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
753 u32 *ctx = apb_dma;
754 int i;
755
756 writel(*ctx++, addr + APB_DMA_GEN);
757 writel(*ctx++, addr + APB_DMA_CNTRL);
758 writel(*ctx++, addr + APB_DMA_IRQ_MASK);
759
760 for (i = 0; i < TEGRA_SYSTEM_DMA_CH_NR; i++) {
761 addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
762 TEGRA_APB_DMA_CH0_SIZE * i);
763
764 writel(*ctx++, addr + APB_DMA_CHAN_CSR);
765 writel(*ctx++, addr + APB_DMA_CHAN_AHB_PTR);
766 writel(*ctx++, addr + APB_DMA_CHAN_AHB_SEQ);
767 writel(*ctx++, addr + APB_DMA_CHAN_APB_PTR);
768 writel(*ctx++, addr + APB_DMA_CHAN_APB_SEQ);
769 }
770}
771
772#endif