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