1 /*
2  * drivers/media/video/omap24xxcam-dma.c
3  *
4  * Copyright (C) 2004 MontaVista Software, Inc.
5  * Copyright (C) 2004 Texas Instruments.
6  * Copyright (C) 2007 Nokia Corporation.
7  *
8  * Contact: Sakari Ailus <sakari.ailus@nokia.com>
9  *
10  * Based on code from Andy Lowe <source@mvista.com> and
11  *                    David Cohen <david.cohen@indt.org.br>.
12  *
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.
16  *
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.
21  *
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
25  * 02110-1301 USA
26  */
27 
28 #include <linux/kernel.h>
29 #include <linux/io.h>
30 #include <linux/scatterlist.h>
31 
32 #include "omap24xxcam.h"
33 
34 /*
35  *
36  * DMA hardware.
37  *
38  */
39 
40 /* Ack all interrupt on CSR and IRQSTATUS_L0 */
omap24xxcam_dmahw_ack_all(unsigned long base)41 static void omap24xxcam_dmahw_ack_all(unsigned long base)
42 {
43 	u32 csr;
44 	int i;
45 
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);
50 	}
51 	omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf);
52 }
53 
54 /* Ack dmach on CSR and IRQSTATUS_L0 */
omap24xxcam_dmahw_ack_ch(unsigned long base,int dmach)55 static u32 omap24xxcam_dmahw_ack_ch(unsigned long base, int dmach)
56 {
57 	u32 csr;
58 
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));
64 
65 	return csr;
66 }
67 
omap24xxcam_dmahw_running(unsigned long base,int dmach)68 static int omap24xxcam_dmahw_running(unsigned long base, int dmach)
69 {
70 	return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE;
71 }
72 
omap24xxcam_dmahw_transfer_setup(unsigned long base,int dmach,dma_addr_t start,u32 len)73 static void omap24xxcam_dmahw_transfer_setup(unsigned long base, int dmach,
74 					     dma_addr_t start, u32 len)
75 {
76 	omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
77 			    CAMDMA_CCR_SEL_SRC_DST_SYNC
78 			    | CAMDMA_CCR_BS
79 			    | CAMDMA_CCR_DST_AMODE_POST_INC
80 			    | CAMDMA_CCR_SRC_AMODE_POST_INC
81 			    | CAMDMA_CCR_FS
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
105 			    | CAMDMA_CSR_BLOCK
106 			    | CAMDMA_CSR_DROP);
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);
113 }
114 
omap24xxcam_dmahw_transfer_start(unsigned long base,int dmach)115 static void omap24xxcam_dmahw_transfer_start(unsigned long base, int dmach)
116 {
117 	omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
118 			    CAMDMA_CCR_SEL_SRC_DST_SYNC
119 			    | CAMDMA_CCR_BS
120 			    | CAMDMA_CCR_DST_AMODE_POST_INC
121 			    | CAMDMA_CCR_SRC_AMODE_POST_INC
122 			    | CAMDMA_CCR_ENABLE
123 			    | CAMDMA_CCR_FS
124 			    | CAMDMA_CCR_SYNCHRO_CAMERA);
125 }
126 
omap24xxcam_dmahw_transfer_chain(unsigned long base,int dmach,int free_dmach)127 static void omap24xxcam_dmahw_transfer_chain(unsigned long base, int dmach,
128 					     int free_dmach)
129 {
130 	int prev_dmach, ch;
131 
132 	if (dmach == 0)
133 		prev_dmach = NUM_CAMDMA_CHANNELS - 1;
134 	else
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
139 	 * finished?
140 	 */
141 	ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS;
142 	while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch))
143 		 & CAMDMA_CCR_ENABLE)) {
144 		if (ch == dmach) {
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
148 			 * start it now.
149 			 */
150 			omap24xxcam_dmahw_transfer_start(base, dmach);
151 			break;
152 		} else
153 			ch = (ch + 1) % NUM_CAMDMA_CHANNELS;
154 	}
155 }
156 
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.
162  */
omap24xxcam_dmahw_abort_ch(unsigned long base,int dmach)163 static void omap24xxcam_dmahw_abort_ch(unsigned long base, int dmach)
164 {
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);
172 }
173 
omap24xxcam_dmahw_init(unsigned long base)174 static void omap24xxcam_dmahw_init(unsigned long base)
175 {
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);
180 
181 	omap24xxcam_reg_merge(base, CAMDMA_GCR, 0x10,
182 			      CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH);
183 
184 	omap24xxcam_reg_out(base, CAMDMA_IRQENABLE_L0, 0xf);
185 }
186 
187 /*
188  *
189  * Individual DMA channel handling.
190  *
191  */
192 
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.
196  */
omap24xxcam_dma_start(struct omap24xxcam_dma * dma,dma_addr_t start,u32 len,dma_callback_t callback,void * arg)197 static int omap24xxcam_dma_start(struct omap24xxcam_dma *dma, dma_addr_t start,
198 				 u32 len, dma_callback_t callback, void *arg)
199 {
200 	unsigned long flags;
201 	int dmach;
202 
203 	spin_lock_irqsave(&dma->lock, flags);
204 
205 	if (!dma->free_dmach || atomic_read(&dma->dma_stop)) {
206 		spin_unlock_irqrestore(&dma->lock, flags);
207 		return -EBUSY;
208 	}
209 
210 	dmach = dma->next_dmach;
211 
212 	dma->ch_state[dmach].callback = callback;
213 	dma->ch_state[dmach].arg = arg;
214 
215 	omap24xxcam_dmahw_transfer_setup(dma->base, dmach, start, len);
216 
217 	/* We're ready to start the DMA transfer. */
218 
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,
222 						 dma->free_dmach);
223 	} else {
224 		/* No transfer is in progress, so we'll just start this one
225 		 * now.
226 		 */
227 		omap24xxcam_dmahw_transfer_start(dma->base, dmach);
228 	}
229 
230 	dma->next_dmach = (dma->next_dmach + 1) % NUM_CAMDMA_CHANNELS;
231 	dma->free_dmach--;
232 
233 	spin_unlock_irqrestore(&dma->lock, flags);
234 
235 	return 0;
236 }
237 
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.
243  */
omap24xxcam_dma_abort(struct omap24xxcam_dma * dma,u32 csr)244 static void omap24xxcam_dma_abort(struct omap24xxcam_dma *dma, u32 csr)
245 {
246 	unsigned long flags;
247 	int dmach, i, free_dmach;
248 	dma_callback_t callback;
249 	void *arg;
250 
251 	spin_lock_irqsave(&dma->lock, flags);
252 
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;
258 	}
259 
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.
263 	 */
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;
271 		dma->free_dmach++;
272 		free_dmach++;
273 		if (callback) {
274 			/* leave interrupts disabled during callback */
275 			spin_unlock(&dma->lock);
276 			(*callback) (dma, csr, arg);
277 			spin_lock(&dma->lock);
278 		}
279 	}
280 
281 	spin_unlock_irqrestore(&dma->lock, flags);
282 }
283 
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.
289  */
omap24xxcam_dma_stop(struct omap24xxcam_dma * dma,u32 csr)290 static void omap24xxcam_dma_stop(struct omap24xxcam_dma *dma, u32 csr)
291 {
292 	atomic_inc(&dma->dma_stop);
293 	omap24xxcam_dma_abort(dma, csr);
294 	atomic_dec(&dma->dma_stop);
295 }
296 
297 /* Camera DMA interrupt service routine. */
omap24xxcam_dma_isr(struct omap24xxcam_dma * dma)298 void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma)
299 {
300 	int dmach;
301 	dma_callback_t callback;
302 	void *arg;
303 	u32 csr;
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;
307 
308 	spin_lock(&dma->lock);
309 
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.
314 		 */
315 		omap24xxcam_dmahw_ack_all(dma->base);
316 		spin_unlock(&dma->lock);
317 		return;
318 	}
319 
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. */
325 			break;
326 		}
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.
331 			 */
332 			spin_unlock(&dma->lock);
333 			omap24xxcam_dma_stop(dma, csr);
334 			return;
335 		} else {
336 			callback = dma->ch_state[dmach].callback;
337 			arg = dma->ch_state[dmach].arg;
338 			dma->free_dmach++;
339 			if (callback) {
340 				spin_unlock(&dma->lock);
341 				(*callback) (dma, csr, arg);
342 				spin_lock(&dma->lock);
343 			}
344 		}
345 	}
346 
347 	spin_unlock(&dma->lock);
348 
349 	omap24xxcam_sgdma_process(
350 		container_of(dma, struct omap24xxcam_sgdma, dma));
351 }
352 
omap24xxcam_dma_hwinit(struct omap24xxcam_dma * dma)353 void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma)
354 {
355 	unsigned long flags;
356 
357 	spin_lock_irqsave(&dma->lock, flags);
358 
359 	omap24xxcam_dmahw_init(dma->base);
360 
361 	spin_unlock_irqrestore(&dma->lock, flags);
362 }
363 
omap24xxcam_dma_init(struct omap24xxcam_dma * dma,unsigned long base)364 static void omap24xxcam_dma_init(struct omap24xxcam_dma *dma,
365 				 unsigned long base)
366 {
367 	int ch;
368 
369 	/* group all channels on DMA IRQ0 and unmask irq */
370 	spin_lock_init(&dma->lock);
371 	dma->base = base;
372 	dma->free_dmach = NUM_CAMDMA_CHANNELS;
373 	dma->next_dmach = 0;
374 	for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) {
375 		dma->ch_state[ch].callback = NULL;
376 		dma->ch_state[ch].arg = NULL;
377 	}
378 }
379 
380 /*
381  *
382  * Scatter-gather DMA.
383  *
384  * High-level DMA construct for transferring whole picture frames to
385  * memory that is discontinuous.
386  *
387  */
388 
389 /* DMA completion routine for the scatter-gather DMA fragments. */
omap24xxcam_sgdma_callback(struct omap24xxcam_dma * dma,u32 csr,void * arg)390 static void omap24xxcam_sgdma_callback(struct omap24xxcam_dma *dma, u32 csr,
391 				       void *arg)
392 {
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;
400 
401 	spin_lock(&sgdma->lock);
402 
403 	/* We got an interrupt, we can remove the timer */
404 	del_timer(&sgdma->reset_timer);
405 
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",
410 		       __func__);
411 		return;
412 	}
413 
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
417 		 * done.
418 		 */
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 */
425 			sgdma->free_sgdma++;
426 			if (callback) {
427 				spin_unlock(&sgdma->lock);
428 				(*callback) (sgdma, sg_csr, arg);
429 				return;
430 			}
431 		}
432 	}
433 
434 	spin_unlock(&sgdma->lock);
435 }
436 
437 /* Start queued scatter-gather DMA transfers. */
omap24xxcam_sgdma_process(struct omap24xxcam_sgdma * sgdma)438 void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma)
439 {
440 	unsigned long flags;
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;
446 
447 	spin_lock_irqsave(&sgdma->lock, flags);
448 
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;
456 			unsigned int len;
457 
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) {
461 				/*
462 				 *  On the last sg, we handle the case where
463 				 *  cam->img.pix.sizeimage % PAGE_ALIGN != 0
464 				 */
465 				len = sg_state->len - sg_state->bytes_read;
466 			} else {
467 				len = sg_dma_len(sglist);
468 			}
469 
470 			if (omap24xxcam_dma_start(&sgdma->dma,
471 						  sg_dma_address(sglist),
472 						  len,
473 						  omap24xxcam_sgdma_callback,
474 						  (void *)sgslot)) {
475 				/* DMA start failed */
476 				spin_unlock_irqrestore(&sgdma->lock, flags);
477 				return;
478 			} else {
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++;
484 
485 				/* We start the reset timer */
486 				expires = jiffies + HZ;
487 				mod_timer(&sgdma->reset_timer, expires);
488 			}
489 		}
490 		queued_sgdma--;
491 		sgslot = (sgslot + 1) % NUM_SG_DMA;
492 	}
493 
494 	spin_unlock_irqrestore(&sgdma->lock, flags);
495 }
496 
497 /*
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.
501  */
omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma * sgdma,const struct scatterlist * sglist,int sglen,int len,sgdma_callback_t callback,void * arg)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)
505 {
506 	unsigned long flags;
507 	struct sgdma_state *sg_state;
508 
509 	if ((sglen < 0) || ((sglen > 0) && !sglist))
510 		return -EINVAL;
511 
512 	spin_lock_irqsave(&sgdma->lock, flags);
513 
514 	if (!sgdma->free_sgdma) {
515 		spin_unlock_irqrestore(&sgdma->lock, flags);
516 		return -EBUSY;
517 	}
518 
519 	sg_state = sgdma->sg_state + sgdma->next_sgdma;
520 
521 	sg_state->sglist = sglist;
522 	sg_state->sglen = sglen;
523 	sg_state->next_sglist = 0;
524 	sg_state->bytes_read = 0;
525 	sg_state->len = len;
526 	sg_state->queued_sglist = 0;
527 	sg_state->csr = 0;
528 	sg_state->callback = callback;
529 	sg_state->arg = arg;
530 
531 	sgdma->next_sgdma = (sgdma->next_sgdma + 1) % NUM_SG_DMA;
532 	sgdma->free_sgdma--;
533 
534 	spin_unlock_irqrestore(&sgdma->lock, flags);
535 
536 	omap24xxcam_sgdma_process(sgdma);
537 
538 	return 0;
539 }
540 
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.
546  */
omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma * sgdma)547 void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma)
548 {
549 	unsigned long flags;
550 	int sgslot;
551 	struct sgdma_state *sg_state;
552 	u32 csr = CAMDMA_CSR_TRANS_ERR;
553 
554 	/* stop any DMA transfers in progress */
555 	omap24xxcam_dma_stop(&sgdma->dma, csr);
556 
557 	spin_lock_irqsave(&sgdma->lock, flags);
558 
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;
566 			sgdma->free_sgdma++;
567 			if (callback) {
568 				/* leave interrupts masked */
569 				spin_unlock(&sgdma->lock);
570 				(*callback) (sgdma, csr, arg);
571 				spin_lock(&sgdma->lock);
572 			}
573 		}
574 	}
575 
576 	spin_unlock_irqrestore(&sgdma->lock, flags);
577 }
578 
omap24xxcam_sgdma_init(struct omap24xxcam_sgdma * sgdma,unsigned long base,void (* reset_callback)(unsigned long data),unsigned long reset_callback_data)579 void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
580 			    unsigned long base,
581 			    void (*reset_callback)(unsigned long data),
582 			    unsigned long reset_callback_data)
583 {
584 	int sg;
585 
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;
597 	}
598 
599 	omap24xxcam_dma_init(&sgdma->dma, base);
600 	setup_timer(&sgdma->reset_timer, reset_callback, reset_callback_data);
601 }
602