xref: /openbmc/linux/drivers/media/pci/ivtv/ivtv-irq.c (revision d832672f2038d7b36dc08636468cbbed4afe625b)
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 
414313902eSAndy Walls static void ivtv_pcm_work_handler(struct ivtv *itv)
424313902eSAndy Walls {
434313902eSAndy Walls 	struct ivtv_stream *s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
444313902eSAndy Walls 	struct ivtv_buffer *buf;
454313902eSAndy Walls 
464313902eSAndy Walls 	/* Pass the PCM data to ivtv-alsa */
474313902eSAndy Walls 
484313902eSAndy Walls 	while (1) {
494313902eSAndy Walls 		/*
504313902eSAndy Walls 		 * Users should not be using both the ALSA and V4L2 PCM audio
514313902eSAndy Walls 		 * capture interfaces at the same time.  If the user is doing
524313902eSAndy Walls 		 * this, there maybe a buffer in q_io to grab, use, and put
534313902eSAndy Walls 		 * back in rotation.
544313902eSAndy Walls 		 */
554313902eSAndy Walls 		buf = ivtv_dequeue(s, &s->q_io);
564313902eSAndy Walls 		if (buf == NULL)
574313902eSAndy Walls 			buf = ivtv_dequeue(s, &s->q_full);
584313902eSAndy Walls 		if (buf == NULL)
594313902eSAndy Walls 			break;
604313902eSAndy Walls 
614313902eSAndy Walls 		if (buf->readpos < buf->bytesused)
624313902eSAndy Walls 			itv->pcm_announce_callback(itv->alsa,
634313902eSAndy Walls 				(u8 *)(buf->buf + buf->readpos),
644313902eSAndy Walls 				(size_t)(buf->bytesused - buf->readpos));
654313902eSAndy Walls 
664313902eSAndy Walls 		ivtv_enqueue(s, buf, &s->q_free);
674313902eSAndy Walls 	}
684313902eSAndy 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);
1144313902eSAndy Walls 
1154313902eSAndy Walls 	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PCM, &itv->i_flags))
1164313902eSAndy 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);
1953efb8ab6SHans Verkuil 			write_dec_sync(DMA_MAGIC_COOKIE, offset - IVTV_DECODER_OFFSET);
196b285192aSMauro Carvalho Chehab 		}
197b285192aSMauro Carvalho Chehab 		else {
198b285192aSMauro Carvalho Chehab 			s->pending_backup = read_enc(offset);
1993efb8ab6SHans Verkuil 			write_enc_sync(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;
2783efb8ab6SHans Verkuil 			if (le32_to_cpu(u32buf[offset / 4]) != DMA_MAGIC_COOKIE)
279b285192aSMauro Carvalho Chehab 			{
2803efb8ab6SHans Verkuil 				for (offset = 0; offset < 64; offset++)
2813efb8ab6SHans Verkuil 					if (le32_to_cpu(u32buf[offset]) == DMA_MAGIC_COOKIE)
282b285192aSMauro Carvalho Chehab 						break;
283b285192aSMauro Carvalho Chehab 				offset *= 4;
284b285192aSMauro Carvalho Chehab 				if (offset == 256) {
285b285192aSMauro Carvalho Chehab 					IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name);
286b285192aSMauro Carvalho Chehab 					offset = s->dma_last_offset;
287b285192aSMauro Carvalho Chehab 				}
288b285192aSMauro Carvalho Chehab 				if (s->dma_last_offset != offset)
289b285192aSMauro Carvalho Chehab 					IVTV_DEBUG_WARN("%s: offset %d -> %d\n", s->name, s->dma_last_offset, offset);
290b285192aSMauro Carvalho Chehab 				s->dma_last_offset = offset;
291b285192aSMauro Carvalho Chehab 			}
292b285192aSMauro Carvalho Chehab 			if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
293b285192aSMauro Carvalho Chehab 						s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
294b285192aSMauro Carvalho Chehab 				write_dec_sync(0, s->dma_offset - IVTV_DECODER_OFFSET);
295b285192aSMauro Carvalho Chehab 			}
296b285192aSMauro Carvalho Chehab 			else {
297b285192aSMauro Carvalho Chehab 				write_enc_sync(0, s->dma_offset);
298b285192aSMauro Carvalho Chehab 			}
299b285192aSMauro Carvalho Chehab 			if (offset) {
300b285192aSMauro Carvalho Chehab 				buf->bytesused -= offset;
301b285192aSMauro Carvalho Chehab 				memcpy(buf->buf, buf->buf + offset, buf->bytesused + offset);
302b285192aSMauro Carvalho Chehab 			}
303b285192aSMauro Carvalho Chehab 			*u32buf = cpu_to_le32(s->dma_backup);
304b285192aSMauro Carvalho Chehab 		}
305b285192aSMauro Carvalho Chehab 		x++;
306b285192aSMauro Carvalho Chehab 		/* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */
307b285192aSMauro Carvalho Chehab 		if (s->type == IVTV_ENC_STREAM_TYPE_MPG ||
308b285192aSMauro Carvalho Chehab 		    s->type == IVTV_ENC_STREAM_TYPE_VBI)
309b285192aSMauro Carvalho Chehab 			buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP;
310b285192aSMauro Carvalho Chehab 	}
311b285192aSMauro Carvalho Chehab 	if (buf)
312b285192aSMauro Carvalho Chehab 		buf->bytesused += s->dma_last_offset;
313b285192aSMauro Carvalho Chehab 	if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) {
314b285192aSMauro Carvalho Chehab 		list_for_each_entry(buf, &s->q_dma.list, list) {
315b285192aSMauro Carvalho Chehab 			/* Parse and Groom VBI Data */
316b285192aSMauro Carvalho Chehab 			s->q_dma.bytesused -= buf->bytesused;
317b285192aSMauro Carvalho Chehab 			ivtv_process_vbi_data(itv, buf, 0, s->type);
318b285192aSMauro Carvalho Chehab 			s->q_dma.bytesused += buf->bytesused;
319b285192aSMauro Carvalho Chehab 		}
320b285192aSMauro Carvalho Chehab 		if (s->fh == NULL) {
321b285192aSMauro Carvalho Chehab 			ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
322b285192aSMauro Carvalho Chehab 			return;
323b285192aSMauro Carvalho Chehab 		}
324b285192aSMauro Carvalho Chehab 	}
3254313902eSAndy Walls 
326b285192aSMauro Carvalho Chehab 	ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused);
3274313902eSAndy Walls 
3284313902eSAndy Walls 	if (s->type == IVTV_ENC_STREAM_TYPE_PCM &&
3294313902eSAndy Walls 	    itv->pcm_announce_callback != NULL) {
3304313902eSAndy Walls 		/*
3314313902eSAndy Walls 		 * Set up the work handler to pass the data to ivtv-alsa.
3324313902eSAndy Walls 		 *
3334313902eSAndy Walls 		 * We just use q_full and let the work handler race with users
3344313902eSAndy Walls 		 * making ivtv-fileops.c calls on the PCM device node.
3354313902eSAndy Walls 		 *
3364313902eSAndy Walls 		 * Users should not be using both the ALSA and V4L2 PCM audio
3374313902eSAndy Walls 		 * capture interfaces at the same time.  If the user does this,
3384313902eSAndy Walls 		 * fragments of data will just go out each interface as they
3394313902eSAndy Walls 		 * race for PCM data.
3404313902eSAndy Walls 		 */
3414313902eSAndy Walls 		set_bit(IVTV_F_I_WORK_HANDLER_PCM, &itv->i_flags);
3424313902eSAndy Walls 		set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
3434313902eSAndy Walls 	}
3444313902eSAndy Walls 
345b285192aSMauro Carvalho Chehab 	if (s->fh)
346b285192aSMauro Carvalho Chehab 		wake_up(&s->waitq);
347b285192aSMauro Carvalho Chehab }
348b285192aSMauro Carvalho Chehab 
349b285192aSMauro Carvalho Chehab void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
350b285192aSMauro Carvalho Chehab {
351b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
352b285192aSMauro Carvalho Chehab 	struct yuv_playback_info *yi = &itv->yuv_info;
353b285192aSMauro Carvalho Chehab 	u8 frame = yi->draw_frame;
354b285192aSMauro Carvalho Chehab 	struct yuv_frame_info *f = &yi->new_frame_info[frame];
355b285192aSMauro Carvalho Chehab 	struct ivtv_buffer *buf;
356b285192aSMauro Carvalho Chehab 	u32 y_size = 720 * ((f->src_h + 31) & ~31);
357b285192aSMauro Carvalho Chehab 	u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
358b285192aSMauro Carvalho Chehab 	int y_done = 0;
359b285192aSMauro Carvalho Chehab 	int bytes_written = 0;
360b285192aSMauro Carvalho Chehab 	int idx = 0;
361b285192aSMauro Carvalho Chehab 
362b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
363b285192aSMauro Carvalho Chehab 
364b285192aSMauro Carvalho Chehab 	/* Insert buffer block for YUV if needed */
365b285192aSMauro Carvalho Chehab 	if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) {
366b285192aSMauro Carvalho Chehab 		if (yi->blanking_dmaptr) {
367b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].src = yi->blanking_dmaptr;
368b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].dst = offset;
369b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].size = 720 * 16;
370b285192aSMauro Carvalho Chehab 		}
371b285192aSMauro Carvalho Chehab 		offset += 720 * 16;
372b285192aSMauro Carvalho Chehab 		idx++;
373b285192aSMauro Carvalho Chehab 	}
374b285192aSMauro Carvalho Chehab 
375b285192aSMauro Carvalho Chehab 	list_for_each_entry(buf, &s->q_predma.list, list) {
376b285192aSMauro Carvalho Chehab 		/* YUV UV Offset from Y Buffer */
377b285192aSMauro Carvalho Chehab 		if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done &&
378b285192aSMauro Carvalho Chehab 				(bytes_written + buf->bytesused) >= y_size) {
379b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].src = buf->dma_handle;
380b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].dst = offset;
381b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].size = y_size - bytes_written;
382b285192aSMauro Carvalho Chehab 			offset = uv_offset;
383b285192aSMauro Carvalho Chehab 			if (s->sg_pending[idx].size != buf->bytesused) {
384b285192aSMauro Carvalho Chehab 				idx++;
385b285192aSMauro Carvalho Chehab 				s->sg_pending[idx].src =
386b285192aSMauro Carvalho Chehab 				  buf->dma_handle + s->sg_pending[idx - 1].size;
387b285192aSMauro Carvalho Chehab 				s->sg_pending[idx].dst = offset;
388b285192aSMauro Carvalho Chehab 				s->sg_pending[idx].size =
389b285192aSMauro Carvalho Chehab 				   buf->bytesused - s->sg_pending[idx - 1].size;
390b285192aSMauro Carvalho Chehab 				offset += s->sg_pending[idx].size;
391b285192aSMauro Carvalho Chehab 			}
392b285192aSMauro Carvalho Chehab 			y_done = 1;
393b285192aSMauro Carvalho Chehab 		} else {
394b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].src = buf->dma_handle;
395b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].dst = offset;
396b285192aSMauro Carvalho Chehab 			s->sg_pending[idx].size = buf->bytesused;
397b285192aSMauro Carvalho Chehab 			offset += buf->bytesused;
398b285192aSMauro Carvalho Chehab 		}
399b285192aSMauro Carvalho Chehab 		bytes_written += buf->bytesused;
400b285192aSMauro Carvalho Chehab 
401b285192aSMauro Carvalho Chehab 		/* Sync SG buffers */
402b285192aSMauro Carvalho Chehab 		ivtv_buf_sync_for_device(s, buf);
403b285192aSMauro Carvalho Chehab 		idx++;
404b285192aSMauro Carvalho Chehab 	}
405b285192aSMauro Carvalho Chehab 	s->sg_pending_size = idx;
406b285192aSMauro Carvalho Chehab 
407b285192aSMauro Carvalho Chehab 	/* Sync Hardware SG List of buffers */
408b285192aSMauro Carvalho Chehab 	ivtv_stream_sync_for_device(s);
409*d832672fSHans Verkuil 	if (lock) {
410*d832672fSHans Verkuil 		unsigned long flags = 0;
411*d832672fSHans Verkuil 
412b285192aSMauro Carvalho Chehab 		spin_lock_irqsave(&itv->dma_reg_lock, flags);
413*d832672fSHans Verkuil 		if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
414b285192aSMauro Carvalho Chehab 			ivtv_dma_dec_start(s);
415*d832672fSHans Verkuil 		else
416*d832672fSHans Verkuil 			set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
417*d832672fSHans Verkuil 		spin_unlock_irqrestore(&itv->dma_reg_lock, flags);
418*d832672fSHans Verkuil 	} else {
419*d832672fSHans Verkuil 		if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
420*d832672fSHans Verkuil 			ivtv_dma_dec_start(s);
421*d832672fSHans Verkuil 		else
422b285192aSMauro Carvalho Chehab 			set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
423b285192aSMauro Carvalho Chehab 	}
424b285192aSMauro Carvalho Chehab }
425b285192aSMauro Carvalho Chehab 
426b285192aSMauro Carvalho Chehab static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s)
427b285192aSMauro Carvalho Chehab {
428b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
429b285192aSMauro Carvalho Chehab 
430b285192aSMauro Carvalho Chehab 	s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
431b285192aSMauro Carvalho Chehab 	s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
432b285192aSMauro Carvalho Chehab 	s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
433b285192aSMauro Carvalho Chehab 	s->sg_processed++;
434b285192aSMauro Carvalho Chehab 	/* Sync Hardware SG List of buffers */
435b285192aSMauro Carvalho Chehab 	ivtv_stream_sync_for_device(s);
436b285192aSMauro Carvalho Chehab 	write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR);
437b285192aSMauro Carvalho Chehab 	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
438b285192aSMauro Carvalho Chehab 	itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
439b285192aSMauro Carvalho Chehab 	add_timer(&itv->dma_timer);
440b285192aSMauro Carvalho Chehab }
441b285192aSMauro Carvalho Chehab 
442b285192aSMauro Carvalho Chehab static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s)
443b285192aSMauro Carvalho Chehab {
444b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
445b285192aSMauro Carvalho Chehab 
446b285192aSMauro Carvalho Chehab 	s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
447b285192aSMauro Carvalho Chehab 	s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
448b285192aSMauro Carvalho Chehab 	s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
449b285192aSMauro Carvalho Chehab 	s->sg_processed++;
450b285192aSMauro Carvalho Chehab 	/* Sync Hardware SG List of buffers */
451b285192aSMauro Carvalho Chehab 	ivtv_stream_sync_for_device(s);
452b285192aSMauro Carvalho Chehab 	write_reg(s->sg_handle, IVTV_REG_DECDMAADDR);
453b285192aSMauro Carvalho Chehab 	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
454b285192aSMauro Carvalho Chehab 	itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
455b285192aSMauro Carvalho Chehab 	add_timer(&itv->dma_timer);
456b285192aSMauro Carvalho Chehab }
457b285192aSMauro Carvalho Chehab 
458b285192aSMauro Carvalho Chehab /* start the encoder DMA */
459b285192aSMauro Carvalho Chehab static void ivtv_dma_enc_start(struct ivtv_stream *s)
460b285192aSMauro Carvalho Chehab {
461b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
462b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
463b285192aSMauro Carvalho Chehab 	int i;
464b285192aSMauro Carvalho Chehab 
465b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
466b285192aSMauro Carvalho Chehab 
467b285192aSMauro Carvalho Chehab 	if (s->q_predma.bytesused)
468b285192aSMauro Carvalho Chehab 		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
469b285192aSMauro Carvalho Chehab 
470b285192aSMauro Carvalho Chehab 	if (ivtv_use_dma(s))
471b285192aSMauro Carvalho Chehab 		s->sg_pending[s->sg_pending_size - 1].size += 256;
472b285192aSMauro Carvalho Chehab 
473b285192aSMauro Carvalho Chehab 	/* If this is an MPEG stream, and VBI data is also pending, then append the
474b285192aSMauro Carvalho Chehab 	   VBI DMA to the MPEG DMA and transfer both sets of data at once.
475b285192aSMauro Carvalho Chehab 
476b285192aSMauro Carvalho Chehab 	   VBI DMA is a second class citizen compared to MPEG and mixing them together
477b285192aSMauro Carvalho Chehab 	   will confuse the firmware (the end of a VBI DMA is seen as the end of a
478b285192aSMauro Carvalho Chehab 	   MPEG DMA, thus effectively dropping an MPEG frame). So instead we make
479b285192aSMauro Carvalho Chehab 	   sure we only use the MPEG DMA to transfer the VBI DMA if both are in
480b285192aSMauro Carvalho Chehab 	   use. This way no conflicts occur. */
481b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
482b285192aSMauro Carvalho Chehab 	if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size &&
483b285192aSMauro Carvalho Chehab 			s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) {
484b285192aSMauro Carvalho Chehab 		ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused);
485b285192aSMauro Carvalho Chehab 		if (ivtv_use_dma(s_vbi))
486b285192aSMauro Carvalho Chehab 			s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256;
487b285192aSMauro Carvalho Chehab 		for (i = 0; i < s_vbi->sg_pending_size; i++) {
488b285192aSMauro Carvalho Chehab 			s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i];
489b285192aSMauro Carvalho Chehab 		}
490b285192aSMauro Carvalho Chehab 		s_vbi->dma_offset = s_vbi->pending_offset;
491b285192aSMauro Carvalho Chehab 		s_vbi->sg_pending_size = 0;
492b285192aSMauro Carvalho Chehab 		s_vbi->dma_xfer_cnt++;
493b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
494b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name);
495b285192aSMauro Carvalho Chehab 	}
496b285192aSMauro Carvalho Chehab 
497b285192aSMauro Carvalho Chehab 	s->dma_xfer_cnt++;
498b285192aSMauro Carvalho Chehab 	memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
499b285192aSMauro Carvalho Chehab 	s->sg_processing_size = s->sg_pending_size;
500b285192aSMauro Carvalho Chehab 	s->sg_pending_size = 0;
501b285192aSMauro Carvalho Chehab 	s->sg_processed = 0;
502b285192aSMauro Carvalho Chehab 	s->dma_offset = s->pending_offset;
503b285192aSMauro Carvalho Chehab 	s->dma_backup = s->pending_backup;
504b285192aSMauro Carvalho Chehab 	s->dma_pts = s->pending_pts;
505b285192aSMauro Carvalho Chehab 
506b285192aSMauro Carvalho Chehab 	if (ivtv_use_pio(s)) {
507b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags);
508b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
509b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_I_PIO, &itv->i_flags);
510b285192aSMauro Carvalho Chehab 		itv->cur_pio_stream = s->type;
511b285192aSMauro Carvalho Chehab 	}
512b285192aSMauro Carvalho Chehab 	else {
513b285192aSMauro Carvalho Chehab 		itv->dma_retries = 0;
514b285192aSMauro Carvalho Chehab 		ivtv_dma_enc_start_xfer(s);
515b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_I_DMA, &itv->i_flags);
516b285192aSMauro Carvalho Chehab 		itv->cur_dma_stream = s->type;
517b285192aSMauro Carvalho Chehab 	}
518b285192aSMauro Carvalho Chehab }
519b285192aSMauro Carvalho Chehab 
520b285192aSMauro Carvalho Chehab static void ivtv_dma_dec_start(struct ivtv_stream *s)
521b285192aSMauro Carvalho Chehab {
522b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
523b285192aSMauro Carvalho Chehab 
524b285192aSMauro Carvalho Chehab 	if (s->q_predma.bytesused)
525b285192aSMauro Carvalho Chehab 		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
526b285192aSMauro Carvalho Chehab 	s->dma_xfer_cnt++;
527b285192aSMauro Carvalho Chehab 	memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
528b285192aSMauro Carvalho Chehab 	s->sg_processing_size = s->sg_pending_size;
529b285192aSMauro Carvalho Chehab 	s->sg_pending_size = 0;
530b285192aSMauro Carvalho Chehab 	s->sg_processed = 0;
531b285192aSMauro Carvalho Chehab 
532b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name);
533b285192aSMauro Carvalho Chehab 	itv->dma_retries = 0;
534b285192aSMauro Carvalho Chehab 	ivtv_dma_dec_start_xfer(s);
535b285192aSMauro Carvalho Chehab 	set_bit(IVTV_F_I_DMA, &itv->i_flags);
536b285192aSMauro Carvalho Chehab 	itv->cur_dma_stream = s->type;
537b285192aSMauro Carvalho Chehab }
538b285192aSMauro Carvalho Chehab 
539b285192aSMauro Carvalho Chehab static void ivtv_irq_dma_read(struct ivtv *itv)
540b285192aSMauro Carvalho Chehab {
541b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s = NULL;
542b285192aSMauro Carvalho Chehab 	struct ivtv_buffer *buf;
543b285192aSMauro Carvalho Chehab 	int hw_stream_type = 0;
544b285192aSMauro Carvalho Chehab 
545b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("DEC DMA READ\n");
546b285192aSMauro Carvalho Chehab 
547b285192aSMauro Carvalho Chehab 	del_timer(&itv->dma_timer);
548b285192aSMauro Carvalho Chehab 
549b285192aSMauro Carvalho Chehab 	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0)
550b285192aSMauro Carvalho Chehab 		return;
551b285192aSMauro Carvalho Chehab 
552b285192aSMauro Carvalho Chehab 	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
553b285192aSMauro Carvalho Chehab 		s = &itv->streams[itv->cur_dma_stream];
554b285192aSMauro Carvalho Chehab 		ivtv_stream_sync_for_cpu(s);
555b285192aSMauro Carvalho Chehab 
556b285192aSMauro Carvalho Chehab 		if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
557b285192aSMauro Carvalho Chehab 			IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n",
558b285192aSMauro Carvalho Chehab 					read_reg(IVTV_REG_DMASTATUS),
559b285192aSMauro Carvalho Chehab 					s->sg_processed, s->sg_processing_size, itv->dma_retries);
560b285192aSMauro Carvalho Chehab 			write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
561b285192aSMauro Carvalho Chehab 			if (itv->dma_retries == 3) {
562b285192aSMauro Carvalho Chehab 				/* Too many retries, give up on this frame */
563b285192aSMauro Carvalho Chehab 				itv->dma_retries = 0;
564b285192aSMauro Carvalho Chehab 				s->sg_processed = s->sg_processing_size;
565b285192aSMauro Carvalho Chehab 			}
566b285192aSMauro Carvalho Chehab 			else {
567b285192aSMauro Carvalho Chehab 				/* Retry, starting with the first xfer segment.
568b285192aSMauro Carvalho Chehab 				   Just retrying the current segment is not sufficient. */
569b285192aSMauro Carvalho Chehab 				s->sg_processed = 0;
570b285192aSMauro Carvalho Chehab 				itv->dma_retries++;
571b285192aSMauro Carvalho Chehab 			}
572b285192aSMauro Carvalho Chehab 		}
573b285192aSMauro Carvalho Chehab 		if (s->sg_processed < s->sg_processing_size) {
574b285192aSMauro Carvalho Chehab 			/* DMA next buffer */
575b285192aSMauro Carvalho Chehab 			ivtv_dma_dec_start_xfer(s);
576b285192aSMauro Carvalho Chehab 			return;
577b285192aSMauro Carvalho Chehab 		}
578b285192aSMauro Carvalho Chehab 		if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
579b285192aSMauro Carvalho Chehab 			hw_stream_type = 2;
580b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
581b285192aSMauro Carvalho Chehab 
582b285192aSMauro Carvalho Chehab 		/* For some reason must kick the firmware, like PIO mode,
583b285192aSMauro Carvalho Chehab 		   I think this tells the firmware we are done and the size
584b285192aSMauro Carvalho Chehab 		   of the xfer so it can calculate what we need next.
585b285192aSMauro Carvalho Chehab 		   I think we can do this part ourselves but would have to
586b285192aSMauro Carvalho Chehab 		   fully calculate xfer info ourselves and not use interrupts
587b285192aSMauro Carvalho Chehab 		 */
588b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, s->q_dma.bytesused,
589b285192aSMauro Carvalho Chehab 				hw_stream_type);
590b285192aSMauro Carvalho Chehab 
591b285192aSMauro Carvalho Chehab 		/* Free last DMA call */
592b285192aSMauro Carvalho Chehab 		while ((buf = ivtv_dequeue(s, &s->q_dma)) != NULL) {
593b285192aSMauro Carvalho Chehab 			ivtv_buf_sync_for_cpu(s, buf);
594b285192aSMauro Carvalho Chehab 			ivtv_enqueue(s, buf, &s->q_free);
595b285192aSMauro Carvalho Chehab 		}
596b285192aSMauro Carvalho Chehab 		wake_up(&s->waitq);
597b285192aSMauro Carvalho Chehab 	}
598b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
599b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
600b285192aSMauro Carvalho Chehab 	itv->cur_dma_stream = -1;
601b285192aSMauro Carvalho Chehab 	wake_up(&itv->dma_waitq);
602b285192aSMauro Carvalho Chehab }
603b285192aSMauro Carvalho Chehab 
604b285192aSMauro Carvalho Chehab static void ivtv_irq_enc_dma_complete(struct ivtv *itv)
605b285192aSMauro Carvalho Chehab {
606b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
607b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s;
608b285192aSMauro Carvalho Chehab 
609b285192aSMauro Carvalho Chehab 	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data);
610b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream);
611b285192aSMauro Carvalho Chehab 
612b285192aSMauro Carvalho Chehab 	del_timer(&itv->dma_timer);
613b285192aSMauro Carvalho Chehab 
614b285192aSMauro Carvalho Chehab 	if (itv->cur_dma_stream < 0)
615b285192aSMauro Carvalho Chehab 		return;
616b285192aSMauro Carvalho Chehab 
617b285192aSMauro Carvalho Chehab 	s = &itv->streams[itv->cur_dma_stream];
618b285192aSMauro Carvalho Chehab 	ivtv_stream_sync_for_cpu(s);
619b285192aSMauro Carvalho Chehab 
620b285192aSMauro Carvalho Chehab 	if (data[0] & 0x18) {
621b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0],
622b285192aSMauro Carvalho Chehab 			s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries);
623b285192aSMauro Carvalho Chehab 		write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
624b285192aSMauro Carvalho Chehab 		if (itv->dma_retries == 3) {
625b285192aSMauro Carvalho Chehab 			/* Too many retries, give up on this frame */
626b285192aSMauro Carvalho Chehab 			itv->dma_retries = 0;
627b285192aSMauro Carvalho Chehab 			s->sg_processed = s->sg_processing_size;
628b285192aSMauro Carvalho Chehab 		}
629b285192aSMauro Carvalho Chehab 		else {
630b285192aSMauro Carvalho Chehab 			/* Retry, starting with the first xfer segment.
631b285192aSMauro Carvalho Chehab 			   Just retrying the current segment is not sufficient. */
632b285192aSMauro Carvalho Chehab 			s->sg_processed = 0;
633b285192aSMauro Carvalho Chehab 			itv->dma_retries++;
634b285192aSMauro Carvalho Chehab 		}
635b285192aSMauro Carvalho Chehab 	}
636b285192aSMauro Carvalho Chehab 	if (s->sg_processed < s->sg_processing_size) {
637b285192aSMauro Carvalho Chehab 		/* DMA next buffer */
638b285192aSMauro Carvalho Chehab 		ivtv_dma_enc_start_xfer(s);
639b285192aSMauro Carvalho Chehab 		return;
640b285192aSMauro Carvalho Chehab 	}
641b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
642b285192aSMauro Carvalho Chehab 	itv->cur_dma_stream = -1;
643b285192aSMauro Carvalho Chehab 	dma_post(s);
644b285192aSMauro Carvalho Chehab 	if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
645b285192aSMauro Carvalho Chehab 		s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
646b285192aSMauro Carvalho Chehab 		dma_post(s);
647b285192aSMauro Carvalho Chehab 	}
648b285192aSMauro Carvalho Chehab 	s->sg_processing_size = 0;
649b285192aSMauro Carvalho Chehab 	s->sg_processed = 0;
650b285192aSMauro Carvalho Chehab 	wake_up(&itv->dma_waitq);
651b285192aSMauro Carvalho Chehab }
652b285192aSMauro Carvalho Chehab 
653b285192aSMauro Carvalho Chehab static void ivtv_irq_enc_pio_complete(struct ivtv *itv)
654b285192aSMauro Carvalho Chehab {
655b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s;
656b285192aSMauro Carvalho Chehab 
657b285192aSMauro Carvalho Chehab 	if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS) {
658b285192aSMauro Carvalho Chehab 		itv->cur_pio_stream = -1;
659b285192aSMauro Carvalho Chehab 		return;
660b285192aSMauro Carvalho Chehab 	}
661b285192aSMauro Carvalho Chehab 	s = &itv->streams[itv->cur_pio_stream];
662b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name);
663b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_PIO, &itv->i_flags);
664b285192aSMauro Carvalho Chehab 	itv->cur_pio_stream = -1;
665b285192aSMauro Carvalho Chehab 	dma_post(s);
666b285192aSMauro Carvalho Chehab 	if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
667b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 0);
668b285192aSMauro Carvalho Chehab 	else if (s->type == IVTV_ENC_STREAM_TYPE_YUV)
669b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 1);
670b285192aSMauro Carvalho Chehab 	else if (s->type == IVTV_ENC_STREAM_TYPE_PCM)
671b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2);
672b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_PIO, &itv->i_flags);
673b285192aSMauro Carvalho Chehab 	if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
674b285192aSMauro Carvalho Chehab 		s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
675b285192aSMauro Carvalho Chehab 		dma_post(s);
676b285192aSMauro Carvalho Chehab 	}
677b285192aSMauro Carvalho Chehab 	wake_up(&itv->dma_waitq);
678b285192aSMauro Carvalho Chehab }
679b285192aSMauro Carvalho Chehab 
680b285192aSMauro Carvalho Chehab static void ivtv_irq_dma_err(struct ivtv *itv)
681b285192aSMauro Carvalho Chehab {
682b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
683b285192aSMauro Carvalho Chehab 	u32 status;
684b285192aSMauro Carvalho Chehab 
685b285192aSMauro Carvalho Chehab 	del_timer(&itv->dma_timer);
686b285192aSMauro Carvalho Chehab 
687b285192aSMauro Carvalho Chehab 	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data);
688b285192aSMauro Carvalho Chehab 	status = read_reg(IVTV_REG_DMASTATUS);
689b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1],
690b285192aSMauro Carvalho Chehab 				status, itv->cur_dma_stream);
691b285192aSMauro Carvalho Chehab 	/*
692b285192aSMauro Carvalho Chehab 	 * We do *not* write back to the IVTV_REG_DMASTATUS register to
693b285192aSMauro Carvalho Chehab 	 * clear the error status, if either the encoder write (0x02) or
694b285192aSMauro Carvalho Chehab 	 * decoder read (0x01) bus master DMA operation do not indicate
695b285192aSMauro Carvalho Chehab 	 * completed.  We can race with the DMA engine, which may have
696b285192aSMauro Carvalho Chehab 	 * transitioned to completed status *after* we read the register.
697b285192aSMauro Carvalho Chehab 	 * Setting a IVTV_REG_DMASTATUS flag back to "busy" status, after the
698b285192aSMauro Carvalho Chehab 	 * DMA engine has completed, will cause the DMA engine to stop working.
699b285192aSMauro Carvalho Chehab 	 */
700b285192aSMauro Carvalho Chehab 	status &= 0x3;
701b285192aSMauro Carvalho Chehab 	if (status == 0x3)
702b285192aSMauro Carvalho Chehab 		write_reg(status, IVTV_REG_DMASTATUS);
703b285192aSMauro Carvalho Chehab 
704b285192aSMauro Carvalho Chehab 	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) &&
705b285192aSMauro Carvalho Chehab 	    itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) {
706b285192aSMauro Carvalho Chehab 		struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream];
707b285192aSMauro Carvalho Chehab 
708b285192aSMauro Carvalho Chehab 		if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
709b285192aSMauro Carvalho Chehab 			/* retry */
710b285192aSMauro Carvalho Chehab 			/*
711b285192aSMauro Carvalho Chehab 			 * FIXME - handle cases of DMA error similar to
712b285192aSMauro Carvalho Chehab 			 * encoder below, except conditioned on status & 0x1
713b285192aSMauro Carvalho Chehab 			 */
714b285192aSMauro Carvalho Chehab 			ivtv_dma_dec_start(s);
715b285192aSMauro Carvalho Chehab 			return;
716b285192aSMauro Carvalho Chehab 		} else {
717b285192aSMauro Carvalho Chehab 			if ((status & 0x2) == 0) {
718b285192aSMauro Carvalho Chehab 				/*
719b285192aSMauro Carvalho Chehab 				 * CX2341x Bus Master DMA write is ongoing.
720b285192aSMauro Carvalho Chehab 				 * Reset the timer and let it complete.
721b285192aSMauro Carvalho Chehab 				 */
722b285192aSMauro Carvalho Chehab 				itv->dma_timer.expires =
723b285192aSMauro Carvalho Chehab 						jiffies + msecs_to_jiffies(600);
724b285192aSMauro Carvalho Chehab 				add_timer(&itv->dma_timer);
725b285192aSMauro Carvalho Chehab 				return;
726b285192aSMauro Carvalho Chehab 			}
727b285192aSMauro Carvalho Chehab 
728b285192aSMauro Carvalho Chehab 			if (itv->dma_retries < 3) {
729b285192aSMauro Carvalho Chehab 				/*
730b285192aSMauro Carvalho Chehab 				 * CX2341x Bus Master DMA write has ended.
731b285192aSMauro Carvalho Chehab 				 * Retry the write, starting with the first
732b285192aSMauro Carvalho Chehab 				 * xfer segment. Just retrying the current
733b285192aSMauro Carvalho Chehab 				 * segment is not sufficient.
734b285192aSMauro Carvalho Chehab 				 */
735b285192aSMauro Carvalho Chehab 				s->sg_processed = 0;
736b285192aSMauro Carvalho Chehab 				itv->dma_retries++;
737b285192aSMauro Carvalho Chehab 				ivtv_dma_enc_start_xfer(s);
738b285192aSMauro Carvalho Chehab 				return;
739b285192aSMauro Carvalho Chehab 			}
740b285192aSMauro Carvalho Chehab 			/* Too many retries, give up on this one */
741b285192aSMauro Carvalho Chehab 		}
742b285192aSMauro Carvalho Chehab 
743b285192aSMauro Carvalho Chehab 	}
744b285192aSMauro Carvalho Chehab 	if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
745b285192aSMauro Carvalho Chehab 		ivtv_udma_start(itv);
746b285192aSMauro Carvalho Chehab 		return;
747b285192aSMauro Carvalho Chehab 	}
748b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
749b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
750b285192aSMauro Carvalho Chehab 	itv->cur_dma_stream = -1;
751b285192aSMauro Carvalho Chehab 	wake_up(&itv->dma_waitq);
752b285192aSMauro Carvalho Chehab }
753b285192aSMauro Carvalho Chehab 
754b285192aSMauro Carvalho Chehab static void ivtv_irq_enc_start_cap(struct ivtv *itv)
755b285192aSMauro Carvalho Chehab {
756b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
757b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s;
758b285192aSMauro Carvalho Chehab 
759b285192aSMauro Carvalho Chehab 	/* Get DMA destination and size arguments from card */
760b285192aSMauro Carvalho Chehab 	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, 7, data);
761b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
762b285192aSMauro Carvalho Chehab 
763b285192aSMauro Carvalho Chehab 	if (data[0] > 2 || data[1] == 0 || data[2] == 0) {
764b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n",
765b285192aSMauro Carvalho Chehab 				data[0], data[1], data[2]);
766b285192aSMauro Carvalho Chehab 		return;
767b285192aSMauro Carvalho Chehab 	}
768b285192aSMauro Carvalho Chehab 	s = &itv->streams[ivtv_stream_map[data[0]]];
769b285192aSMauro Carvalho Chehab 	if (!stream_enc_dma_append(s, data)) {
770b285192aSMauro Carvalho Chehab 		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
771b285192aSMauro Carvalho Chehab 	}
772b285192aSMauro Carvalho Chehab }
773b285192aSMauro Carvalho Chehab 
774b285192aSMauro Carvalho Chehab static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
775b285192aSMauro Carvalho Chehab {
776b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
777b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s;
778b285192aSMauro Carvalho Chehab 
779b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
780b285192aSMauro Carvalho Chehab 	s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
781b285192aSMauro Carvalho Chehab 
782b285192aSMauro Carvalho Chehab 	if (!stream_enc_dma_append(s, data))
783b285192aSMauro Carvalho Chehab 		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
784b285192aSMauro Carvalho Chehab }
785b285192aSMauro Carvalho Chehab 
786b285192aSMauro Carvalho Chehab static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv)
787b285192aSMauro Carvalho Chehab {
788b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
789b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
790b285192aSMauro Carvalho Chehab 
791b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n");
792b285192aSMauro Carvalho Chehab 	if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) &&
793b285192aSMauro Carvalho Chehab 			!stream_enc_dma_append(s, data)) {
794b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags);
795b285192aSMauro Carvalho Chehab 	}
796b285192aSMauro Carvalho Chehab }
797b285192aSMauro Carvalho Chehab 
798b285192aSMauro Carvalho Chehab static void ivtv_irq_dec_data_req(struct ivtv *itv)
799b285192aSMauro Carvalho Chehab {
800b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
801b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s;
802b285192aSMauro Carvalho Chehab 
803b285192aSMauro Carvalho Chehab 	/* YUV or MPG */
804b285192aSMauro Carvalho Chehab 
805b285192aSMauro Carvalho Chehab 	if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
806b285192aSMauro Carvalho Chehab 		ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data);
807b285192aSMauro Carvalho Chehab 		itv->dma_data_req_size =
808b285192aSMauro Carvalho Chehab 				 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
809b285192aSMauro Carvalho Chehab 		itv->dma_data_req_offset = data[1];
810b285192aSMauro Carvalho Chehab 		if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0)
811b285192aSMauro Carvalho Chehab 			ivtv_yuv_frame_complete(itv);
812b285192aSMauro Carvalho Chehab 		s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
813b285192aSMauro Carvalho Chehab 	}
814b285192aSMauro Carvalho Chehab 	else {
815b285192aSMauro Carvalho Chehab 		ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 3, data);
816b285192aSMauro Carvalho Chehab 		itv->dma_data_req_size = min_t(u32, data[2], 0x10000);
817b285192aSMauro Carvalho Chehab 		itv->dma_data_req_offset = data[1];
818b285192aSMauro Carvalho Chehab 		s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
819b285192aSMauro Carvalho Chehab 	}
820b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
821b285192aSMauro Carvalho Chehab 		       itv->dma_data_req_offset, itv->dma_data_req_size);
822b285192aSMauro Carvalho Chehab 	if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) {
823b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
824b285192aSMauro Carvalho Chehab 	}
825b285192aSMauro Carvalho Chehab 	else {
826b285192aSMauro Carvalho Chehab 		if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
827b285192aSMauro Carvalho Chehab 			ivtv_yuv_setup_stream_frame(itv);
828b285192aSMauro Carvalho Chehab 		clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
829b285192aSMauro Carvalho Chehab 		ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
830b285192aSMauro Carvalho Chehab 		ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0);
831b285192aSMauro Carvalho Chehab 	}
832b285192aSMauro Carvalho Chehab }
833b285192aSMauro Carvalho Chehab 
834b285192aSMauro Carvalho Chehab static void ivtv_irq_vsync(struct ivtv *itv)
835b285192aSMauro Carvalho Chehab {
836b285192aSMauro Carvalho Chehab 	/* The vsync interrupt is unusual in that it won't clear until
837b285192aSMauro Carvalho Chehab 	 * the end of the first line for the current field, at which
838b285192aSMauro Carvalho Chehab 	 * point it clears itself. This can result in repeated vsync
839b285192aSMauro Carvalho Chehab 	 * interrupts, or a missed vsync. Read some of the registers
840b285192aSMauro Carvalho Chehab 	 * to determine the line being displayed and ensure we handle
841b285192aSMauro Carvalho Chehab 	 * one vsync per frame.
842b285192aSMauro Carvalho Chehab 	 */
843b285192aSMauro Carvalho Chehab 	unsigned int frame = read_reg(IVTV_REG_DEC_LINE_FIELD) & 1;
844b285192aSMauro Carvalho Chehab 	struct yuv_playback_info *yi = &itv->yuv_info;
845b285192aSMauro Carvalho Chehab 	int last_dma_frame = atomic_read(&yi->next_dma_frame);
846b285192aSMauro Carvalho Chehab 	struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame];
847b285192aSMauro Carvalho Chehab 
848b285192aSMauro Carvalho Chehab 	if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
849b285192aSMauro Carvalho Chehab 
850b285192aSMauro Carvalho Chehab 	if (((frame ^ f->sync_field) == 0 &&
851b285192aSMauro Carvalho Chehab 		((itv->last_vsync_field & 1) ^ f->sync_field)) ||
852b285192aSMauro Carvalho Chehab 			(frame != (itv->last_vsync_field & 1) && !f->interlaced)) {
853b285192aSMauro Carvalho Chehab 		int next_dma_frame = last_dma_frame;
854b285192aSMauro Carvalho Chehab 
855b285192aSMauro Carvalho Chehab 		if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) {
856b285192aSMauro Carvalho Chehab 			if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) {
857b285192aSMauro Carvalho Chehab 				write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
858b285192aSMauro Carvalho Chehab 				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
859b285192aSMauro Carvalho Chehab 				write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
860b285192aSMauro Carvalho Chehab 				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
861b285192aSMauro Carvalho Chehab 				next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS;
862b285192aSMauro Carvalho Chehab 				atomic_set(&yi->next_dma_frame, next_dma_frame);
863b285192aSMauro Carvalho Chehab 				yi->fields_lapsed = -1;
864b285192aSMauro Carvalho Chehab 				yi->running = 1;
865b285192aSMauro Carvalho Chehab 			}
866b285192aSMauro Carvalho Chehab 		}
867b285192aSMauro Carvalho Chehab 	}
868b285192aSMauro Carvalho Chehab 	if (frame != (itv->last_vsync_field & 1)) {
869b285192aSMauro Carvalho Chehab 		static const struct v4l2_event evtop = {
870b285192aSMauro Carvalho Chehab 			.type = V4L2_EVENT_VSYNC,
871b285192aSMauro Carvalho Chehab 			.u.vsync.field = V4L2_FIELD_TOP,
872b285192aSMauro Carvalho Chehab 		};
873b285192aSMauro Carvalho Chehab 		static const struct v4l2_event evbottom = {
874b285192aSMauro Carvalho Chehab 			.type = V4L2_EVENT_VSYNC,
875b285192aSMauro Carvalho Chehab 			.u.vsync.field = V4L2_FIELD_BOTTOM,
876b285192aSMauro Carvalho Chehab 		};
877b285192aSMauro Carvalho Chehab 		struct ivtv_stream *s = ivtv_get_output_stream(itv);
878b285192aSMauro Carvalho Chehab 
879b285192aSMauro Carvalho Chehab 		itv->last_vsync_field += 1;
880b285192aSMauro Carvalho Chehab 		if (frame == 0) {
881b285192aSMauro Carvalho Chehab 			clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
882b285192aSMauro Carvalho Chehab 			clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags);
883b285192aSMauro Carvalho Chehab 		}
884b285192aSMauro Carvalho Chehab 		else {
885b285192aSMauro Carvalho Chehab 			set_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags);
886b285192aSMauro Carvalho Chehab 		}
887b285192aSMauro Carvalho Chehab 		if (test_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags)) {
888b285192aSMauro Carvalho Chehab 			set_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags);
889b285192aSMauro Carvalho Chehab 			wake_up(&itv->event_waitq);
890b285192aSMauro Carvalho Chehab 			if (s)
891b285192aSMauro Carvalho Chehab 				wake_up(&s->waitq);
892b285192aSMauro Carvalho Chehab 		}
893b285192aSMauro Carvalho Chehab 		if (s && s->vdev)
894b285192aSMauro Carvalho Chehab 			v4l2_event_queue(s->vdev, frame ? &evtop : &evbottom);
895b285192aSMauro Carvalho Chehab 		wake_up(&itv->vsync_waitq);
896b285192aSMauro Carvalho Chehab 
897b285192aSMauro Carvalho Chehab 		/* Send VBI to saa7127 */
898b285192aSMauro Carvalho Chehab 		if (frame && (itv->output_mode == OUT_PASSTHROUGH ||
899b285192aSMauro Carvalho Chehab 			test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) ||
900b285192aSMauro Carvalho Chehab 			test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) ||
901b285192aSMauro Carvalho Chehab 			test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) {
902b285192aSMauro Carvalho Chehab 			set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags);
903b285192aSMauro Carvalho Chehab 			set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
904b285192aSMauro Carvalho Chehab 		}
905b285192aSMauro Carvalho Chehab 
906b285192aSMauro Carvalho Chehab 		/* Check if we need to update the yuv registers */
907b285192aSMauro Carvalho Chehab 		if (yi->running && (yi->yuv_forced_update || f->update)) {
908b285192aSMauro Carvalho Chehab 			if (!f->update) {
909b285192aSMauro Carvalho Chehab 				last_dma_frame =
910b285192aSMauro Carvalho Chehab 					(u8)(atomic_read(&yi->next_dma_frame) -
911b285192aSMauro Carvalho Chehab 						 1) % IVTV_YUV_BUFFERS;
912b285192aSMauro Carvalho Chehab 				f = &yi->new_frame_info[last_dma_frame];
913b285192aSMauro Carvalho Chehab 			}
914b285192aSMauro Carvalho Chehab 
915b285192aSMauro Carvalho Chehab 			if (f->src_w) {
916b285192aSMauro Carvalho Chehab 				yi->update_frame = last_dma_frame;
917b285192aSMauro Carvalho Chehab 				f->update = 0;
918b285192aSMauro Carvalho Chehab 				yi->yuv_forced_update = 0;
919b285192aSMauro Carvalho Chehab 				set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags);
920b285192aSMauro Carvalho Chehab 				set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
921b285192aSMauro Carvalho Chehab 			}
922b285192aSMauro Carvalho Chehab 		}
923b285192aSMauro Carvalho Chehab 
924b285192aSMauro Carvalho Chehab 		yi->fields_lapsed++;
925b285192aSMauro Carvalho Chehab 	}
926b285192aSMauro Carvalho Chehab }
927b285192aSMauro Carvalho Chehab 
928b285192aSMauro 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)
929b285192aSMauro Carvalho Chehab 
930b285192aSMauro Carvalho Chehab irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
931b285192aSMauro Carvalho Chehab {
932b285192aSMauro Carvalho Chehab 	struct ivtv *itv = (struct ivtv *)dev_id;
933b285192aSMauro Carvalho Chehab 	u32 combo;
934b285192aSMauro Carvalho Chehab 	u32 stat;
935b285192aSMauro Carvalho Chehab 	int i;
936b285192aSMauro Carvalho Chehab 	u8 vsync_force = 0;
937b285192aSMauro Carvalho Chehab 
938b285192aSMauro Carvalho Chehab 	spin_lock(&itv->dma_reg_lock);
939b285192aSMauro Carvalho Chehab 	/* get contents of irq status register */
940b285192aSMauro Carvalho Chehab 	stat = read_reg(IVTV_REG_IRQSTATUS);
941b285192aSMauro Carvalho Chehab 
942b285192aSMauro Carvalho Chehab 	combo = ~itv->irqmask & stat;
943b285192aSMauro Carvalho Chehab 
944b285192aSMauro Carvalho Chehab 	/* Clear out IRQ */
945b285192aSMauro Carvalho Chehab 	if (combo) write_reg(combo, IVTV_REG_IRQSTATUS);
946b285192aSMauro Carvalho Chehab 
947b285192aSMauro Carvalho Chehab 	if (0 == combo) {
948b285192aSMauro Carvalho Chehab 		/* The vsync interrupt is unusual and clears itself. If we
949b285192aSMauro Carvalho Chehab 		 * took too long, we may have missed it. Do some checks
950b285192aSMauro Carvalho Chehab 		 */
951b285192aSMauro Carvalho Chehab 		if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
952b285192aSMauro Carvalho Chehab 			/* vsync is enabled, see if we're in a new field */
953b285192aSMauro Carvalho Chehab 			if ((itv->last_vsync_field & 1) !=
954b285192aSMauro Carvalho Chehab 			    (read_reg(IVTV_REG_DEC_LINE_FIELD) & 1)) {
955b285192aSMauro Carvalho Chehab 				/* New field, looks like we missed it */
956b285192aSMauro Carvalho Chehab 				IVTV_DEBUG_YUV("VSync interrupt missed %d\n",
957b285192aSMauro Carvalho Chehab 				       read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16);
958b285192aSMauro Carvalho Chehab 				vsync_force = 1;
959b285192aSMauro Carvalho Chehab 			}
960b285192aSMauro Carvalho Chehab 		}
961b285192aSMauro Carvalho Chehab 
962b285192aSMauro Carvalho Chehab 		if (!vsync_force) {
963b285192aSMauro Carvalho Chehab 			/* No Vsync expected, wasn't for us */
964b285192aSMauro Carvalho Chehab 			spin_unlock(&itv->dma_reg_lock);
965b285192aSMauro Carvalho Chehab 			return IRQ_NONE;
966b285192aSMauro Carvalho Chehab 		}
967b285192aSMauro Carvalho Chehab 	}
968b285192aSMauro Carvalho Chehab 
969b285192aSMauro Carvalho Chehab 	/* Exclude interrupts noted below from the output, otherwise the log is flooded with
970b285192aSMauro Carvalho Chehab 	   these messages */
971b285192aSMauro Carvalho Chehab 	if (combo & ~0xff6d0400)
972b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
973b285192aSMauro Carvalho Chehab 
974b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) {
975b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n");
976b285192aSMauro Carvalho Chehab 	}
977b285192aSMauro Carvalho Chehab 
978b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_DMA_READ) {
979b285192aSMauro Carvalho Chehab 		ivtv_irq_dma_read(itv);
980b285192aSMauro Carvalho Chehab 	}
981b285192aSMauro Carvalho Chehab 
982b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) {
983b285192aSMauro Carvalho Chehab 		ivtv_irq_enc_dma_complete(itv);
984b285192aSMauro Carvalho Chehab 	}
985b285192aSMauro Carvalho Chehab 
986b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_ENC_PIO_COMPLETE) {
987b285192aSMauro Carvalho Chehab 		ivtv_irq_enc_pio_complete(itv);
988b285192aSMauro Carvalho Chehab 	}
989b285192aSMauro Carvalho Chehab 
990b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_DMA_ERR) {
991b285192aSMauro Carvalho Chehab 		ivtv_irq_dma_err(itv);
992b285192aSMauro Carvalho Chehab 	}
993b285192aSMauro Carvalho Chehab 
994b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_ENC_START_CAP) {
995b285192aSMauro Carvalho Chehab 		ivtv_irq_enc_start_cap(itv);
996b285192aSMauro Carvalho Chehab 	}
997b285192aSMauro Carvalho Chehab 
998b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_ENC_VBI_CAP) {
999b285192aSMauro Carvalho Chehab 		ivtv_irq_enc_vbi_cap(itv);
1000b285192aSMauro Carvalho Chehab 	}
1001b285192aSMauro Carvalho Chehab 
1002b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) {
1003b285192aSMauro Carvalho Chehab 		ivtv_irq_dec_vbi_reinsert(itv);
1004b285192aSMauro Carvalho Chehab 	}
1005b285192aSMauro Carvalho Chehab 
1006b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_ENC_EOS) {
1007b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_IRQ("ENC EOS\n");
1008b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_I_EOS, &itv->i_flags);
1009b285192aSMauro Carvalho Chehab 		wake_up(&itv->eos_waitq);
1010b285192aSMauro Carvalho Chehab 	}
1011b285192aSMauro Carvalho Chehab 
1012b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_DEC_DATA_REQ) {
1013b285192aSMauro Carvalho Chehab 		ivtv_irq_dec_data_req(itv);
1014b285192aSMauro Carvalho Chehab 	}
1015b285192aSMauro Carvalho Chehab 
1016b285192aSMauro Carvalho Chehab 	/* Decoder Vertical Sync - We can't rely on 'combo', so check if vsync enabled */
1017b285192aSMauro Carvalho Chehab 	if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
1018b285192aSMauro Carvalho Chehab 		ivtv_irq_vsync(itv);
1019b285192aSMauro Carvalho Chehab 	}
1020b285192aSMauro Carvalho Chehab 
1021b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_ENC_VIM_RST) {
1022b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_IRQ("VIM RST\n");
1023b285192aSMauro Carvalho Chehab 		/*ivtv_vapi(itv, CX2341X_ENC_REFRESH_INPUT, 0); */
1024b285192aSMauro Carvalho Chehab 	}
1025b285192aSMauro Carvalho Chehab 
1026b285192aSMauro Carvalho Chehab 	if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) {
1027b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_INFO("Stereo mode changed\n");
1028b285192aSMauro Carvalho Chehab 	}
1029b285192aSMauro Carvalho Chehab 
1030b285192aSMauro Carvalho Chehab 	if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
1031b285192aSMauro Carvalho Chehab 		itv->irq_rr_idx++;
1032b285192aSMauro Carvalho Chehab 		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
1033b285192aSMauro Carvalho Chehab 			int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
1034b285192aSMauro Carvalho Chehab 			struct ivtv_stream *s = &itv->streams[idx];
1035b285192aSMauro Carvalho Chehab 
1036b285192aSMauro Carvalho Chehab 			if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags))
1037b285192aSMauro Carvalho Chehab 				continue;
1038b285192aSMauro Carvalho Chehab 			if (s->type >= IVTV_DEC_STREAM_TYPE_MPG)
1039b285192aSMauro Carvalho Chehab 				ivtv_dma_dec_start(s);
1040b285192aSMauro Carvalho Chehab 			else
1041b285192aSMauro Carvalho Chehab 				ivtv_dma_enc_start(s);
1042b285192aSMauro Carvalho Chehab 			break;
1043b285192aSMauro Carvalho Chehab 		}
1044b285192aSMauro Carvalho Chehab 
1045b285192aSMauro Carvalho Chehab 		if (i == IVTV_MAX_STREAMS &&
1046b285192aSMauro Carvalho Chehab 		    test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
1047b285192aSMauro Carvalho Chehab 			ivtv_udma_start(itv);
1048b285192aSMauro Carvalho Chehab 	}
1049b285192aSMauro Carvalho Chehab 
1050b285192aSMauro Carvalho Chehab 	if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) {
1051b285192aSMauro Carvalho Chehab 		itv->irq_rr_idx++;
1052b285192aSMauro Carvalho Chehab 		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
1053b285192aSMauro Carvalho Chehab 			int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
1054b285192aSMauro Carvalho Chehab 			struct ivtv_stream *s = &itv->streams[idx];
1055b285192aSMauro Carvalho Chehab 
1056b285192aSMauro Carvalho Chehab 			if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags))
1057b285192aSMauro Carvalho Chehab 				continue;
1058b285192aSMauro Carvalho Chehab 			if (s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type < IVTV_DEC_STREAM_TYPE_MPG)
1059b285192aSMauro Carvalho Chehab 				ivtv_dma_enc_start(s);
1060b285192aSMauro Carvalho Chehab 			break;
1061b285192aSMauro Carvalho Chehab 		}
1062b285192aSMauro Carvalho Chehab 	}
1063b285192aSMauro Carvalho Chehab 
1064b285192aSMauro Carvalho Chehab 	if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) {
1065b285192aSMauro Carvalho Chehab 		queue_kthread_work(&itv->irq_worker, &itv->irq_work);
1066b285192aSMauro Carvalho Chehab 	}
1067b285192aSMauro Carvalho Chehab 
1068b285192aSMauro Carvalho Chehab 	spin_unlock(&itv->dma_reg_lock);
1069b285192aSMauro Carvalho Chehab 
1070b285192aSMauro Carvalho Chehab 	/* If we've just handled a 'forced' vsync, it's safest to say it
1071b285192aSMauro Carvalho Chehab 	 * wasn't ours. Another device may have triggered it at just
1072b285192aSMauro Carvalho Chehab 	 * the right time.
1073b285192aSMauro Carvalho Chehab 	 */
1074b285192aSMauro Carvalho Chehab 	return vsync_force ? IRQ_NONE : IRQ_HANDLED;
1075b285192aSMauro Carvalho Chehab }
1076b285192aSMauro Carvalho Chehab 
1077b285192aSMauro Carvalho Chehab void ivtv_unfinished_dma(unsigned long arg)
1078b285192aSMauro Carvalho Chehab {
1079b285192aSMauro Carvalho Chehab 	struct ivtv *itv = (struct ivtv *)arg;
1080b285192aSMauro Carvalho Chehab 
1081b285192aSMauro Carvalho Chehab 	if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
1082b285192aSMauro Carvalho Chehab 		return;
1083b285192aSMauro Carvalho Chehab 	IVTV_ERR("DMA TIMEOUT %08x %d\n", read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
1084b285192aSMauro Carvalho Chehab 
1085b285192aSMauro Carvalho Chehab 	write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
1086b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
1087b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
1088b285192aSMauro Carvalho Chehab 	itv->cur_dma_stream = -1;
1089b285192aSMauro Carvalho Chehab 	wake_up(&itv->dma_waitq);
1090b285192aSMauro Carvalho Chehab }
1091