2 * drivers/media/video/omap24xxcam-dma.c
4 * Copyright (C) 2004 MontaVista Software, Inc.
5 * Copyright (C) 2004 Texas Instruments.
6 * Copyright (C) 2007 Nokia Corporation.
8 * Contact: Sakari Ailus <sakari.ailus@nokia.com>
10 * Based on code from Andy Lowe <source@mvista.com> and
11 * David Cohen <david.cohen@indt.org.br>.
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * version 2 as published by the Free Software Foundation.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
28 #include <linux/kernel.h>
30 #include <linux/scatterlist.h>
32 #include "omap24xxcam.h"
40 /* Ack all interrupt on CSR and IRQSTATUS_L0 */
41 static void omap24xxcam_dmahw_ack_all(unsigned long base
)
46 for (i
= 0; i
< NUM_CAMDMA_CHANNELS
; ++i
) {
47 csr
= omap24xxcam_reg_in(base
, CAMDMA_CSR(i
));
48 /* ack interrupt in CSR */
49 omap24xxcam_reg_out(base
, CAMDMA_CSR(i
), csr
);
51 omap24xxcam_reg_out(base
, CAMDMA_IRQSTATUS_L0
, 0xf);
54 /* Ack dmach on CSR and IRQSTATUS_L0 */
55 static u32
omap24xxcam_dmahw_ack_ch(unsigned long base
, int dmach
)
59 csr
= omap24xxcam_reg_in(base
, CAMDMA_CSR(dmach
));
60 /* ack interrupt in CSR */
61 omap24xxcam_reg_out(base
, CAMDMA_CSR(dmach
), csr
);
62 /* ack interrupt in IRQSTATUS */
63 omap24xxcam_reg_out(base
, CAMDMA_IRQSTATUS_L0
, (1 << dmach
));
68 static int omap24xxcam_dmahw_running(unsigned long base
, int dmach
)
70 return omap24xxcam_reg_in(base
, CAMDMA_CCR(dmach
)) & CAMDMA_CCR_ENABLE
;
73 static void omap24xxcam_dmahw_transfer_setup(unsigned long base
, int dmach
,
74 dma_addr_t start
, u32 len
)
76 omap24xxcam_reg_out(base
, CAMDMA_CCR(dmach
),
77 CAMDMA_CCR_SEL_SRC_DST_SYNC
79 | CAMDMA_CCR_DST_AMODE_POST_INC
80 | CAMDMA_CCR_SRC_AMODE_POST_INC
82 | CAMDMA_CCR_WR_ACTIVE
83 | CAMDMA_CCR_RD_ACTIVE
84 | CAMDMA_CCR_SYNCHRO_CAMERA
);
85 omap24xxcam_reg_out(base
, CAMDMA_CLNK_CTRL(dmach
), 0);
86 omap24xxcam_reg_out(base
, CAMDMA_CEN(dmach
), len
);
87 omap24xxcam_reg_out(base
, CAMDMA_CFN(dmach
), 1);
88 omap24xxcam_reg_out(base
, CAMDMA_CSDP(dmach
),
89 CAMDMA_CSDP_WRITE_MODE_POSTED
90 | CAMDMA_CSDP_DST_BURST_EN_32
91 | CAMDMA_CSDP_DST_PACKED
92 | CAMDMA_CSDP_SRC_BURST_EN_32
93 | CAMDMA_CSDP_SRC_PACKED
94 | CAMDMA_CSDP_DATA_TYPE_8BITS
);
95 omap24xxcam_reg_out(base
, CAMDMA_CSSA(dmach
), 0);
96 omap24xxcam_reg_out(base
, CAMDMA_CDSA(dmach
), start
);
97 omap24xxcam_reg_out(base
, CAMDMA_CSEI(dmach
), 0);
98 omap24xxcam_reg_out(base
, CAMDMA_CSFI(dmach
), DMA_THRESHOLD
);
99 omap24xxcam_reg_out(base
, CAMDMA_CDEI(dmach
), 0);
100 omap24xxcam_reg_out(base
, CAMDMA_CDFI(dmach
), 0);
101 omap24xxcam_reg_out(base
, CAMDMA_CSR(dmach
),
102 CAMDMA_CSR_MISALIGNED_ERR
103 | CAMDMA_CSR_SECURE_ERR
104 | CAMDMA_CSR_TRANS_ERR
107 omap24xxcam_reg_out(base
, CAMDMA_CICR(dmach
),
108 CAMDMA_CICR_MISALIGNED_ERR_IE
109 | CAMDMA_CICR_SECURE_ERR_IE
110 | CAMDMA_CICR_TRANS_ERR_IE
111 | CAMDMA_CICR_BLOCK_IE
112 | CAMDMA_CICR_DROP_IE
);
115 static void omap24xxcam_dmahw_transfer_start(unsigned long base
, int dmach
)
117 omap24xxcam_reg_out(base
, CAMDMA_CCR(dmach
),
118 CAMDMA_CCR_SEL_SRC_DST_SYNC
120 | CAMDMA_CCR_DST_AMODE_POST_INC
121 | CAMDMA_CCR_SRC_AMODE_POST_INC
124 | CAMDMA_CCR_SYNCHRO_CAMERA
);
127 static void omap24xxcam_dmahw_transfer_chain(unsigned long base
, int dmach
,
133 prev_dmach
= NUM_CAMDMA_CHANNELS
- 1;
135 prev_dmach
= dmach
- 1;
136 omap24xxcam_reg_out(base
, CAMDMA_CLNK_CTRL(prev_dmach
),
137 CAMDMA_CLNK_CTRL_ENABLE_LNK
| dmach
);
138 /* Did we chain the DMA transfer before the previous one
141 ch
= (dmach
+ free_dmach
) % NUM_CAMDMA_CHANNELS
;
142 while (!(omap24xxcam_reg_in(base
, CAMDMA_CCR(ch
))
143 & CAMDMA_CCR_ENABLE
)) {
145 /* The previous transfer has ended and this one
146 * hasn't started, so we must not have chained
147 * to the previous one in time. We'll have to
150 omap24xxcam_dmahw_transfer_start(base
, dmach
);
153 ch
= (ch
+ 1) % NUM_CAMDMA_CHANNELS
;
157 /* Abort all chained DMA transfers. After all transfers have been
158 * aborted and the DMA controller is idle, the completion routines for
159 * any aborted transfers will be called in sequence. The DMA
160 * controller may not be idle after this routine completes, because
161 * the completion routines might start new transfers.
163 static void omap24xxcam_dmahw_abort_ch(unsigned long base
, int dmach
)
165 /* mask all interrupts from this channel */
166 omap24xxcam_reg_out(base
, CAMDMA_CICR(dmach
), 0);
167 /* unlink this channel */
168 omap24xxcam_reg_merge(base
, CAMDMA_CLNK_CTRL(dmach
), 0,
169 CAMDMA_CLNK_CTRL_ENABLE_LNK
);
170 /* disable this channel */
171 omap24xxcam_reg_merge(base
, CAMDMA_CCR(dmach
), 0, CAMDMA_CCR_ENABLE
);
174 static void omap24xxcam_dmahw_init(unsigned long base
)
176 omap24xxcam_reg_out(base
, CAMDMA_OCP_SYSCONFIG
,
177 CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY
178 | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE
179 | CAMDMA_OCP_SYSCONFIG_AUTOIDLE
);
181 omap24xxcam_reg_merge(base
, CAMDMA_GCR
, 0x10,
182 CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH
);
184 omap24xxcam_reg_out(base
, CAMDMA_IRQENABLE_L0
, 0xf);
189 * Individual DMA channel handling.
193 /* Start a DMA transfer from the camera to memory.
194 * Returns zero if the transfer was successfully started, or non-zero if all
195 * DMA channels are already in use or starting is currently inhibited.
197 static int omap24xxcam_dma_start(struct omap24xxcam_dma
*dma
, dma_addr_t start
,
198 u32 len
, dma_callback_t callback
, void *arg
)
203 spin_lock_irqsave(&dma
->lock
, flags
);
205 if (!dma
->free_dmach
|| atomic_read(&dma
->dma_stop
)) {
206 spin_unlock_irqrestore(&dma
->lock
, flags
);
210 dmach
= dma
->next_dmach
;
212 dma
->ch_state
[dmach
].callback
= callback
;
213 dma
->ch_state
[dmach
].arg
= arg
;
215 omap24xxcam_dmahw_transfer_setup(dma
->base
, dmach
, start
, len
);
217 /* We're ready to start the DMA transfer. */
219 if (dma
->free_dmach
< NUM_CAMDMA_CHANNELS
) {
220 /* A transfer is already in progress, so try to chain to it. */
221 omap24xxcam_dmahw_transfer_chain(dma
->base
, dmach
,
224 /* No transfer is in progress, so we'll just start this one
227 omap24xxcam_dmahw_transfer_start(dma
->base
, dmach
);
230 dma
->next_dmach
= (dma
->next_dmach
+ 1) % NUM_CAMDMA_CHANNELS
;
233 spin_unlock_irqrestore(&dma
->lock
, flags
);
238 /* Abort all chained DMA transfers. After all transfers have been
239 * aborted and the DMA controller is idle, the completion routines for
240 * any aborted transfers will be called in sequence. The DMA
241 * controller may not be idle after this routine completes, because
242 * the completion routines might start new transfers.
244 static void omap24xxcam_dma_abort(struct omap24xxcam_dma
*dma
, u32 csr
)
247 int dmach
, i
, free_dmach
;
248 dma_callback_t callback
;
251 spin_lock_irqsave(&dma
->lock
, flags
);
253 /* stop any DMA transfers in progress */
254 dmach
= (dma
->next_dmach
+ dma
->free_dmach
) % NUM_CAMDMA_CHANNELS
;
255 for (i
= 0; i
< NUM_CAMDMA_CHANNELS
; i
++) {
256 omap24xxcam_dmahw_abort_ch(dma
->base
, dmach
);
257 dmach
= (dmach
+ 1) % NUM_CAMDMA_CHANNELS
;
260 /* We have to be careful here because the callback routine
261 * might start a new DMA transfer, and we only want to abort
262 * transfers that were started before this routine was called.
264 free_dmach
= dma
->free_dmach
;
265 while ((dma
->free_dmach
< NUM_CAMDMA_CHANNELS
) &&
266 (free_dmach
< NUM_CAMDMA_CHANNELS
)) {
267 dmach
= (dma
->next_dmach
+ dma
->free_dmach
)
268 % NUM_CAMDMA_CHANNELS
;
269 callback
= dma
->ch_state
[dmach
].callback
;
270 arg
= dma
->ch_state
[dmach
].arg
;
274 /* leave interrupts disabled during callback */
275 spin_unlock(&dma
->lock
);
276 (*callback
) (dma
, csr
, arg
);
277 spin_lock(&dma
->lock
);
281 spin_unlock_irqrestore(&dma
->lock
, flags
);
284 /* Abort all chained DMA transfers. After all transfers have been
285 * aborted and the DMA controller is idle, the completion routines for
286 * any aborted transfers will be called in sequence. If the completion
287 * routines attempt to start a new DMA transfer it will fail, so the
288 * DMA controller will be idle after this routine completes.
290 static void omap24xxcam_dma_stop(struct omap24xxcam_dma
*dma
, u32 csr
)
292 atomic_inc(&dma
->dma_stop
);
293 omap24xxcam_dma_abort(dma
, csr
);
294 atomic_dec(&dma
->dma_stop
);
297 /* Camera DMA interrupt service routine. */
298 void omap24xxcam_dma_isr(struct omap24xxcam_dma
*dma
)
301 dma_callback_t callback
;
304 const u32 csr_error
= CAMDMA_CSR_MISALIGNED_ERR
305 | CAMDMA_CSR_SUPERVISOR_ERR
| CAMDMA_CSR_SECURE_ERR
306 | CAMDMA_CSR_TRANS_ERR
| CAMDMA_CSR_DROP
;
308 spin_lock(&dma
->lock
);
310 if (dma
->free_dmach
== NUM_CAMDMA_CHANNELS
) {
311 /* A camera DMA interrupt occurred while all channels
312 * are idle, so we'll acknowledge the interrupt in the
313 * IRQSTATUS register and exit.
315 omap24xxcam_dmahw_ack_all(dma
->base
);
316 spin_unlock(&dma
->lock
);
320 while (dma
->free_dmach
< NUM_CAMDMA_CHANNELS
) {
321 dmach
= (dma
->next_dmach
+ dma
->free_dmach
)
322 % NUM_CAMDMA_CHANNELS
;
323 if (omap24xxcam_dmahw_running(dma
->base
, dmach
)) {
324 /* This buffer hasn't finished yet, so we're done. */
327 csr
= omap24xxcam_dmahw_ack_ch(dma
->base
, dmach
);
328 if (csr
& csr_error
) {
329 /* A DMA error occurred, so stop all DMA
330 * transfers in progress.
332 spin_unlock(&dma
->lock
);
333 omap24xxcam_dma_stop(dma
, csr
);
336 callback
= dma
->ch_state
[dmach
].callback
;
337 arg
= dma
->ch_state
[dmach
].arg
;
340 spin_unlock(&dma
->lock
);
341 (*callback
) (dma
, csr
, arg
);
342 spin_lock(&dma
->lock
);
347 spin_unlock(&dma
->lock
);
349 omap24xxcam_sgdma_process(
350 container_of(dma
, struct omap24xxcam_sgdma
, dma
));
353 void omap24xxcam_dma_hwinit(const struct omap24xxcam_dma
*dma
)
357 spin_lock_irqsave(&dma
->lock
, flags
);
359 omap24xxcam_dmahw_init(dma
->base
);
361 spin_unlock_irqrestore(&dma
->lock
, flags
);
364 static void omap24xxcam_dma_init(struct omap24xxcam_dma
*dma
,
369 /* group all channels on DMA IRQ0 and unmask irq */
370 spin_lock_init(&dma
->lock
);
372 dma
->free_dmach
= NUM_CAMDMA_CHANNELS
;
374 for (ch
= 0; ch
< NUM_CAMDMA_CHANNELS
; ch
++) {
375 dma
->ch_state
[ch
].callback
= NULL
;
376 dma
->ch_state
[ch
].arg
= NULL
;
382 * Scatter-gather DMA.
384 * High-level DMA construct for transferring whole picture frames to
385 * memory that is discontinuous.
389 /* DMA completion routine for the scatter-gather DMA fragments. */
390 static void omap24xxcam_sgdma_callback(struct omap24xxcam_dma
*dma
, u32 csr
,
393 struct omap24xxcam_sgdma
*sgdma
=
394 container_of(dma
, struct omap24xxcam_sgdma
, dma
);
395 int sgslot
= (int)arg
;
396 struct sgdma_state
*sg_state
;
397 const u32 csr_error
= CAMDMA_CSR_MISALIGNED_ERR
398 | CAMDMA_CSR_SUPERVISOR_ERR
| CAMDMA_CSR_SECURE_ERR
399 | CAMDMA_CSR_TRANS_ERR
| CAMDMA_CSR_DROP
;
401 spin_lock(&sgdma
->lock
);
403 /* We got an interrupt, we can remove the timer */
404 del_timer(&sgdma
->reset_timer
);
406 sg_state
= sgdma
->sg_state
+ sgslot
;
407 if (!sg_state
->queued_sglist
) {
408 spin_unlock(&sgdma
->lock
);
409 printk(KERN_ERR
"%s: sgdma completed when none queued!\n",
414 sg_state
->csr
|= csr
;
415 if (!--sg_state
->queued_sglist
) {
416 /* Queue for this sglist is empty, so check to see if we're
419 if ((sg_state
->next_sglist
== sg_state
->sglen
)
420 || (sg_state
->csr
& csr_error
)) {
421 sgdma_callback_t callback
= sg_state
->callback
;
422 void *arg
= sg_state
->arg
;
423 u32 sg_csr
= sg_state
->csr
;
424 /* All done with this sglist */
427 spin_unlock(&sgdma
->lock
);
428 (*callback
) (sgdma
, sg_csr
, arg
);
434 spin_unlock(&sgdma
->lock
);
437 /* Start queued scatter-gather DMA transfers. */
438 void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma
*sgdma
)
441 int queued_sgdma
, sgslot
;
442 struct sgdma_state
*sg_state
;
443 const u32 csr_error
= CAMDMA_CSR_MISALIGNED_ERR
444 | CAMDMA_CSR_SUPERVISOR_ERR
| CAMDMA_CSR_SECURE_ERR
445 | CAMDMA_CSR_TRANS_ERR
| CAMDMA_CSR_DROP
;
447 spin_lock_irqsave(&sgdma
->lock
, flags
);
449 queued_sgdma
= NUM_SG_DMA
- sgdma
->free_sgdma
;
450 sgslot
= (sgdma
->next_sgdma
+ sgdma
->free_sgdma
) % NUM_SG_DMA
;
451 while (queued_sgdma
> 0) {
452 sg_state
= sgdma
->sg_state
+ sgslot
;
453 while ((sg_state
->next_sglist
< sg_state
->sglen
) &&
454 !(sg_state
->csr
& csr_error
)) {
455 const struct scatterlist
*sglist
;
458 sglist
= sg_state
->sglist
+ sg_state
->next_sglist
;
459 /* try to start the next DMA transfer */
460 if (sg_state
->next_sglist
+ 1 == sg_state
->sglen
) {
462 * On the last sg, we handle the case where
463 * cam->img.pix.sizeimage % PAGE_ALIGN != 0
465 len
= sg_state
->len
- sg_state
->bytes_read
;
467 len
= sg_dma_len(sglist
);
470 if (omap24xxcam_dma_start(&sgdma
->dma
,
471 sg_dma_address(sglist
),
473 omap24xxcam_sgdma_callback
,
475 /* DMA start failed */
476 spin_unlock_irqrestore(&sgdma
->lock
, flags
);
479 unsigned long expires
;
480 /* DMA start was successful */
481 sg_state
->next_sglist
++;
482 sg_state
->bytes_read
+= len
;
483 sg_state
->queued_sglist
++;
485 /* We start the reset timer */
486 expires
= jiffies
+ HZ
;
487 mod_timer(&sgdma
->reset_timer
, expires
);
491 sgslot
= (sgslot
+ 1) % NUM_SG_DMA
;
494 spin_unlock_irqrestore(&sgdma
->lock
, flags
);
498 * Queue a scatter-gather DMA transfer from the camera to memory.
499 * Returns zero if the transfer was successfully queued, or non-zero
500 * if all of the scatter-gather slots are already in use.
502 int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma
*sgdma
,
503 const struct scatterlist
*sglist
, int sglen
,
504 int len
, sgdma_callback_t callback
, void *arg
)
507 struct sgdma_state
*sg_state
;
509 if ((sglen
< 0) || ((sglen
> 0) & !sglist
))
512 spin_lock_irqsave(&sgdma
->lock
, flags
);
514 if (!sgdma
->free_sgdma
) {
515 spin_unlock_irqrestore(&sgdma
->lock
, flags
);
519 sg_state
= sgdma
->sg_state
+ sgdma
->next_sgdma
;
521 sg_state
->sglist
= sglist
;
522 sg_state
->sglen
= sglen
;
523 sg_state
->next_sglist
= 0;
524 sg_state
->bytes_read
= 0;
526 sg_state
->queued_sglist
= 0;
528 sg_state
->callback
= callback
;
531 sgdma
->next_sgdma
= (sgdma
->next_sgdma
+ 1) % NUM_SG_DMA
;
534 spin_unlock_irqrestore(&sgdma
->lock
, flags
);
536 omap24xxcam_sgdma_process(sgdma
);
541 /* Sync scatter-gather DMA by aborting any DMA transfers currently in progress.
542 * Any queued scatter-gather DMA transactions that have not yet been started
543 * will remain queued. The DMA controller will be idle after this routine
544 * completes. When the scatter-gather queue is restarted, the next
545 * scatter-gather DMA transfer will begin at the start of a new transaction.
547 void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma
*sgdma
)
551 struct sgdma_state
*sg_state
;
552 u32 csr
= CAMDMA_CSR_TRANS_ERR
;
554 /* stop any DMA transfers in progress */
555 omap24xxcam_dma_stop(&sgdma
->dma
, csr
);
557 spin_lock_irqsave(&sgdma
->lock
, flags
);
559 if (sgdma
->free_sgdma
< NUM_SG_DMA
) {
560 sgslot
= (sgdma
->next_sgdma
+ sgdma
->free_sgdma
) % NUM_SG_DMA
;
561 sg_state
= sgdma
->sg_state
+ sgslot
;
562 if (sg_state
->next_sglist
!= 0) {
563 /* This DMA transfer was in progress, so abort it. */
564 sgdma_callback_t callback
= sg_state
->callback
;
565 void *arg
= sg_state
->arg
;
568 /* leave interrupts masked */
569 spin_unlock(&sgdma
->lock
);
570 (*callback
) (sgdma
, csr
, arg
);
571 spin_lock(&sgdma
->lock
);
576 spin_unlock_irqrestore(&sgdma
->lock
, flags
);
579 void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma
*sgdma
,
581 void (*reset_callback
)(unsigned long data
),
582 unsigned long reset_callback_data
)
586 spin_lock_init(&sgdma
->lock
);
587 sgdma
->free_sgdma
= NUM_SG_DMA
;
588 sgdma
->next_sgdma
= 0;
589 for (sg
= 0; sg
< NUM_SG_DMA
; sg
++) {
590 sgdma
->sg_state
[sg
].sglen
= 0;
591 sgdma
->sg_state
[sg
].next_sglist
= 0;
592 sgdma
->sg_state
[sg
].bytes_read
= 0;
593 sgdma
->sg_state
[sg
].queued_sglist
= 0;
594 sgdma
->sg_state
[sg
].csr
= 0;
595 sgdma
->sg_state
[sg
].callback
= NULL
;
596 sgdma
->sg_state
[sg
].arg
= NULL
;
599 omap24xxcam_dma_init(&sgdma
->dma
, base
);
600 setup_timer(&sgdma
->reset_timer
, reset_callback
, reset_callback_data
);