xref: /openbmc/linux/drivers/media/pci/ivtv/ivtv-irq.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*1a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b285192aSMauro Carvalho Chehab /* interrupt handling
3b285192aSMauro Carvalho Chehab     Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
4b285192aSMauro Carvalho Chehab     Copyright (C) 2004  Chris Kennedy <c@groovy.org>
5b285192aSMauro Carvalho Chehab     Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
6b285192aSMauro Carvalho Chehab 
7b285192aSMauro Carvalho Chehab  */
8b285192aSMauro Carvalho Chehab 
9b285192aSMauro Carvalho Chehab #include "ivtv-driver.h"
10b285192aSMauro Carvalho Chehab #include "ivtv-queue.h"
11b285192aSMauro Carvalho Chehab #include "ivtv-udma.h"
12b285192aSMauro Carvalho Chehab #include "ivtv-irq.h"
13b285192aSMauro Carvalho Chehab #include "ivtv-mailbox.h"
14b285192aSMauro Carvalho Chehab #include "ivtv-vbi.h"
15b285192aSMauro Carvalho Chehab #include "ivtv-yuv.h"
16b285192aSMauro Carvalho Chehab #include <media/v4l2-event.h>
17b285192aSMauro Carvalho Chehab 
18b285192aSMauro Carvalho Chehab #define DMA_MAGIC_COOKIE 0x000001fe
19b285192aSMauro Carvalho Chehab 
20b285192aSMauro Carvalho Chehab static void ivtv_dma_dec_start(struct ivtv_stream *s);
21b285192aSMauro Carvalho Chehab 
22b285192aSMauro Carvalho Chehab static const int ivtv_stream_map[] = {
23b285192aSMauro Carvalho Chehab 	IVTV_ENC_STREAM_TYPE_MPG,
24b285192aSMauro Carvalho Chehab 	IVTV_ENC_STREAM_TYPE_YUV,
25b285192aSMauro Carvalho Chehab 	IVTV_ENC_STREAM_TYPE_PCM,
26b285192aSMauro Carvalho Chehab 	IVTV_ENC_STREAM_TYPE_VBI,
27b285192aSMauro Carvalho Chehab };
28b285192aSMauro Carvalho Chehab 
ivtv_pcm_work_handler(struct ivtv * itv)294313902eSAndy Walls static void ivtv_pcm_work_handler(struct ivtv *itv)
304313902eSAndy Walls {
314313902eSAndy Walls 	struct ivtv_stream *s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
324313902eSAndy Walls 	struct ivtv_buffer *buf;
334313902eSAndy Walls 
344313902eSAndy Walls 	/* Pass the PCM data to ivtv-alsa */
354313902eSAndy Walls 
364313902eSAndy Walls 	while (1) {
374313902eSAndy Walls 		/*
384313902eSAndy Walls 		 * Users should not be using both the ALSA and V4L2 PCM audio
394313902eSAndy Walls 		 * capture interfaces at the same time.  If the user is doing
404313902eSAndy Walls 		 * this, there maybe a buffer in q_io to grab, use, and put
414313902eSAndy Walls 		 * back in rotation.
424313902eSAndy Walls 		 */
434313902eSAndy Walls 		buf = ivtv_dequeue(s, &s->q_io);
444313902eSAndy Walls 		if (buf == NULL)
454313902eSAndy Walls 			buf = ivtv_dequeue(s, &s->q_full);
464313902eSAndy Walls 		if (buf == NULL)
474313902eSAndy Walls 			break;
484313902eSAndy Walls 
494313902eSAndy Walls 		if (buf->readpos < buf->bytesused)
504313902eSAndy Walls 			itv->pcm_announce_callback(itv->alsa,
514313902eSAndy Walls 				(u8 *)(buf->buf + buf->readpos),
524313902eSAndy Walls 				(size_t)(buf->bytesused - buf->readpos));
534313902eSAndy Walls 
544313902eSAndy Walls 		ivtv_enqueue(s, buf, &s->q_free);
554313902eSAndy Walls 	}
564313902eSAndy Walls }
57b285192aSMauro Carvalho Chehab 
ivtv_pio_work_handler(struct ivtv * itv)58b285192aSMauro Carvalho Chehab static void ivtv_pio_work_handler(struct ivtv *itv)
59b285192aSMauro Carvalho Chehab {
60b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream];
61b285192aSMauro Carvalho Chehab 	struct ivtv_buffer *buf;
62b285192aSMauro Carvalho Chehab 	int i = 0;
63b285192aSMauro Carvalho Chehab 
64b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
65b285192aSMauro Carvalho Chehab 	if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
66635d62f0SHans Verkuil 			s->vdev.v4l2_dev == NULL || !ivtv_use_pio(s)) {
67b285192aSMauro Carvalho Chehab 		itv->cur_pio_stream = -1;
68b285192aSMauro Carvalho Chehab 		/* trigger PIO complete user interrupt */
69b285192aSMauro Carvalho Chehab 		write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
70b285192aSMauro Carvalho Chehab 		return;
71b285192aSMauro Carvalho Chehab 	}
72b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name);
73b285192aSMauro Carvalho Chehab 	list_for_each_entry(buf, &s->q_dma.list, list) {
74b285192aSMauro Carvalho Chehab 		u32 size = s->sg_processing[i].size & 0x3ffff;
75b285192aSMauro Carvalho Chehab 
76b285192aSMauro Carvalho Chehab 		/* Copy the data from the card to the buffer */
77b285192aSMauro Carvalho Chehab 		if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
78b285192aSMauro Carvalho Chehab 			memcpy_fromio(buf->buf, itv->dec_mem + s->sg_processing[i].src - IVTV_DECODER_OFFSET, size);
79b285192aSMauro Carvalho Chehab 		}
80b285192aSMauro Carvalho Chehab 		else {
81b285192aSMauro Carvalho Chehab 			memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size);
82b285192aSMauro Carvalho Chehab 		}
83b285192aSMauro Carvalho Chehab 		i++;
84b285192aSMauro Carvalho Chehab 		if (i == s->sg_processing_size)
85b285192aSMauro Carvalho Chehab 			break;
86b285192aSMauro Carvalho Chehab 	}
87b285192aSMauro Carvalho Chehab 	write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
88b285192aSMauro Carvalho Chehab }
89b285192aSMauro Carvalho Chehab 
ivtv_irq_work_handler(struct kthread_work * work)90b285192aSMauro Carvalho Chehab void ivtv_irq_work_handler(struct kthread_work *work)
91b285192aSMauro Carvalho Chehab {
92b285192aSMauro Carvalho Chehab 	struct ivtv *itv = container_of(work, struct ivtv, irq_work);
93b285192aSMauro Carvalho Chehab 
94b285192aSMauro Carvalho Chehab 	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags))
95b285192aSMauro Carvalho Chehab 		ivtv_pio_work_handler(itv);
96b285192aSMauro Carvalho Chehab 
97b285192aSMauro Carvalho Chehab 	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags))
98b285192aSMauro Carvalho Chehab 		ivtv_vbi_work_handler(itv);
99b285192aSMauro Carvalho Chehab 
100b285192aSMauro Carvalho Chehab 	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags))
101b285192aSMauro Carvalho Chehab 		ivtv_yuv_work_handler(itv);
1024313902eSAndy Walls 
1034313902eSAndy Walls 	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PCM, &itv->i_flags))
1044313902eSAndy Walls 		ivtv_pcm_work_handler(itv);
105b285192aSMauro Carvalho Chehab }
106b285192aSMauro Carvalho Chehab 
107b285192aSMauro Carvalho Chehab /* Determine the required DMA size, setup enough buffers in the predma queue and
108b285192aSMauro Carvalho Chehab    actually copy the data from the card to the buffers in case a PIO transfer is
109b285192aSMauro Carvalho Chehab    required for this stream.
110b285192aSMauro Carvalho Chehab  */
stream_enc_dma_append(struct ivtv_stream * s,u32 data[CX2341X_MBOX_MAX_DATA])111b285192aSMauro Carvalho Chehab static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MAX_DATA])
112b285192aSMauro Carvalho Chehab {
113b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
114b285192aSMauro Carvalho Chehab 	struct ivtv_buffer *buf;
115b285192aSMauro Carvalho Chehab 	u32 bytes_needed = 0;
116b285192aSMauro Carvalho Chehab 	u32 offset, size;
117b285192aSMauro Carvalho Chehab 	u32 UVoffset = 0, UVsize = 0;
118b285192aSMauro Carvalho Chehab 	int skip_bufs = s->q_predma.buffers;
119b285192aSMauro Carvalho Chehab 	int idx = s->sg_pending_size;
120b285192aSMauro Carvalho Chehab 	int rc;
121b285192aSMauro Carvalho Chehab 
122b285192aSMauro Carvalho Chehab 	/* sanity checks */
123635d62f0SHans Verkuil 	if (s->vdev.v4l2_dev == NULL) {
124b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_WARN("Stream %s not started\n", s->name);
125b285192aSMauro Carvalho Chehab 		return -1;
126b285192aSMauro Carvalho Chehab 	}
127b285192aSMauro Carvalho Chehab 	if (!test_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
128b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_WARN("Stream %s not open\n", s->name);
129b285192aSMauro Carvalho Chehab 		return -1;
130b285192aSMauro Carvalho Chehab 	}
131b285192aSMauro Carvalho Chehab 
132b285192aSMauro Carvalho Chehab 	/* determine offset, size and PTS for the various streams */
133b285192aSMauro Carvalho Chehab 	switch (s->type) {
134b285192aSMauro Carvalho Chehab 		case IVTV_ENC_STREAM_TYPE_MPG:
135b285192aSMauro Carvalho Chehab 			offset = data[1];
136b285192aSMauro Carvalho Chehab 			size = data[2];
137b285192aSMauro Carvalho Chehab 			s->pending_pts = 0;
138b285192aSMauro Carvalho Chehab 			break;
139b285192aSMauro Carvalho Chehab 
140b285192aSMauro Carvalho Chehab 		case IVTV_ENC_STREAM_TYPE_YUV:
141b285192aSMauro Carvalho Chehab 			offset = data[1];
142b285192aSMauro Carvalho Chehab 			size = data[2];
143b285192aSMauro Carvalho Chehab 			UVoffset = data[3];
144b285192aSMauro Carvalho Chehab 			UVsize = data[4];
145b285192aSMauro Carvalho Chehab 			s->pending_pts = ((u64) data[5] << 32) | data[6];
146b285192aSMauro Carvalho Chehab 			break;
147b285192aSMauro Carvalho Chehab 
148b285192aSMauro Carvalho Chehab 		case IVTV_ENC_STREAM_TYPE_PCM:
149b285192aSMauro Carvalho Chehab 			offset = data[1] + 12;
150b285192aSMauro Carvalho Chehab 			size = data[2] - 12;
151b285192aSMauro Carvalho Chehab 			s->pending_pts = read_dec(offset - 8) |
152b285192aSMauro Carvalho Chehab 				((u64)(read_dec(offset - 12)) << 32);
153b285192aSMauro Carvalho Chehab 			if (itv->has_cx23415)
154b285192aSMauro Carvalho Chehab 				offset += IVTV_DECODER_OFFSET;
155b285192aSMauro Carvalho Chehab 			break;
156b285192aSMauro Carvalho Chehab 
157b285192aSMauro Carvalho Chehab 		case IVTV_ENC_STREAM_TYPE_VBI:
158b285192aSMauro Carvalho Chehab 			size = itv->vbi.enc_size * itv->vbi.fpi;
159b285192aSMauro Carvalho Chehab 			offset = read_enc(itv->vbi.enc_start - 4) + 12;
160b285192aSMauro Carvalho Chehab 			if (offset == 12) {
161b285192aSMauro Carvalho Chehab 				IVTV_DEBUG_INFO("VBI offset == 0\n");
162b285192aSMauro Carvalho Chehab 				return -1;
163b285192aSMauro Carvalho Chehab 			}
164b285192aSMauro Carvalho Chehab 			s->pending_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32);
165b285192aSMauro Carvalho Chehab 			break;
166b285192aSMauro Carvalho Chehab 
167b285192aSMauro Carvalho Chehab 		case IVTV_DEC_STREAM_TYPE_VBI:
168b285192aSMauro Carvalho Chehab 			size = read_dec(itv->vbi.dec_start + 4) + 8;
169b285192aSMauro Carvalho Chehab 			offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start;
170b285192aSMauro Carvalho Chehab 			s->pending_pts = 0;
171b285192aSMauro Carvalho Chehab 			offset += IVTV_DECODER_OFFSET;
172b285192aSMauro Carvalho Chehab 			break;
173b285192aSMauro Carvalho Chehab 		default:
174b285192aSMauro Carvalho Chehab 			/* shouldn't happen */
175b285192aSMauro Carvalho Chehab 			return -1;
176b285192aSMauro Carvalho Chehab 	}
177b285192aSMauro Carvalho Chehab 
178b285192aSMauro Carvalho Chehab 	/* if this is the start of the DMA then fill in the magic cookie */
179b285192aSMauro Carvalho Chehab 	if (s->sg_pending_size == 0 && ivtv_use_dma(s)) {
180b285192aSMauro Carvalho Chehab 		if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
181b285192aSMauro Carvalho Chehab 		    s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
182b285192aSMauro Carvalho Chehab 			s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET);
1833efb8ab6SHans Verkuil 			write_dec_sync(DMA_MAGIC_COOKIE, offset - IVTV_DECODER_OFFSET);
184b285192aSMauro Carvalho Chehab 		}
185b285192aSMauro Carvalho Chehab 		else {
186b285192aSMauro Carvalho Chehab 			s->pending_backup = read_enc(offset);
1873efb8ab6SHans Verkuil 			write_enc_sync(DMA_MAGIC_COOKIE, offset);
188b285192aSMauro Carvalho Chehab 		}
189b285192aSMauro Carvalho Chehab 		s->pending_offset = offset;
190b285192aSMauro Carvalho Chehab 	}
191b285192aSMauro Carvalho Chehab 
192b285192aSMauro Carvalho Chehab 	bytes_needed = size;
193b285192aSMauro Carvalho Chehab 	if (s->type == IVTV_ENC_STREAM_TYPE_YUV) {
194b285192aSMauro Carvalho Chehab 		/* The size for the Y samples needs to be rounded upwards to a
195b285192aSMauro Carvalho Chehab 		   multiple of the buf_size. The UV samples then start in the
196b285192aSMauro Carvalho Chehab 		   next buffer. */
197b285192aSMauro Carvalho Chehab 		bytes_needed = s->buf_size * ((bytes_needed + s->buf_size - 1) / s->buf_size);
198b285192aSMauro Carvalho Chehab 		bytes_needed += UVsize;
199b285192aSMauro Carvalho Chehab 	}
200b285192aSMauro Carvalho Chehab 
201b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
202b285192aSMauro Carvalho Chehab 		ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset);
203b285192aSMauro Carvalho Chehab 
204b285192aSMauro Carvalho Chehab 	rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed);
205b285192aSMauro Carvalho Chehab 	if (rc < 0) { /* Insufficient buffers */
206b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_WARN("Cannot obtain %d bytes for %s data transfer\n",
207b285192aSMauro Carvalho Chehab 				bytes_needed, s->name);
208b285192aSMauro Carvalho Chehab 		return -1;
209b285192aSMauro Carvalho Chehab 	}
210b285192aSMauro Carvalho Chehab 	if (rc && !s->buffers_stolen && test_bit(IVTV_F_S_APPL_IO, &s->s_flags)) {
211b285192aSMauro Carvalho Chehab 		IVTV_WARN("All %s stream buffers are full. Dropping data.\n", s->name);
212b285192aSMauro Carvalho Chehab 		IVTV_WARN("Cause: the application is not reading fast enough.\n");
213b285192aSMauro Carvalho Chehab 	}
214b285192aSMauro Carvalho Chehab 	s->buffers_stolen = rc;
215b285192aSMauro Carvalho Chehab 
216b285192aSMauro Carvalho Chehab 	/* got the buffers, now fill in sg_pending */
217b285192aSMauro Carvalho Chehab 	buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
218b285192aSMauro Carvalho Chehab 	memset(buf->buf, 0, 128);
219b285192aSMauro Carvalho Chehab 	list_for_each_entry(buf, &s->q_predma.list, list) {
220b285192aSMauro Carvalho Chehab 		if (skip_bufs-- > 0)
221b285192aSMauro Carvalho Chehab 			continue;
222b285192aSMauro Carvalho Chehab 		s->sg_pending[idx].dst = buf->dma_handle;
223b285192aSMauro Carvalho Chehab 		s->sg_pending[idx].src = offset;
224b285192aSMauro Carvalho Chehab 		s->sg_pending[idx].size = s->buf_size;
225b285192aSMauro Carvalho Chehab 		buf->bytesused = min(size, s->buf_size);
226b285192aSMauro Carvalho Chehab 		buf->dma_xfer_cnt = s->dma_xfer_cnt;
227b285192aSMauro Carvalho Chehab 
228b285192aSMauro Carvalho Chehab 		s->q_predma.bytesused += buf->bytesused;
229b285192aSMauro Carvalho Chehab 		size -= buf->bytesused;
230b285192aSMauro Carvalho Chehab 		offset += s->buf_size;
231b285192aSMauro Carvalho Chehab 
232b285192aSMauro Carvalho Chehab 		/* Sync SG buffers */
233b285192aSMauro Carvalho Chehab 		ivtv_buf_sync_for_device(s, buf);
234b285192aSMauro Carvalho Chehab 
235b285192aSMauro Carvalho Chehab 		if (size == 0) {	/* YUV */
236b285192aSMauro Carvalho Chehab 			/* process the UV section */
237b285192aSMauro Carvalho Chehab 			offset = UVoffset;
238b285192aSMauro Carvalho Chehab 			size = UVsize;
239b285192aSMauro Carvalho Chehab 		}
240b285192aSMauro Carvalho Chehab 		idx++;
241b285192aSMauro Carvalho Chehab 	}
242b285192aSMauro Carvalho Chehab 	s->sg_pending_size = idx;
243b285192aSMauro Carvalho Chehab 	return 0;
244b285192aSMauro Carvalho Chehab }
245b285192aSMauro Carvalho Chehab 
dma_post(struct ivtv_stream * s)246b285192aSMauro Carvalho Chehab static void dma_post(struct ivtv_stream *s)
247b285192aSMauro Carvalho Chehab {
248b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
249b285192aSMauro Carvalho Chehab 	struct ivtv_buffer *buf = NULL;
250b285192aSMauro Carvalho Chehab 	struct list_head *p;
251b285192aSMauro Carvalho Chehab 	u32 offset;
252b285192aSMauro Carvalho Chehab 	__le32 *u32buf;
253b285192aSMauro Carvalho Chehab 	int x = 0;
254b285192aSMauro Carvalho Chehab 
255b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
256b285192aSMauro Carvalho Chehab 			s->name, s->dma_offset);
257b285192aSMauro Carvalho Chehab 	list_for_each(p, &s->q_dma.list) {
258b285192aSMauro Carvalho Chehab 		buf = list_entry(p, struct ivtv_buffer, list);
259b285192aSMauro Carvalho Chehab 		u32buf = (__le32 *)buf->buf;
260b285192aSMauro Carvalho Chehab 
261b285192aSMauro Carvalho Chehab 		/* Sync Buffer */
262b285192aSMauro Carvalho Chehab 		ivtv_buf_sync_for_cpu(s, buf);
263b285192aSMauro Carvalho Chehab 
264b285192aSMauro Carvalho Chehab 		if (x == 0 && ivtv_use_dma(s)) {
265b285192aSMauro Carvalho Chehab 			offset = s->dma_last_offset;
2663efb8ab6SHans Verkuil 			if (le32_to_cpu(u32buf[offset / 4]) != DMA_MAGIC_COOKIE)
267b285192aSMauro Carvalho Chehab 			{
2683efb8ab6SHans Verkuil 				for (offset = 0; offset < 64; offset++)
2693efb8ab6SHans Verkuil 					if (le32_to_cpu(u32buf[offset]) == DMA_MAGIC_COOKIE)
270b285192aSMauro Carvalho Chehab 						break;
271b285192aSMauro Carvalho Chehab 				offset *= 4;
272b285192aSMauro Carvalho Chehab 				if (offset == 256) {
273b285192aSMauro Carvalho Chehab 					IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name);
274b285192aSMauro Carvalho Chehab 					offset = s->dma_last_offset;
275b285192aSMauro Carvalho Chehab 				}
276b285192aSMauro Carvalho Chehab 				if (s->dma_last_offset != offset)
277b285192aSMauro Carvalho Chehab 					IVTV_DEBUG_WARN("%s: offset %d -> %d\n", s->name, s->dma_last_offset, offset);
278b285192aSMauro Carvalho Chehab 				s->dma_last_offset = offset;
279b285192aSMauro Carvalho Chehab 			}
280b285192aSMauro Carvalho Chehab 			if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
281b285192aSMauro Carvalho Chehab 						s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
282b285192aSMauro Carvalho Chehab 				write_dec_sync(0, s->dma_offset - IVTV_DECODER_OFFSET);
283b285192aSMauro Carvalho Chehab 			}
284b285192aSMauro Carvalho Chehab 			else {
285b285192aSMauro Carvalho Chehab 				write_enc_sync(0, s->dma_offset);
286b285192aSMauro Carvalho Chehab 			}
287b285192aSMauro Carvalho Chehab 			if (offset) {
288b285192aSMauro Carvalho Chehab 				buf->bytesused -= offset;
289b285192aSMauro Carvalho Chehab 				memcpy(buf->buf, buf->buf + offset, buf->bytesused + offset);
290b285192aSMauro Carvalho Chehab 			}
291b285192aSMauro Carvalho Chehab 			*u32buf = cpu_to_le32(s->dma_backup);
292b285192aSMauro Carvalho Chehab 		}
293b285192aSMauro Carvalho Chehab 		x++;
294b285192aSMauro Carvalho Chehab 		/* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */
295b285192aSMauro Carvalho Chehab 		if (s->type == IVTV_ENC_STREAM_TYPE_MPG ||
296b285192aSMauro Carvalho Chehab 		    s->type == IVTV_ENC_STREAM_TYPE_VBI)
297b285192aSMauro Carvalho Chehab 			buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP;
298b285192aSMauro Carvalho Chehab 	}
299b285192aSMauro Carvalho Chehab 	if (buf)
300b285192aSMauro Carvalho Chehab 		buf->bytesused += s->dma_last_offset;
301b285192aSMauro Carvalho Chehab 	if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) {
302b285192aSMauro Carvalho Chehab 		list_for_each_entry(buf, &s->q_dma.list, list) {
303b285192aSMauro Carvalho Chehab 			/* Parse and Groom VBI Data */
304b285192aSMauro Carvalho Chehab 			s->q_dma.bytesused -= buf->bytesused;
305b285192aSMauro Carvalho Chehab 			ivtv_process_vbi_data(itv, buf, 0, s->type);
306b285192aSMauro Carvalho Chehab 			s->q_dma.bytesused += buf->bytesused;
307b285192aSMauro Carvalho Chehab 		}
308b285192aSMauro Carvalho Chehab 		if (s->fh == NULL) {
309b285192aSMauro Carvalho Chehab 			ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
310b285192aSMauro Carvalho Chehab 			return;
311b285192aSMauro Carvalho Chehab 		}
312b285192aSMauro Carvalho Chehab 	}
3134313902eSAndy Walls 
314b285192aSMauro Carvalho Chehab 	ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused);
3154313902eSAndy Walls 
3164313902eSAndy Walls 	if (s->type == IVTV_ENC_STREAM_TYPE_PCM &&
3174313902eSAndy Walls 	    itv->pcm_announce_callback != NULL) {
3184313902eSAndy Walls 		/*
3194313902eSAndy Walls 		 * Set up the work handler to pass the data to ivtv-alsa.
3204313902eSAndy Walls 		 *
3214313902eSAndy Walls 		 * We just use q_full and let the work handler race with users
3224313902eSAndy Walls 		 * making ivtv-fileops.c calls on the PCM device node.
3234313902eSAndy Walls 		 *
3244313902eSAndy Walls 		 * Users should not be using both the ALSA and V4L2 PCM audio
3254313902eSAndy Walls 		 * capture interfaces at the same time.  If the user does this,
3264313902eSAndy Walls 		 * fragments of data will just go out each interface as they
3274313902eSAndy Walls 		 * race for PCM data.
3284313902eSAndy Walls 		 */
3294313902eSAndy Walls 		set_bit(IVTV_F_I_WORK_HANDLER_PCM, &itv->i_flags);
3304313902eSAndy Walls 		set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
3314313902eSAndy Walls 	}
3324313902eSAndy Walls 
333b285192aSMauro Carvalho Chehab 	if (s->fh)
334b285192aSMauro Carvalho Chehab 		wake_up(&s->waitq);
335b285192aSMauro Carvalho Chehab }
336b285192aSMauro Carvalho Chehab 
ivtv_dma_stream_dec_prepare(struct ivtv_stream * s,u32 offset,int lock)337b285192aSMauro Carvalho Chehab void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
338b285192aSMauro Carvalho Chehab {
339b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
340b285192aSMauro Carvalho Chehab 	struct yuv_playback_info *yi = &itv->yuv_info;
341b285192aSMauro Carvalho Chehab 	u8 frame = yi->draw_frame;
342b285192aSMauro Carvalho Chehab 	struct yuv_frame_info *f = &yi->new_frame_info[frame];
343b285192aSMauro Carvalho Chehab 	struct ivtv_buffer *buf;
344b285192aSMauro Carvalho Chehab 	u32 y_size = 720 * ((f->src_h + 31) & ~31);
345b285192aSMauro Carvalho Chehab 	u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
346b285192aSMauro Carvalho Chehab 	int y_done = 0;
347b285192aSMauro Carvalho Chehab 	int bytes_written = 0;
348b285192aSMauro Carvalho Chehab 	int idx = 0;
349b285192aSMauro Carvalho Chehab 
350b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
351b285192aSMauro Carvalho Chehab 
352b285192aSMauro Carvalho Chehab 	/* Insert buffer block for YUV if needed */
353b285192aSMauro Carvalho Chehab 	if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) {
354b285192aSMauro Carvalho Chehab 		if (yi->blanking_dmaptr) {
355b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].src = yi->blanking_dmaptr;
356b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].dst = offset;
357b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].size = 720 * 16;
358b285192aSMauro Carvalho Chehab 		}
359b285192aSMauro Carvalho Chehab 		offset += 720 * 16;
360b285192aSMauro Carvalho Chehab 		idx++;
361b285192aSMauro Carvalho Chehab 	}
362b285192aSMauro Carvalho Chehab 
363b285192aSMauro Carvalho Chehab 	list_for_each_entry(buf, &s->q_predma.list, list) {
364b285192aSMauro Carvalho Chehab 		/* YUV UV Offset from Y Buffer */
365b285192aSMauro Carvalho Chehab 		if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done &&
366b285192aSMauro Carvalho Chehab 				(bytes_written + buf->bytesused) >= y_size) {
367b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].src = buf->dma_handle;
368b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].dst = offset;
369b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].size = y_size - bytes_written;
370b285192aSMauro Carvalho Chehab 			offset = uv_offset;
371b285192aSMauro Carvalho Chehab 			if (s->sg_pending[idx].size != buf->bytesused) {
372b285192aSMauro Carvalho Chehab 				idx++;
373b285192aSMauro Carvalho Chehab 				s->sg_pending[idx].src =
374b285192aSMauro Carvalho Chehab 				  buf->dma_handle + s->sg_pending[idx - 1].size;
375b285192aSMauro Carvalho Chehab 				s->sg_pending[idx].dst = offset;
376b285192aSMauro Carvalho Chehab 				s->sg_pending[idx].size =
377b285192aSMauro Carvalho Chehab 				   buf->bytesused - s->sg_pending[idx - 1].size;
378b285192aSMauro Carvalho Chehab 				offset += s->sg_pending[idx].size;
379b285192aSMauro Carvalho Chehab 			}
380b285192aSMauro Carvalho Chehab 			y_done = 1;
381b285192aSMauro Carvalho Chehab 		} else {
382b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].src = buf->dma_handle;
383b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].dst = offset;
384b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].size = buf->bytesused;
385b285192aSMauro Carvalho Chehab 			offset += buf->bytesused;
386b285192aSMauro Carvalho Chehab 		}
387b285192aSMauro Carvalho Chehab 		bytes_written += buf->bytesused;
388b285192aSMauro Carvalho Chehab 
389b285192aSMauro Carvalho Chehab 		/* Sync SG buffers */
390b285192aSMauro Carvalho Chehab 		ivtv_buf_sync_for_device(s, buf);
391b285192aSMauro Carvalho Chehab 		idx++;
392b285192aSMauro Carvalho Chehab 	}
393b285192aSMauro Carvalho Chehab 	s->sg_pending_size = idx;
394b285192aSMauro Carvalho Chehab 
395b285192aSMauro Carvalho Chehab 	/* Sync Hardware SG List of buffers */
396b285192aSMauro Carvalho Chehab 	ivtv_stream_sync_for_device(s);
397d832672fSHans Verkuil 	if (lock) {
398d832672fSHans Verkuil 		unsigned long flags = 0;
399d832672fSHans Verkuil 
400b285192aSMauro Carvalho Chehab 		spin_lock_irqsave(&itv->dma_reg_lock, flags);
401d832672fSHans Verkuil 		if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
402b285192aSMauro Carvalho Chehab 			ivtv_dma_dec_start(s);
403d832672fSHans Verkuil 		else
404d832672fSHans Verkuil 			set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
405d832672fSHans Verkuil 		spin_unlock_irqrestore(&itv->dma_reg_lock, flags);
406d832672fSHans Verkuil 	} else {
407d832672fSHans Verkuil 		if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
408d832672fSHans Verkuil 			ivtv_dma_dec_start(s);
409d832672fSHans Verkuil 		else
410b285192aSMauro Carvalho Chehab 			set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
411b285192aSMauro Carvalho Chehab 	}
412b285192aSMauro Carvalho Chehab }
413b285192aSMauro Carvalho Chehab 
ivtv_dma_enc_start_xfer(struct ivtv_stream * s)414b285192aSMauro Carvalho Chehab static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s)
415b285192aSMauro Carvalho Chehab {
416b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
417b285192aSMauro Carvalho Chehab 
418b285192aSMauro Carvalho Chehab 	s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
419b285192aSMauro Carvalho Chehab 	s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
420b285192aSMauro Carvalho Chehab 	s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
421b285192aSMauro Carvalho Chehab 	s->sg_processed++;
422b285192aSMauro Carvalho Chehab 	/* Sync Hardware SG List of buffers */
423b285192aSMauro Carvalho Chehab 	ivtv_stream_sync_for_device(s);
424b285192aSMauro Carvalho Chehab 	write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR);
425b285192aSMauro Carvalho Chehab 	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
426b285192aSMauro Carvalho Chehab 	itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
427b285192aSMauro Carvalho Chehab 	add_timer(&itv->dma_timer);
428b285192aSMauro Carvalho Chehab }
429b285192aSMauro Carvalho Chehab 
ivtv_dma_dec_start_xfer(struct ivtv_stream * s)430b285192aSMauro Carvalho Chehab static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s)
431b285192aSMauro Carvalho Chehab {
432b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
433b285192aSMauro Carvalho Chehab 
434b285192aSMauro Carvalho Chehab 	s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
435b285192aSMauro Carvalho Chehab 	s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
436b285192aSMauro Carvalho Chehab 	s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
437b285192aSMauro Carvalho Chehab 	s->sg_processed++;
438b285192aSMauro Carvalho Chehab 	/* Sync Hardware SG List of buffers */
439b285192aSMauro Carvalho Chehab 	ivtv_stream_sync_for_device(s);
440b285192aSMauro Carvalho Chehab 	write_reg(s->sg_handle, IVTV_REG_DECDMAADDR);
441b285192aSMauro Carvalho Chehab 	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
442b285192aSMauro Carvalho Chehab 	itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
443b285192aSMauro Carvalho Chehab 	add_timer(&itv->dma_timer);
444b285192aSMauro Carvalho Chehab }
445b285192aSMauro Carvalho Chehab 
446b285192aSMauro Carvalho Chehab /* start the encoder DMA */
ivtv_dma_enc_start(struct ivtv_stream * s)447b285192aSMauro Carvalho Chehab static void ivtv_dma_enc_start(struct ivtv_stream *s)
448b285192aSMauro Carvalho Chehab {
449b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
450b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
451b285192aSMauro Carvalho Chehab 	int i;
452b285192aSMauro Carvalho Chehab 
453b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
454b285192aSMauro Carvalho Chehab 
455b285192aSMauro Carvalho Chehab 	if (s->q_predma.bytesused)
456b285192aSMauro Carvalho Chehab 		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
457b285192aSMauro Carvalho Chehab 
458b285192aSMauro Carvalho Chehab 	if (ivtv_use_dma(s))
459b285192aSMauro Carvalho Chehab 		s->sg_pending[s->sg_pending_size - 1].size += 256;
460b285192aSMauro Carvalho Chehab 
461b285192aSMauro Carvalho Chehab 	/* If this is an MPEG stream, and VBI data is also pending, then append the
462b285192aSMauro Carvalho Chehab 	   VBI DMA to the MPEG DMA and transfer both sets of data at once.
463b285192aSMauro Carvalho Chehab 
464b285192aSMauro Carvalho Chehab 	   VBI DMA is a second class citizen compared to MPEG and mixing them together
465b285192aSMauro Carvalho Chehab 	   will confuse the firmware (the end of a VBI DMA is seen as the end of a
466b285192aSMauro Carvalho Chehab 	   MPEG DMA, thus effectively dropping an MPEG frame). So instead we make
467b285192aSMauro Carvalho Chehab 	   sure we only use the MPEG DMA to transfer the VBI DMA if both are in
468b285192aSMauro Carvalho Chehab 	   use. This way no conflicts occur. */
469b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
470b285192aSMauro Carvalho Chehab 	if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size &&
471b285192aSMauro Carvalho Chehab 			s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) {
472b285192aSMauro Carvalho Chehab 		ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused);
473b285192aSMauro Carvalho Chehab 		if (ivtv_use_dma(s_vbi))
474b285192aSMauro Carvalho Chehab 			s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256;
475b285192aSMauro Carvalho Chehab 		for (i = 0; i < s_vbi->sg_pending_size; i++) {
476b285192aSMauro Carvalho Chehab 			s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i];
477b285192aSMauro Carvalho Chehab 		}
478b285192aSMauro Carvalho Chehab 		s_vbi->dma_offset = s_vbi->pending_offset;
479b285192aSMauro Carvalho Chehab 		s_vbi->sg_pending_size = 0;
480b285192aSMauro Carvalho Chehab 		s_vbi->dma_xfer_cnt++;
481b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
482b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name);
483b285192aSMauro Carvalho Chehab 	}
484b285192aSMauro Carvalho Chehab 
485b285192aSMauro Carvalho Chehab 	s->dma_xfer_cnt++;
486b285192aSMauro Carvalho Chehab 	memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
487b285192aSMauro Carvalho Chehab 	s->sg_processing_size = s->sg_pending_size;
488b285192aSMauro Carvalho Chehab 	s->sg_pending_size = 0;
489b285192aSMauro Carvalho Chehab 	s->sg_processed = 0;
490b285192aSMauro Carvalho Chehab 	s->dma_offset = s->pending_offset;
491b285192aSMauro Carvalho Chehab 	s->dma_backup = s->pending_backup;
492b285192aSMauro Carvalho Chehab 	s->dma_pts = s->pending_pts;
493b285192aSMauro Carvalho Chehab 
494b285192aSMauro Carvalho Chehab 	if (ivtv_use_pio(s)) {
495b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags);
496b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
497b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_I_PIO, &itv->i_flags);
498b285192aSMauro Carvalho Chehab 		itv->cur_pio_stream = s->type;
499b285192aSMauro Carvalho Chehab 	}
500b285192aSMauro Carvalho Chehab 	else {
501b285192aSMauro Carvalho Chehab 		itv->dma_retries = 0;
502b285192aSMauro Carvalho Chehab 		ivtv_dma_enc_start_xfer(s);
503b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_I_DMA, &itv->i_flags);
504b285192aSMauro Carvalho Chehab 		itv->cur_dma_stream = s->type;
505b285192aSMauro Carvalho Chehab 	}
506b285192aSMauro Carvalho Chehab }
507b285192aSMauro Carvalho Chehab 
ivtv_dma_dec_start(struct ivtv_stream * s)508b285192aSMauro Carvalho Chehab static void ivtv_dma_dec_start(struct ivtv_stream *s)
509b285192aSMauro Carvalho Chehab {
510b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
511b285192aSMauro Carvalho Chehab 
512b285192aSMauro Carvalho Chehab 	if (s->q_predma.bytesused)
513b285192aSMauro Carvalho Chehab 		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
514b285192aSMauro Carvalho Chehab 	s->dma_xfer_cnt++;
515b285192aSMauro Carvalho Chehab 	memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
516b285192aSMauro Carvalho Chehab 	s->sg_processing_size = s->sg_pending_size;
517b285192aSMauro Carvalho Chehab 	s->sg_pending_size = 0;
518b285192aSMauro Carvalho Chehab 	s->sg_processed = 0;
519b285192aSMauro Carvalho Chehab 
520b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name);
521b285192aSMauro Carvalho Chehab 	itv->dma_retries = 0;
522b285192aSMauro Carvalho Chehab 	ivtv_dma_dec_start_xfer(s);
523b285192aSMauro Carvalho Chehab 	set_bit(IVTV_F_I_DMA, &itv->i_flags);
524b285192aSMauro Carvalho Chehab 	itv->cur_dma_stream = s->type;
525b285192aSMauro Carvalho Chehab }
526b285192aSMauro Carvalho Chehab 
ivtv_irq_dma_read(struct ivtv * itv)527b285192aSMauro Carvalho Chehab static void ivtv_irq_dma_read(struct ivtv *itv)
528b285192aSMauro Carvalho Chehab {
529b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s = NULL;
530b285192aSMauro Carvalho Chehab 	struct ivtv_buffer *buf;
531b285192aSMauro Carvalho Chehab 	int hw_stream_type = 0;
532b285192aSMauro Carvalho Chehab 
533b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("DEC DMA READ\n");
534b285192aSMauro Carvalho Chehab 
535b285192aSMauro Carvalho Chehab 	del_timer(&itv->dma_timer);
536b285192aSMauro Carvalho Chehab 
537b285192aSMauro Carvalho Chehab 	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0)
538b285192aSMauro Carvalho Chehab 		return;
539b285192aSMauro Carvalho Chehab 
540b285192aSMauro Carvalho Chehab 	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
541b285192aSMauro Carvalho Chehab 		s = &itv->streams[itv->cur_dma_stream];
542b285192aSMauro Carvalho Chehab 		ivtv_stream_sync_for_cpu(s);
543b285192aSMauro Carvalho Chehab 
544b285192aSMauro Carvalho Chehab 		if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
545b285192aSMauro Carvalho Chehab 			IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n",
546b285192aSMauro Carvalho Chehab 					read_reg(IVTV_REG_DMASTATUS),
547b285192aSMauro Carvalho Chehab 					s->sg_processed, s->sg_processing_size, itv->dma_retries);
548b285192aSMauro Carvalho Chehab 			write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
549b285192aSMauro Carvalho Chehab 			if (itv->dma_retries == 3) {
550b285192aSMauro Carvalho Chehab 				/* Too many retries, give up on this frame */
551b285192aSMauro Carvalho Chehab 				itv->dma_retries = 0;
552b285192aSMauro Carvalho Chehab 				s->sg_processed = s->sg_processing_size;
553b285192aSMauro Carvalho Chehab 			}
554b285192aSMauro Carvalho Chehab 			else {
555b285192aSMauro Carvalho Chehab 				/* Retry, starting with the first xfer segment.
556b285192aSMauro Carvalho Chehab 				   Just retrying the current segment is not sufficient. */
557b285192aSMauro Carvalho Chehab 				s->sg_processed = 0;
558b285192aSMauro Carvalho Chehab 				itv->dma_retries++;
559b285192aSMauro Carvalho Chehab 			}
560b285192aSMauro Carvalho Chehab 		}
561b285192aSMauro Carvalho Chehab 		if (s->sg_processed < s->sg_processing_size) {
562b285192aSMauro Carvalho Chehab 			/* DMA next buffer */
563b285192aSMauro Carvalho Chehab 			ivtv_dma_dec_start_xfer(s);
564b285192aSMauro Carvalho Chehab 			return;
565b285192aSMauro Carvalho Chehab 		}
566b285192aSMauro Carvalho Chehab 		if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
567b285192aSMauro Carvalho Chehab 			hw_stream_type = 2;
568b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
569b285192aSMauro Carvalho Chehab 
570b285192aSMauro Carvalho Chehab 		/* For some reason must kick the firmware, like PIO mode,
571b285192aSMauro Carvalho Chehab 		   I think this tells the firmware we are done and the size
572b285192aSMauro Carvalho Chehab 		   of the xfer so it can calculate what we need next.
573b285192aSMauro Carvalho Chehab 		   I think we can do this part ourselves but would have to
574b285192aSMauro Carvalho Chehab 		   fully calculate xfer info ourselves and not use interrupts
575b285192aSMauro Carvalho Chehab 		 */
576b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, s->q_dma.bytesused,
577b285192aSMauro Carvalho Chehab 				hw_stream_type);
578b285192aSMauro Carvalho Chehab 
579b285192aSMauro Carvalho Chehab 		/* Free last DMA call */
580b285192aSMauro Carvalho Chehab 		while ((buf = ivtv_dequeue(s, &s->q_dma)) != NULL) {
581b285192aSMauro Carvalho Chehab 			ivtv_buf_sync_for_cpu(s, buf);
582b285192aSMauro Carvalho Chehab 			ivtv_enqueue(s, buf, &s->q_free);
583b285192aSMauro Carvalho Chehab 		}
584b285192aSMauro Carvalho Chehab 		wake_up(&s->waitq);
585b285192aSMauro Carvalho Chehab 	}
586b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
587b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
588b285192aSMauro Carvalho Chehab 	itv->cur_dma_stream = -1;
589b285192aSMauro Carvalho Chehab 	wake_up(&itv->dma_waitq);
590b285192aSMauro Carvalho Chehab }
591b285192aSMauro Carvalho Chehab 
ivtv_irq_enc_dma_complete(struct ivtv * itv)592b285192aSMauro Carvalho Chehab static void ivtv_irq_enc_dma_complete(struct ivtv *itv)
593b285192aSMauro Carvalho Chehab {
594b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
595b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s;
596b285192aSMauro Carvalho Chehab 
597b285192aSMauro Carvalho Chehab 	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data);
598b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream);
599b285192aSMauro Carvalho Chehab 
600b285192aSMauro Carvalho Chehab 	del_timer(&itv->dma_timer);
601b285192aSMauro Carvalho Chehab 
602b285192aSMauro Carvalho Chehab 	if (itv->cur_dma_stream < 0)
603b285192aSMauro Carvalho Chehab 		return;
604b285192aSMauro Carvalho Chehab 
605b285192aSMauro Carvalho Chehab 	s = &itv->streams[itv->cur_dma_stream];
606b285192aSMauro Carvalho Chehab 	ivtv_stream_sync_for_cpu(s);
607b285192aSMauro Carvalho Chehab 
608b285192aSMauro Carvalho Chehab 	if (data[0] & 0x18) {
609b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0],
610b285192aSMauro Carvalho Chehab 			s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries);
611b285192aSMauro Carvalho Chehab 		write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
612b285192aSMauro Carvalho Chehab 		if (itv->dma_retries == 3) {
613b285192aSMauro Carvalho Chehab 			/* Too many retries, give up on this frame */
614b285192aSMauro Carvalho Chehab 			itv->dma_retries = 0;
615b285192aSMauro Carvalho Chehab 			s->sg_processed = s->sg_processing_size;
616b285192aSMauro Carvalho Chehab 		}
617b285192aSMauro Carvalho Chehab 		else {
618b285192aSMauro Carvalho Chehab 			/* Retry, starting with the first xfer segment.
619b285192aSMauro Carvalho Chehab 			   Just retrying the current segment is not sufficient. */
620b285192aSMauro Carvalho Chehab 			s->sg_processed = 0;
621b285192aSMauro Carvalho Chehab 			itv->dma_retries++;
622b285192aSMauro Carvalho Chehab 		}
623b285192aSMauro Carvalho Chehab 	}
624b285192aSMauro Carvalho Chehab 	if (s->sg_processed < s->sg_processing_size) {
625b285192aSMauro Carvalho Chehab 		/* DMA next buffer */
626b285192aSMauro Carvalho Chehab 		ivtv_dma_enc_start_xfer(s);
627b285192aSMauro Carvalho Chehab 		return;
628b285192aSMauro Carvalho Chehab 	}
629b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
630b285192aSMauro Carvalho Chehab 	itv->cur_dma_stream = -1;
631b285192aSMauro Carvalho Chehab 	dma_post(s);
632b285192aSMauro Carvalho Chehab 	if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
633b285192aSMauro Carvalho Chehab 		s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
634b285192aSMauro Carvalho Chehab 		dma_post(s);
635b285192aSMauro Carvalho Chehab 	}
636b285192aSMauro Carvalho Chehab 	s->sg_processing_size = 0;
637b285192aSMauro Carvalho Chehab 	s->sg_processed = 0;
638b285192aSMauro Carvalho Chehab 	wake_up(&itv->dma_waitq);
639b285192aSMauro Carvalho Chehab }
640b285192aSMauro Carvalho Chehab 
ivtv_irq_enc_pio_complete(struct ivtv * itv)641b285192aSMauro Carvalho Chehab static void ivtv_irq_enc_pio_complete(struct ivtv *itv)
642b285192aSMauro Carvalho Chehab {
643b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s;
644b285192aSMauro Carvalho Chehab 
645b285192aSMauro Carvalho Chehab 	if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS) {
646b285192aSMauro Carvalho Chehab 		itv->cur_pio_stream = -1;
647b285192aSMauro Carvalho Chehab 		return;
648b285192aSMauro Carvalho Chehab 	}
649b285192aSMauro Carvalho Chehab 	s = &itv->streams[itv->cur_pio_stream];
650b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name);
651b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_PIO, &itv->i_flags);
652b285192aSMauro Carvalho Chehab 	itv->cur_pio_stream = -1;
653b285192aSMauro Carvalho Chehab 	dma_post(s);
654b285192aSMauro Carvalho Chehab 	if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
655b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 0);
656b285192aSMauro Carvalho Chehab 	else if (s->type == IVTV_ENC_STREAM_TYPE_YUV)
657b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 1);
658b285192aSMauro Carvalho Chehab 	else if (s->type == IVTV_ENC_STREAM_TYPE_PCM)
659b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2);
660b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_PIO, &itv->i_flags);
661b285192aSMauro Carvalho Chehab 	if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
662b285192aSMauro Carvalho Chehab 		s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
663b285192aSMauro Carvalho Chehab 		dma_post(s);
664b285192aSMauro Carvalho Chehab 	}
665b285192aSMauro Carvalho Chehab 	wake_up(&itv->dma_waitq);
666b285192aSMauro Carvalho Chehab }
667b285192aSMauro Carvalho Chehab 
ivtv_irq_dma_err(struct ivtv * itv)668b285192aSMauro Carvalho Chehab static void ivtv_irq_dma_err(struct ivtv *itv)
669b285192aSMauro Carvalho Chehab {
670b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
671b285192aSMauro Carvalho Chehab 	u32 status;
672b285192aSMauro Carvalho Chehab 
673b285192aSMauro Carvalho Chehab 	del_timer(&itv->dma_timer);
674b285192aSMauro Carvalho Chehab 
675b285192aSMauro Carvalho Chehab 	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data);
676b285192aSMauro Carvalho Chehab 	status = read_reg(IVTV_REG_DMASTATUS);
677b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1],
678b285192aSMauro Carvalho Chehab 				status, itv->cur_dma_stream);
679b285192aSMauro Carvalho Chehab 	/*
680b285192aSMauro Carvalho Chehab 	 * We do *not* write back to the IVTV_REG_DMASTATUS register to
681b285192aSMauro Carvalho Chehab 	 * clear the error status, if either the encoder write (0x02) or
682b285192aSMauro Carvalho Chehab 	 * decoder read (0x01) bus master DMA operation do not indicate
683b285192aSMauro Carvalho Chehab 	 * completed.  We can race with the DMA engine, which may have
684b285192aSMauro Carvalho Chehab 	 * transitioned to completed status *after* we read the register.
685b285192aSMauro Carvalho Chehab 	 * Setting a IVTV_REG_DMASTATUS flag back to "busy" status, after the
686b285192aSMauro Carvalho Chehab 	 * DMA engine has completed, will cause the DMA engine to stop working.
687b285192aSMauro Carvalho Chehab 	 */
688b285192aSMauro Carvalho Chehab 	status &= 0x3;
689b285192aSMauro Carvalho Chehab 	if (status == 0x3)
690b285192aSMauro Carvalho Chehab 		write_reg(status, IVTV_REG_DMASTATUS);
691b285192aSMauro Carvalho Chehab 
692b285192aSMauro Carvalho Chehab 	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) &&
693b285192aSMauro Carvalho Chehab 	    itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) {
694b285192aSMauro Carvalho Chehab 		struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream];
695b285192aSMauro Carvalho Chehab 
696b285192aSMauro Carvalho Chehab 		if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
697b285192aSMauro Carvalho Chehab 			/* retry */
698b285192aSMauro Carvalho Chehab 			/*
699b285192aSMauro Carvalho Chehab 			 * FIXME - handle cases of DMA error similar to
700b285192aSMauro Carvalho Chehab 			 * encoder below, except conditioned on status & 0x1
701b285192aSMauro Carvalho Chehab 			 */
702b285192aSMauro Carvalho Chehab 			ivtv_dma_dec_start(s);
703b285192aSMauro Carvalho Chehab 			return;
704b285192aSMauro Carvalho Chehab 		} else {
705b285192aSMauro Carvalho Chehab 			if ((status & 0x2) == 0) {
706b285192aSMauro Carvalho Chehab 				/*
707b285192aSMauro Carvalho Chehab 				 * CX2341x Bus Master DMA write is ongoing.
708b285192aSMauro Carvalho Chehab 				 * Reset the timer and let it complete.
709b285192aSMauro Carvalho Chehab 				 */
710b285192aSMauro Carvalho Chehab 				itv->dma_timer.expires =
711b285192aSMauro Carvalho Chehab 						jiffies + msecs_to_jiffies(600);
712b285192aSMauro Carvalho Chehab 				add_timer(&itv->dma_timer);
713b285192aSMauro Carvalho Chehab 				return;
714b285192aSMauro Carvalho Chehab 			}
715b285192aSMauro Carvalho Chehab 
716b285192aSMauro Carvalho Chehab 			if (itv->dma_retries < 3) {
717b285192aSMauro Carvalho Chehab 				/*
718b285192aSMauro Carvalho Chehab 				 * CX2341x Bus Master DMA write has ended.
719b285192aSMauro Carvalho Chehab 				 * Retry the write, starting with the first
720b285192aSMauro Carvalho Chehab 				 * xfer segment. Just retrying the current
721b285192aSMauro Carvalho Chehab 				 * segment is not sufficient.
722b285192aSMauro Carvalho Chehab 				 */
723b285192aSMauro Carvalho Chehab 				s->sg_processed = 0;
724b285192aSMauro Carvalho Chehab 				itv->dma_retries++;
725b285192aSMauro Carvalho Chehab 				ivtv_dma_enc_start_xfer(s);
726b285192aSMauro Carvalho Chehab 				return;
727b285192aSMauro Carvalho Chehab 			}
728b285192aSMauro Carvalho Chehab 			/* Too many retries, give up on this one */
729b285192aSMauro Carvalho Chehab 		}
730b285192aSMauro Carvalho Chehab 
731b285192aSMauro Carvalho Chehab 	}
732b285192aSMauro Carvalho Chehab 	if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
733b285192aSMauro Carvalho Chehab 		ivtv_udma_start(itv);
734b285192aSMauro Carvalho Chehab 		return;
735b285192aSMauro Carvalho Chehab 	}
736b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
737b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
738b285192aSMauro Carvalho Chehab 	itv->cur_dma_stream = -1;
739b285192aSMauro Carvalho Chehab 	wake_up(&itv->dma_waitq);
740b285192aSMauro Carvalho Chehab }
741b285192aSMauro Carvalho Chehab 
ivtv_irq_enc_start_cap(struct ivtv * itv)742b285192aSMauro Carvalho Chehab static void ivtv_irq_enc_start_cap(struct ivtv *itv)
743b285192aSMauro Carvalho Chehab {
744b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
745b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s;
746b285192aSMauro Carvalho Chehab 
747b285192aSMauro Carvalho Chehab 	/* Get DMA destination and size arguments from card */
748b285192aSMauro Carvalho Chehab 	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, 7, data);
749b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
750b285192aSMauro Carvalho Chehab 
751b285192aSMauro Carvalho Chehab 	if (data[0] > 2 || data[1] == 0 || data[2] == 0) {
752b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n",
753b285192aSMauro Carvalho Chehab 				data[0], data[1], data[2]);
754b285192aSMauro Carvalho Chehab 		return;
755b285192aSMauro Carvalho Chehab 	}
756b285192aSMauro Carvalho Chehab 	s = &itv->streams[ivtv_stream_map[data[0]]];
757b285192aSMauro Carvalho Chehab 	if (!stream_enc_dma_append(s, data)) {
758b285192aSMauro Carvalho Chehab 		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
759b285192aSMauro Carvalho Chehab 	}
760b285192aSMauro Carvalho Chehab }
761b285192aSMauro Carvalho Chehab 
ivtv_irq_enc_vbi_cap(struct ivtv * itv)762b285192aSMauro Carvalho Chehab static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
763b285192aSMauro Carvalho Chehab {
764b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
765b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s;
766b285192aSMauro Carvalho Chehab 
767b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
768b285192aSMauro Carvalho Chehab 	s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
769b285192aSMauro Carvalho Chehab 
770b285192aSMauro Carvalho Chehab 	if (!stream_enc_dma_append(s, data))
771b285192aSMauro Carvalho Chehab 		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
772b285192aSMauro Carvalho Chehab }
773b285192aSMauro Carvalho Chehab 
ivtv_irq_dec_vbi_reinsert(struct ivtv * itv)774b285192aSMauro Carvalho Chehab static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv)
775b285192aSMauro Carvalho Chehab {
776b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
777b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
778b285192aSMauro Carvalho Chehab 
779b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n");
780b285192aSMauro Carvalho Chehab 	if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) &&
781b285192aSMauro Carvalho Chehab 			!stream_enc_dma_append(s, data)) {
782b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags);
783b285192aSMauro Carvalho Chehab 	}
784b285192aSMauro Carvalho Chehab }
785b285192aSMauro Carvalho Chehab 
ivtv_irq_dec_data_req(struct ivtv * itv)786b285192aSMauro Carvalho Chehab static void ivtv_irq_dec_data_req(struct ivtv *itv)
787b285192aSMauro Carvalho Chehab {
788b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
789b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s;
790b285192aSMauro Carvalho Chehab 
791b285192aSMauro Carvalho Chehab 	/* YUV or MPG */
792b285192aSMauro Carvalho Chehab 
793b285192aSMauro Carvalho Chehab 	if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
794b285192aSMauro Carvalho Chehab 		ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data);
795b285192aSMauro Carvalho Chehab 		itv->dma_data_req_size =
796b285192aSMauro Carvalho Chehab 				 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
797b285192aSMauro Carvalho Chehab 		itv->dma_data_req_offset = data[1];
798b285192aSMauro Carvalho Chehab 		if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0)
799b285192aSMauro Carvalho Chehab 			ivtv_yuv_frame_complete(itv);
800b285192aSMauro Carvalho Chehab 		s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
801b285192aSMauro Carvalho Chehab 	}
802b285192aSMauro Carvalho Chehab 	else {
803b285192aSMauro Carvalho Chehab 		ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 3, data);
804b285192aSMauro Carvalho Chehab 		itv->dma_data_req_size = min_t(u32, data[2], 0x10000);
805b285192aSMauro Carvalho Chehab 		itv->dma_data_req_offset = data[1];
806b285192aSMauro Carvalho Chehab 		s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
807b285192aSMauro Carvalho Chehab 	}
808b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
809b285192aSMauro Carvalho Chehab 		       itv->dma_data_req_offset, itv->dma_data_req_size);
810b285192aSMauro Carvalho Chehab 	if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) {
811b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
812b285192aSMauro Carvalho Chehab 	}
813b285192aSMauro Carvalho Chehab 	else {
814b285192aSMauro Carvalho Chehab 		if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
815b285192aSMauro Carvalho Chehab 			ivtv_yuv_setup_stream_frame(itv);
816b285192aSMauro Carvalho Chehab 		clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
817b285192aSMauro Carvalho Chehab 		ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
818b285192aSMauro Carvalho Chehab 		ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0);
819b285192aSMauro Carvalho Chehab 	}
820b285192aSMauro Carvalho Chehab }
821b285192aSMauro Carvalho Chehab 
ivtv_irq_vsync(struct ivtv * itv)822b285192aSMauro Carvalho Chehab static void ivtv_irq_vsync(struct ivtv *itv)
823b285192aSMauro Carvalho Chehab {
824b285192aSMauro Carvalho Chehab 	/* The vsync interrupt is unusual in that it won't clear until
825b285192aSMauro Carvalho Chehab 	 * the end of the first line for the current field, at which
826b285192aSMauro Carvalho Chehab 	 * point it clears itself. This can result in repeated vsync
827b285192aSMauro Carvalho Chehab 	 * interrupts, or a missed vsync. Read some of the registers
828b285192aSMauro Carvalho Chehab 	 * to determine the line being displayed and ensure we handle
829b285192aSMauro Carvalho Chehab 	 * one vsync per frame.
830b285192aSMauro Carvalho Chehab 	 */
831b285192aSMauro Carvalho Chehab 	unsigned int frame = read_reg(IVTV_REG_DEC_LINE_FIELD) & 1;
832b285192aSMauro Carvalho Chehab 	struct yuv_playback_info *yi = &itv->yuv_info;
833b285192aSMauro Carvalho Chehab 	int last_dma_frame = atomic_read(&yi->next_dma_frame);
834b285192aSMauro Carvalho Chehab 	struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame];
835b285192aSMauro Carvalho Chehab 
836b285192aSMauro Carvalho Chehab 	if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
837b285192aSMauro Carvalho Chehab 
838b285192aSMauro Carvalho Chehab 	if (((frame ^ f->sync_field) == 0 &&
839b285192aSMauro Carvalho Chehab 		((itv->last_vsync_field & 1) ^ f->sync_field)) ||
840b285192aSMauro Carvalho Chehab 			(frame != (itv->last_vsync_field & 1) && !f->interlaced)) {
841b285192aSMauro Carvalho Chehab 		int next_dma_frame = last_dma_frame;
842b285192aSMauro Carvalho Chehab 
843b285192aSMauro Carvalho Chehab 		if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) {
844b285192aSMauro Carvalho Chehab 			if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) {
845b285192aSMauro Carvalho Chehab 				write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
846b285192aSMauro Carvalho Chehab 				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
847b285192aSMauro Carvalho Chehab 				write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
848b285192aSMauro Carvalho Chehab 				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
849b285192aSMauro Carvalho Chehab 				next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS;
850b285192aSMauro Carvalho Chehab 				atomic_set(&yi->next_dma_frame, next_dma_frame);
851b285192aSMauro Carvalho Chehab 				yi->fields_lapsed = -1;
852b285192aSMauro Carvalho Chehab 				yi->running = 1;
853b285192aSMauro Carvalho Chehab 			}
854b285192aSMauro Carvalho Chehab 		}
855b285192aSMauro Carvalho Chehab 	}
856b285192aSMauro Carvalho Chehab 	if (frame != (itv->last_vsync_field & 1)) {
857b285192aSMauro Carvalho Chehab 		static const struct v4l2_event evtop = {
858b285192aSMauro Carvalho Chehab 			.type = V4L2_EVENT_VSYNC,
859b285192aSMauro Carvalho Chehab 			.u.vsync.field = V4L2_FIELD_TOP,
860b285192aSMauro Carvalho Chehab 		};
861b285192aSMauro Carvalho Chehab 		static const struct v4l2_event evbottom = {
862b285192aSMauro Carvalho Chehab 			.type = V4L2_EVENT_VSYNC,
863b285192aSMauro Carvalho Chehab 			.u.vsync.field = V4L2_FIELD_BOTTOM,
864b285192aSMauro Carvalho Chehab 		};
865b285192aSMauro Carvalho Chehab 		struct ivtv_stream *s = ivtv_get_output_stream(itv);
866b285192aSMauro Carvalho Chehab 
867b285192aSMauro Carvalho Chehab 		itv->last_vsync_field += 1;
868b285192aSMauro Carvalho Chehab 		if (frame == 0) {
869b285192aSMauro Carvalho Chehab 			clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
870b285192aSMauro Carvalho Chehab 			clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags);
871b285192aSMauro Carvalho Chehab 		}
872b285192aSMauro Carvalho Chehab 		else {
873b285192aSMauro Carvalho Chehab 			set_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags);
874b285192aSMauro Carvalho Chehab 		}
875b285192aSMauro Carvalho Chehab 		if (test_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags)) {
876b285192aSMauro Carvalho Chehab 			set_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags);
877b285192aSMauro Carvalho Chehab 			wake_up(&itv->event_waitq);
878b285192aSMauro Carvalho Chehab 			if (s)
879b285192aSMauro Carvalho Chehab 				wake_up(&s->waitq);
880b285192aSMauro Carvalho Chehab 		}
881635d62f0SHans Verkuil 		if (s && s->vdev.v4l2_dev)
882635d62f0SHans Verkuil 			v4l2_event_queue(&s->vdev, frame ? &evtop : &evbottom);
883b285192aSMauro Carvalho Chehab 		wake_up(&itv->vsync_waitq);
884b285192aSMauro Carvalho Chehab 
885b285192aSMauro Carvalho Chehab 		/* Send VBI to saa7127 */
886b285192aSMauro Carvalho Chehab 		if (frame && (itv->output_mode == OUT_PASSTHROUGH ||
887b285192aSMauro Carvalho Chehab 			test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) ||
888b285192aSMauro Carvalho Chehab 			test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) ||
889b285192aSMauro Carvalho Chehab 			test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) {
890b285192aSMauro Carvalho Chehab 			set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags);
891b285192aSMauro Carvalho Chehab 			set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
892b285192aSMauro Carvalho Chehab 		}
893b285192aSMauro Carvalho Chehab 
894b285192aSMauro Carvalho Chehab 		/* Check if we need to update the yuv registers */
895b285192aSMauro Carvalho Chehab 		if (yi->running && (yi->yuv_forced_update || f->update)) {
896b285192aSMauro Carvalho Chehab 			if (!f->update) {
897b285192aSMauro Carvalho Chehab 				last_dma_frame =
898b285192aSMauro Carvalho Chehab 					(u8)(atomic_read(&yi->next_dma_frame) -
899b285192aSMauro Carvalho Chehab 						 1) % IVTV_YUV_BUFFERS;
900b285192aSMauro Carvalho Chehab 				f = &yi->new_frame_info[last_dma_frame];
901b285192aSMauro Carvalho Chehab 			}
902b285192aSMauro Carvalho Chehab 
903b285192aSMauro Carvalho Chehab 			if (f->src_w) {
904b285192aSMauro Carvalho Chehab 				yi->update_frame = last_dma_frame;
905b285192aSMauro Carvalho Chehab 				f->update = 0;
906b285192aSMauro Carvalho Chehab 				yi->yuv_forced_update = 0;
907b285192aSMauro Carvalho Chehab 				set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags);
908b285192aSMauro Carvalho Chehab 				set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
909b285192aSMauro Carvalho Chehab 			}
910b285192aSMauro Carvalho Chehab 		}
911b285192aSMauro Carvalho Chehab 
912b285192aSMauro Carvalho Chehab 		yi->fields_lapsed++;
913b285192aSMauro Carvalho Chehab 	}
914b285192aSMauro Carvalho Chehab }
915b285192aSMauro Carvalho Chehab 
916b285192aSMauro Carvalho Chehab #define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_VBI_RE_INSERT)
917b285192aSMauro Carvalho Chehab 
ivtv_irq_handler(int irq,void * dev_id)918b285192aSMauro Carvalho Chehab irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
919b285192aSMauro Carvalho Chehab {
920b285192aSMauro Carvalho Chehab 	struct ivtv *itv = (struct ivtv *)dev_id;
921b285192aSMauro Carvalho Chehab 	u32 combo;
922b285192aSMauro Carvalho Chehab 	u32 stat;
923b285192aSMauro Carvalho Chehab 	int i;
924b285192aSMauro Carvalho Chehab 	u8 vsync_force = 0;
925b285192aSMauro Carvalho Chehab 
926b285192aSMauro Carvalho Chehab 	spin_lock(&itv->dma_reg_lock);
927b285192aSMauro Carvalho Chehab 	/* get contents of irq status register */
928b285192aSMauro Carvalho Chehab 	stat = read_reg(IVTV_REG_IRQSTATUS);
929b285192aSMauro Carvalho Chehab 
930b285192aSMauro Carvalho Chehab 	combo = ~itv->irqmask & stat;
931b285192aSMauro Carvalho Chehab 
932b285192aSMauro Carvalho Chehab 	/* Clear out IRQ */
933b285192aSMauro Carvalho Chehab 	if (combo) write_reg(combo, IVTV_REG_IRQSTATUS);
934b285192aSMauro Carvalho Chehab 
935b285192aSMauro Carvalho Chehab 	if (0 == combo) {
936b285192aSMauro Carvalho Chehab 		/* The vsync interrupt is unusual and clears itself. If we
937b285192aSMauro Carvalho Chehab 		 * took too long, we may have missed it. Do some checks
938b285192aSMauro Carvalho Chehab 		 */
939b285192aSMauro Carvalho Chehab 		if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
940b285192aSMauro Carvalho Chehab 			/* vsync is enabled, see if we're in a new field */
941b285192aSMauro Carvalho Chehab 			if ((itv->last_vsync_field & 1) !=
942b285192aSMauro Carvalho Chehab 			    (read_reg(IVTV_REG_DEC_LINE_FIELD) & 1)) {
943b285192aSMauro Carvalho Chehab 				/* New field, looks like we missed it */
944b285192aSMauro Carvalho Chehab 				IVTV_DEBUG_YUV("VSync interrupt missed %d\n",
945b285192aSMauro Carvalho Chehab 				       read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16);
946b285192aSMauro Carvalho Chehab 				vsync_force = 1;
947b285192aSMauro Carvalho Chehab 			}
948b285192aSMauro Carvalho Chehab 		}
949b285192aSMauro Carvalho Chehab 
950b285192aSMauro Carvalho Chehab 		if (!vsync_force) {
951b285192aSMauro Carvalho Chehab 			/* No Vsync expected, wasn't for us */
952b285192aSMauro Carvalho Chehab 			spin_unlock(&itv->dma_reg_lock);
953b285192aSMauro Carvalho Chehab 			return IRQ_NONE;
954b285192aSMauro Carvalho Chehab 		}
955b285192aSMauro Carvalho Chehab 	}
956b285192aSMauro Carvalho Chehab 
957b285192aSMauro Carvalho Chehab 	/* Exclude interrupts noted below from the output, otherwise the log is flooded with
958b285192aSMauro Carvalho Chehab 	   these messages */
959b285192aSMauro Carvalho Chehab 	if (combo & ~0xff6d0400)
960b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
961b285192aSMauro Carvalho Chehab 
962b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) {
963b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n");
964b285192aSMauro Carvalho Chehab 	}
965b285192aSMauro Carvalho Chehab 
966b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_DMA_READ) {
967b285192aSMauro Carvalho Chehab 		ivtv_irq_dma_read(itv);
968b285192aSMauro Carvalho Chehab 	}
969b285192aSMauro Carvalho Chehab 
970b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) {
971b285192aSMauro Carvalho Chehab 		ivtv_irq_enc_dma_complete(itv);
972b285192aSMauro Carvalho Chehab 	}
973b285192aSMauro Carvalho Chehab 
974b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_ENC_PIO_COMPLETE) {
975b285192aSMauro Carvalho Chehab 		ivtv_irq_enc_pio_complete(itv);
976b285192aSMauro Carvalho Chehab 	}
977b285192aSMauro Carvalho Chehab 
978b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_DMA_ERR) {
979b285192aSMauro Carvalho Chehab 		ivtv_irq_dma_err(itv);
980b285192aSMauro Carvalho Chehab 	}
981b285192aSMauro Carvalho Chehab 
982b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_ENC_START_CAP) {
983b285192aSMauro Carvalho Chehab 		ivtv_irq_enc_start_cap(itv);
984b285192aSMauro Carvalho Chehab 	}
985b285192aSMauro Carvalho Chehab 
986b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_ENC_VBI_CAP) {
987b285192aSMauro Carvalho Chehab 		ivtv_irq_enc_vbi_cap(itv);
988b285192aSMauro Carvalho Chehab 	}
989b285192aSMauro Carvalho Chehab 
990b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) {
991b285192aSMauro Carvalho Chehab 		ivtv_irq_dec_vbi_reinsert(itv);
992b285192aSMauro Carvalho Chehab 	}
993b285192aSMauro Carvalho Chehab 
994b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_ENC_EOS) {
995b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_IRQ("ENC EOS\n");
996b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_I_EOS, &itv->i_flags);
997b285192aSMauro Carvalho Chehab 		wake_up(&itv->eos_waitq);
998b285192aSMauro Carvalho Chehab 	}
999b285192aSMauro Carvalho Chehab 
1000b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_DEC_DATA_REQ) {
1001b285192aSMauro Carvalho Chehab 		ivtv_irq_dec_data_req(itv);
1002b285192aSMauro Carvalho Chehab 	}
1003b285192aSMauro Carvalho Chehab 
1004b285192aSMauro Carvalho Chehab 	/* Decoder Vertical Sync - We can't rely on 'combo', so check if vsync enabled */
1005b285192aSMauro Carvalho Chehab 	if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
1006b285192aSMauro Carvalho Chehab 		ivtv_irq_vsync(itv);
1007b285192aSMauro Carvalho Chehab 	}
1008b285192aSMauro Carvalho Chehab 
1009b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_ENC_VIM_RST) {
1010b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_IRQ("VIM RST\n");
1011b285192aSMauro Carvalho Chehab 		/*ivtv_vapi(itv, CX2341X_ENC_REFRESH_INPUT, 0); */
1012b285192aSMauro Carvalho Chehab 	}
1013b285192aSMauro Carvalho Chehab 
1014b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) {
1015b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_INFO("Stereo mode changed\n");
1016b285192aSMauro Carvalho Chehab 	}
1017b285192aSMauro Carvalho Chehab 
1018b285192aSMauro Carvalho Chehab 	if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
1019b285192aSMauro Carvalho Chehab 		itv->irq_rr_idx++;
1020b285192aSMauro Carvalho Chehab 		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
1021b285192aSMauro Carvalho Chehab 			int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
1022b285192aSMauro Carvalho Chehab 			struct ivtv_stream *s = &itv->streams[idx];
1023b285192aSMauro Carvalho Chehab 
1024b285192aSMauro Carvalho Chehab 			if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags))
1025b285192aSMauro Carvalho Chehab 				continue;
1026b285192aSMauro Carvalho Chehab 			if (s->type >= IVTV_DEC_STREAM_TYPE_MPG)
1027b285192aSMauro Carvalho Chehab 				ivtv_dma_dec_start(s);
1028b285192aSMauro Carvalho Chehab 			else
1029b285192aSMauro Carvalho Chehab 				ivtv_dma_enc_start(s);
1030b285192aSMauro Carvalho Chehab 			break;
1031b285192aSMauro Carvalho Chehab 		}
1032b285192aSMauro Carvalho Chehab 
1033b285192aSMauro Carvalho Chehab 		if (i == IVTV_MAX_STREAMS &&
1034b285192aSMauro Carvalho Chehab 		    test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
1035b285192aSMauro Carvalho Chehab 			ivtv_udma_start(itv);
1036b285192aSMauro Carvalho Chehab 	}
1037b285192aSMauro Carvalho Chehab 
1038b285192aSMauro Carvalho Chehab 	if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) {
1039b285192aSMauro Carvalho Chehab 		itv->irq_rr_idx++;
1040b285192aSMauro Carvalho Chehab 		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
1041b285192aSMauro Carvalho Chehab 			int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
1042b285192aSMauro Carvalho Chehab 			struct ivtv_stream *s = &itv->streams[idx];
1043b285192aSMauro Carvalho Chehab 
1044b285192aSMauro Carvalho Chehab 			if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags))
1045b285192aSMauro Carvalho Chehab 				continue;
1046b285192aSMauro Carvalho Chehab 			if (s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type < IVTV_DEC_STREAM_TYPE_MPG)
1047b285192aSMauro Carvalho Chehab 				ivtv_dma_enc_start(s);
1048b285192aSMauro Carvalho Chehab 			break;
1049b285192aSMauro Carvalho Chehab 		}
1050b285192aSMauro Carvalho Chehab 	}
1051b285192aSMauro Carvalho Chehab 
1052b285192aSMauro Carvalho Chehab 	if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) {
10533989144fSPetr Mladek 		kthread_queue_work(&itv->irq_worker, &itv->irq_work);
1054b285192aSMauro Carvalho Chehab 	}
1055b285192aSMauro Carvalho Chehab 
1056b285192aSMauro Carvalho Chehab 	spin_unlock(&itv->dma_reg_lock);
1057b285192aSMauro Carvalho Chehab 
1058b285192aSMauro Carvalho Chehab 	/* If we've just handled a 'forced' vsync, it's safest to say it
1059b285192aSMauro Carvalho Chehab 	 * wasn't ours. Another device may have triggered it at just
1060b285192aSMauro Carvalho Chehab 	 * the right time.
1061b285192aSMauro Carvalho Chehab 	 */
1062b285192aSMauro Carvalho Chehab 	return vsync_force ? IRQ_NONE : IRQ_HANDLED;
1063b285192aSMauro Carvalho Chehab }
1064b285192aSMauro Carvalho Chehab 
ivtv_unfinished_dma(struct timer_list * t)1065162e6376SKees Cook void ivtv_unfinished_dma(struct timer_list *t)
1066b285192aSMauro Carvalho Chehab {
1067162e6376SKees Cook 	struct ivtv *itv = from_timer(itv, t, dma_timer);
1068b285192aSMauro Carvalho Chehab 
1069b285192aSMauro Carvalho Chehab 	if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
1070b285192aSMauro Carvalho Chehab 		return;
1071b285192aSMauro Carvalho Chehab 	IVTV_ERR("DMA TIMEOUT %08x %d\n", read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
1072b285192aSMauro Carvalho Chehab 
1073b285192aSMauro Carvalho Chehab 	write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
1074b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
1075b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
1076b285192aSMauro Carvalho Chehab 	itv->cur_dma_stream = -1;
1077b285192aSMauro Carvalho Chehab 	wake_up(&itv->dma_waitq);
1078b285192aSMauro Carvalho Chehab }
1079