162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* interrupt handling
362306a36Sopenharmony_ci    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
462306a36Sopenharmony_ci    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
562306a36Sopenharmony_ci    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "ivtv-driver.h"
1062306a36Sopenharmony_ci#include "ivtv-queue.h"
1162306a36Sopenharmony_ci#include "ivtv-udma.h"
1262306a36Sopenharmony_ci#include "ivtv-irq.h"
1362306a36Sopenharmony_ci#include "ivtv-mailbox.h"
1462306a36Sopenharmony_ci#include "ivtv-vbi.h"
1562306a36Sopenharmony_ci#include "ivtv-yuv.h"
1662306a36Sopenharmony_ci#include <media/v4l2-event.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define DMA_MAGIC_COOKIE 0x000001fe
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic void ivtv_dma_dec_start(struct ivtv_stream *s);
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic const int ivtv_stream_map[] = {
2362306a36Sopenharmony_ci	IVTV_ENC_STREAM_TYPE_MPG,
2462306a36Sopenharmony_ci	IVTV_ENC_STREAM_TYPE_YUV,
2562306a36Sopenharmony_ci	IVTV_ENC_STREAM_TYPE_PCM,
2662306a36Sopenharmony_ci	IVTV_ENC_STREAM_TYPE_VBI,
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic void ivtv_pcm_work_handler(struct ivtv *itv)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
3262306a36Sopenharmony_ci	struct ivtv_buffer *buf;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	/* Pass the PCM data to ivtv-alsa */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	while (1) {
3762306a36Sopenharmony_ci		/*
3862306a36Sopenharmony_ci		 * Users should not be using both the ALSA and V4L2 PCM audio
3962306a36Sopenharmony_ci		 * capture interfaces at the same time.  If the user is doing
4062306a36Sopenharmony_ci		 * this, there maybe a buffer in q_io to grab, use, and put
4162306a36Sopenharmony_ci		 * back in rotation.
4262306a36Sopenharmony_ci		 */
4362306a36Sopenharmony_ci		buf = ivtv_dequeue(s, &s->q_io);
4462306a36Sopenharmony_ci		if (buf == NULL)
4562306a36Sopenharmony_ci			buf = ivtv_dequeue(s, &s->q_full);
4662306a36Sopenharmony_ci		if (buf == NULL)
4762306a36Sopenharmony_ci			break;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci		if (buf->readpos < buf->bytesused)
5062306a36Sopenharmony_ci			itv->pcm_announce_callback(itv->alsa,
5162306a36Sopenharmony_ci				(u8 *)(buf->buf + buf->readpos),
5262306a36Sopenharmony_ci				(size_t)(buf->bytesused - buf->readpos));
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci		ivtv_enqueue(s, buf, &s->q_free);
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic void ivtv_pio_work_handler(struct ivtv *itv)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream];
6162306a36Sopenharmony_ci	struct ivtv_buffer *buf;
6262306a36Sopenharmony_ci	int i = 0;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
6562306a36Sopenharmony_ci	if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
6662306a36Sopenharmony_ci			s->vdev.v4l2_dev == NULL || !ivtv_use_pio(s)) {
6762306a36Sopenharmony_ci		itv->cur_pio_stream = -1;
6862306a36Sopenharmony_ci		/* trigger PIO complete user interrupt */
6962306a36Sopenharmony_ci		write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
7062306a36Sopenharmony_ci		return;
7162306a36Sopenharmony_ci	}
7262306a36Sopenharmony_ci	IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name);
7362306a36Sopenharmony_ci	list_for_each_entry(buf, &s->q_dma.list, list) {
7462306a36Sopenharmony_ci		u32 size = s->sg_processing[i].size & 0x3ffff;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci		/* Copy the data from the card to the buffer */
7762306a36Sopenharmony_ci		if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
7862306a36Sopenharmony_ci			memcpy_fromio(buf->buf, itv->dec_mem + s->sg_processing[i].src - IVTV_DECODER_OFFSET, size);
7962306a36Sopenharmony_ci		}
8062306a36Sopenharmony_ci		else {
8162306a36Sopenharmony_ci			memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size);
8262306a36Sopenharmony_ci		}
8362306a36Sopenharmony_ci		i++;
8462306a36Sopenharmony_ci		if (i == s->sg_processing_size)
8562306a36Sopenharmony_ci			break;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci	write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_civoid ivtv_irq_work_handler(struct kthread_work *work)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct ivtv *itv = container_of(work, struct ivtv, irq_work);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags))
9562306a36Sopenharmony_ci		ivtv_pio_work_handler(itv);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags))
9862306a36Sopenharmony_ci		ivtv_vbi_work_handler(itv);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags))
10162306a36Sopenharmony_ci		ivtv_yuv_work_handler(itv);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PCM, &itv->i_flags))
10462306a36Sopenharmony_ci		ivtv_pcm_work_handler(itv);
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci/* Determine the required DMA size, setup enough buffers in the predma queue and
10862306a36Sopenharmony_ci   actually copy the data from the card to the buffers in case a PIO transfer is
10962306a36Sopenharmony_ci   required for this stream.
11062306a36Sopenharmony_ci */
11162306a36Sopenharmony_cistatic int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MAX_DATA])
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	struct ivtv *itv = s->itv;
11462306a36Sopenharmony_ci	struct ivtv_buffer *buf;
11562306a36Sopenharmony_ci	u32 bytes_needed = 0;
11662306a36Sopenharmony_ci	u32 offset, size;
11762306a36Sopenharmony_ci	u32 UVoffset = 0, UVsize = 0;
11862306a36Sopenharmony_ci	int skip_bufs = s->q_predma.buffers;
11962306a36Sopenharmony_ci	int idx = s->sg_pending_size;
12062306a36Sopenharmony_ci	int rc;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/* sanity checks */
12362306a36Sopenharmony_ci	if (s->vdev.v4l2_dev == NULL) {
12462306a36Sopenharmony_ci		IVTV_DEBUG_WARN("Stream %s not started\n", s->name);
12562306a36Sopenharmony_ci		return -1;
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci	if (!test_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
12862306a36Sopenharmony_ci		IVTV_DEBUG_WARN("Stream %s not open\n", s->name);
12962306a36Sopenharmony_ci		return -1;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* determine offset, size and PTS for the various streams */
13362306a36Sopenharmony_ci	switch (s->type) {
13462306a36Sopenharmony_ci		case IVTV_ENC_STREAM_TYPE_MPG:
13562306a36Sopenharmony_ci			offset = data[1];
13662306a36Sopenharmony_ci			size = data[2];
13762306a36Sopenharmony_ci			s->pending_pts = 0;
13862306a36Sopenharmony_ci			break;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci		case IVTV_ENC_STREAM_TYPE_YUV:
14162306a36Sopenharmony_ci			offset = data[1];
14262306a36Sopenharmony_ci			size = data[2];
14362306a36Sopenharmony_ci			UVoffset = data[3];
14462306a36Sopenharmony_ci			UVsize = data[4];
14562306a36Sopenharmony_ci			s->pending_pts = ((u64) data[5] << 32) | data[6];
14662306a36Sopenharmony_ci			break;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci		case IVTV_ENC_STREAM_TYPE_PCM:
14962306a36Sopenharmony_ci			offset = data[1] + 12;
15062306a36Sopenharmony_ci			size = data[2] - 12;
15162306a36Sopenharmony_ci			s->pending_pts = read_dec(offset - 8) |
15262306a36Sopenharmony_ci				((u64)(read_dec(offset - 12)) << 32);
15362306a36Sopenharmony_ci			if (itv->has_cx23415)
15462306a36Sopenharmony_ci				offset += IVTV_DECODER_OFFSET;
15562306a36Sopenharmony_ci			break;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		case IVTV_ENC_STREAM_TYPE_VBI:
15862306a36Sopenharmony_ci			size = itv->vbi.enc_size * itv->vbi.fpi;
15962306a36Sopenharmony_ci			offset = read_enc(itv->vbi.enc_start - 4) + 12;
16062306a36Sopenharmony_ci			if (offset == 12) {
16162306a36Sopenharmony_ci				IVTV_DEBUG_INFO("VBI offset == 0\n");
16262306a36Sopenharmony_ci				return -1;
16362306a36Sopenharmony_ci			}
16462306a36Sopenharmony_ci			s->pending_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32);
16562306a36Sopenharmony_ci			break;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci		case IVTV_DEC_STREAM_TYPE_VBI:
16862306a36Sopenharmony_ci			size = read_dec(itv->vbi.dec_start + 4) + 8;
16962306a36Sopenharmony_ci			offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start;
17062306a36Sopenharmony_ci			s->pending_pts = 0;
17162306a36Sopenharmony_ci			offset += IVTV_DECODER_OFFSET;
17262306a36Sopenharmony_ci			break;
17362306a36Sopenharmony_ci		default:
17462306a36Sopenharmony_ci			/* shouldn't happen */
17562306a36Sopenharmony_ci			return -1;
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* if this is the start of the DMA then fill in the magic cookie */
17962306a36Sopenharmony_ci	if (s->sg_pending_size == 0 && ivtv_use_dma(s)) {
18062306a36Sopenharmony_ci		if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
18162306a36Sopenharmony_ci		    s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
18262306a36Sopenharmony_ci			s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET);
18362306a36Sopenharmony_ci			write_dec_sync(DMA_MAGIC_COOKIE, offset - IVTV_DECODER_OFFSET);
18462306a36Sopenharmony_ci		}
18562306a36Sopenharmony_ci		else {
18662306a36Sopenharmony_ci			s->pending_backup = read_enc(offset);
18762306a36Sopenharmony_ci			write_enc_sync(DMA_MAGIC_COOKIE, offset);
18862306a36Sopenharmony_ci		}
18962306a36Sopenharmony_ci		s->pending_offset = offset;
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	bytes_needed = size;
19362306a36Sopenharmony_ci	if (s->type == IVTV_ENC_STREAM_TYPE_YUV) {
19462306a36Sopenharmony_ci		/* The size for the Y samples needs to be rounded upwards to a
19562306a36Sopenharmony_ci		   multiple of the buf_size. The UV samples then start in the
19662306a36Sopenharmony_ci		   next buffer. */
19762306a36Sopenharmony_ci		bytes_needed = s->buf_size * ((bytes_needed + s->buf_size - 1) / s->buf_size);
19862306a36Sopenharmony_ci		bytes_needed += UVsize;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
20262306a36Sopenharmony_ci		ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed);
20562306a36Sopenharmony_ci	if (rc < 0) { /* Insufficient buffers */
20662306a36Sopenharmony_ci		IVTV_DEBUG_WARN("Cannot obtain %d bytes for %s data transfer\n",
20762306a36Sopenharmony_ci				bytes_needed, s->name);
20862306a36Sopenharmony_ci		return -1;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci	if (rc && !s->buffers_stolen && test_bit(IVTV_F_S_APPL_IO, &s->s_flags)) {
21162306a36Sopenharmony_ci		IVTV_WARN("All %s stream buffers are full. Dropping data.\n", s->name);
21262306a36Sopenharmony_ci		IVTV_WARN("Cause: the application is not reading fast enough.\n");
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci	s->buffers_stolen = rc;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	/* got the buffers, now fill in sg_pending */
21762306a36Sopenharmony_ci	buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
21862306a36Sopenharmony_ci	memset(buf->buf, 0, 128);
21962306a36Sopenharmony_ci	list_for_each_entry(buf, &s->q_predma.list, list) {
22062306a36Sopenharmony_ci		if (skip_bufs-- > 0)
22162306a36Sopenharmony_ci			continue;
22262306a36Sopenharmony_ci		s->sg_pending[idx].dst = buf->dma_handle;
22362306a36Sopenharmony_ci		s->sg_pending[idx].src = offset;
22462306a36Sopenharmony_ci		s->sg_pending[idx].size = s->buf_size;
22562306a36Sopenharmony_ci		buf->bytesused = min(size, s->buf_size);
22662306a36Sopenharmony_ci		buf->dma_xfer_cnt = s->dma_xfer_cnt;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci		s->q_predma.bytesused += buf->bytesused;
22962306a36Sopenharmony_ci		size -= buf->bytesused;
23062306a36Sopenharmony_ci		offset += s->buf_size;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci		/* Sync SG buffers */
23362306a36Sopenharmony_ci		ivtv_buf_sync_for_device(s, buf);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci		if (size == 0) {	/* YUV */
23662306a36Sopenharmony_ci			/* process the UV section */
23762306a36Sopenharmony_ci			offset = UVoffset;
23862306a36Sopenharmony_ci			size = UVsize;
23962306a36Sopenharmony_ci		}
24062306a36Sopenharmony_ci		idx++;
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci	s->sg_pending_size = idx;
24362306a36Sopenharmony_ci	return 0;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic void dma_post(struct ivtv_stream *s)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct ivtv *itv = s->itv;
24962306a36Sopenharmony_ci	struct ivtv_buffer *buf = NULL;
25062306a36Sopenharmony_ci	struct list_head *p;
25162306a36Sopenharmony_ci	u32 offset;
25262306a36Sopenharmony_ci	__le32 *u32buf;
25362306a36Sopenharmony_ci	int x = 0;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
25662306a36Sopenharmony_ci			s->name, s->dma_offset);
25762306a36Sopenharmony_ci	list_for_each(p, &s->q_dma.list) {
25862306a36Sopenharmony_ci		buf = list_entry(p, struct ivtv_buffer, list);
25962306a36Sopenharmony_ci		u32buf = (__le32 *)buf->buf;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		/* Sync Buffer */
26262306a36Sopenharmony_ci		ivtv_buf_sync_for_cpu(s, buf);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		if (x == 0 && ivtv_use_dma(s)) {
26562306a36Sopenharmony_ci			offset = s->dma_last_offset;
26662306a36Sopenharmony_ci			if (le32_to_cpu(u32buf[offset / 4]) != DMA_MAGIC_COOKIE)
26762306a36Sopenharmony_ci			{
26862306a36Sopenharmony_ci				for (offset = 0; offset < 64; offset++)
26962306a36Sopenharmony_ci					if (le32_to_cpu(u32buf[offset]) == DMA_MAGIC_COOKIE)
27062306a36Sopenharmony_ci						break;
27162306a36Sopenharmony_ci				offset *= 4;
27262306a36Sopenharmony_ci				if (offset == 256) {
27362306a36Sopenharmony_ci					IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name);
27462306a36Sopenharmony_ci					offset = s->dma_last_offset;
27562306a36Sopenharmony_ci				}
27662306a36Sopenharmony_ci				if (s->dma_last_offset != offset)
27762306a36Sopenharmony_ci					IVTV_DEBUG_WARN("%s: offset %d -> %d\n", s->name, s->dma_last_offset, offset);
27862306a36Sopenharmony_ci				s->dma_last_offset = offset;
27962306a36Sopenharmony_ci			}
28062306a36Sopenharmony_ci			if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
28162306a36Sopenharmony_ci						s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
28262306a36Sopenharmony_ci				write_dec_sync(0, s->dma_offset - IVTV_DECODER_OFFSET);
28362306a36Sopenharmony_ci			}
28462306a36Sopenharmony_ci			else {
28562306a36Sopenharmony_ci				write_enc_sync(0, s->dma_offset);
28662306a36Sopenharmony_ci			}
28762306a36Sopenharmony_ci			if (offset) {
28862306a36Sopenharmony_ci				buf->bytesused -= offset;
28962306a36Sopenharmony_ci				memcpy(buf->buf, buf->buf + offset, buf->bytesused + offset);
29062306a36Sopenharmony_ci			}
29162306a36Sopenharmony_ci			*u32buf = cpu_to_le32(s->dma_backup);
29262306a36Sopenharmony_ci		}
29362306a36Sopenharmony_ci		x++;
29462306a36Sopenharmony_ci		/* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */
29562306a36Sopenharmony_ci		if (s->type == IVTV_ENC_STREAM_TYPE_MPG ||
29662306a36Sopenharmony_ci		    s->type == IVTV_ENC_STREAM_TYPE_VBI)
29762306a36Sopenharmony_ci			buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP;
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci	if (buf)
30062306a36Sopenharmony_ci		buf->bytesused += s->dma_last_offset;
30162306a36Sopenharmony_ci	if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) {
30262306a36Sopenharmony_ci		list_for_each_entry(buf, &s->q_dma.list, list) {
30362306a36Sopenharmony_ci			/* Parse and Groom VBI Data */
30462306a36Sopenharmony_ci			s->q_dma.bytesused -= buf->bytesused;
30562306a36Sopenharmony_ci			ivtv_process_vbi_data(itv, buf, 0, s->type);
30662306a36Sopenharmony_ci			s->q_dma.bytesused += buf->bytesused;
30762306a36Sopenharmony_ci		}
30862306a36Sopenharmony_ci		if (s->fh == NULL) {
30962306a36Sopenharmony_ci			ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
31062306a36Sopenharmony_ci			return;
31162306a36Sopenharmony_ci		}
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (s->type == IVTV_ENC_STREAM_TYPE_PCM &&
31762306a36Sopenharmony_ci	    itv->pcm_announce_callback != NULL) {
31862306a36Sopenharmony_ci		/*
31962306a36Sopenharmony_ci		 * Set up the work handler to pass the data to ivtv-alsa.
32062306a36Sopenharmony_ci		 *
32162306a36Sopenharmony_ci		 * We just use q_full and let the work handler race with users
32262306a36Sopenharmony_ci		 * making ivtv-fileops.c calls on the PCM device node.
32362306a36Sopenharmony_ci		 *
32462306a36Sopenharmony_ci		 * Users should not be using both the ALSA and V4L2 PCM audio
32562306a36Sopenharmony_ci		 * capture interfaces at the same time.  If the user does this,
32662306a36Sopenharmony_ci		 * fragments of data will just go out each interface as they
32762306a36Sopenharmony_ci		 * race for PCM data.
32862306a36Sopenharmony_ci		 */
32962306a36Sopenharmony_ci		set_bit(IVTV_F_I_WORK_HANDLER_PCM, &itv->i_flags);
33062306a36Sopenharmony_ci		set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (s->fh)
33462306a36Sopenharmony_ci		wake_up(&s->waitq);
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_civoid ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	struct ivtv *itv = s->itv;
34062306a36Sopenharmony_ci	struct yuv_playback_info *yi = &itv->yuv_info;
34162306a36Sopenharmony_ci	u8 frame = yi->draw_frame;
34262306a36Sopenharmony_ci	struct yuv_frame_info *f = &yi->new_frame_info[frame];
34362306a36Sopenharmony_ci	struct ivtv_buffer *buf;
34462306a36Sopenharmony_ci	u32 y_size = 720 * ((f->src_h + 31) & ~31);
34562306a36Sopenharmony_ci	u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
34662306a36Sopenharmony_ci	int y_done = 0;
34762306a36Sopenharmony_ci	int bytes_written = 0;
34862306a36Sopenharmony_ci	int idx = 0;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	/* Insert buffer block for YUV if needed */
35362306a36Sopenharmony_ci	if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) {
35462306a36Sopenharmony_ci		if (yi->blanking_dmaptr) {
35562306a36Sopenharmony_ci			s->sg_pending[idx].src = yi->blanking_dmaptr;
35662306a36Sopenharmony_ci			s->sg_pending[idx].dst = offset;
35762306a36Sopenharmony_ci			s->sg_pending[idx].size = 720 * 16;
35862306a36Sopenharmony_ci		}
35962306a36Sopenharmony_ci		offset += 720 * 16;
36062306a36Sopenharmony_ci		idx++;
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	list_for_each_entry(buf, &s->q_predma.list, list) {
36462306a36Sopenharmony_ci		/* YUV UV Offset from Y Buffer */
36562306a36Sopenharmony_ci		if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done &&
36662306a36Sopenharmony_ci				(bytes_written + buf->bytesused) >= y_size) {
36762306a36Sopenharmony_ci			s->sg_pending[idx].src = buf->dma_handle;
36862306a36Sopenharmony_ci			s->sg_pending[idx].dst = offset;
36962306a36Sopenharmony_ci			s->sg_pending[idx].size = y_size - bytes_written;
37062306a36Sopenharmony_ci			offset = uv_offset;
37162306a36Sopenharmony_ci			if (s->sg_pending[idx].size != buf->bytesused) {
37262306a36Sopenharmony_ci				idx++;
37362306a36Sopenharmony_ci				s->sg_pending[idx].src =
37462306a36Sopenharmony_ci				  buf->dma_handle + s->sg_pending[idx - 1].size;
37562306a36Sopenharmony_ci				s->sg_pending[idx].dst = offset;
37662306a36Sopenharmony_ci				s->sg_pending[idx].size =
37762306a36Sopenharmony_ci				   buf->bytesused - s->sg_pending[idx - 1].size;
37862306a36Sopenharmony_ci				offset += s->sg_pending[idx].size;
37962306a36Sopenharmony_ci			}
38062306a36Sopenharmony_ci			y_done = 1;
38162306a36Sopenharmony_ci		} else {
38262306a36Sopenharmony_ci			s->sg_pending[idx].src = buf->dma_handle;
38362306a36Sopenharmony_ci			s->sg_pending[idx].dst = offset;
38462306a36Sopenharmony_ci			s->sg_pending[idx].size = buf->bytesused;
38562306a36Sopenharmony_ci			offset += buf->bytesused;
38662306a36Sopenharmony_ci		}
38762306a36Sopenharmony_ci		bytes_written += buf->bytesused;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		/* Sync SG buffers */
39062306a36Sopenharmony_ci		ivtv_buf_sync_for_device(s, buf);
39162306a36Sopenharmony_ci		idx++;
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci	s->sg_pending_size = idx;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	/* Sync Hardware SG List of buffers */
39662306a36Sopenharmony_ci	ivtv_stream_sync_for_device(s);
39762306a36Sopenharmony_ci	if (lock) {
39862306a36Sopenharmony_ci		unsigned long flags = 0;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci		spin_lock_irqsave(&itv->dma_reg_lock, flags);
40162306a36Sopenharmony_ci		if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
40262306a36Sopenharmony_ci			ivtv_dma_dec_start(s);
40362306a36Sopenharmony_ci		else
40462306a36Sopenharmony_ci			set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
40562306a36Sopenharmony_ci		spin_unlock_irqrestore(&itv->dma_reg_lock, flags);
40662306a36Sopenharmony_ci	} else {
40762306a36Sopenharmony_ci		if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
40862306a36Sopenharmony_ci			ivtv_dma_dec_start(s);
40962306a36Sopenharmony_ci		else
41062306a36Sopenharmony_ci			set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic void ivtv_dma_enc_start_xfer(struct ivtv_stream *s)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	struct ivtv *itv = s->itv;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
41962306a36Sopenharmony_ci	s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
42062306a36Sopenharmony_ci	s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
42162306a36Sopenharmony_ci	s->sg_processed++;
42262306a36Sopenharmony_ci	/* Sync Hardware SG List of buffers */
42362306a36Sopenharmony_ci	ivtv_stream_sync_for_device(s);
42462306a36Sopenharmony_ci	write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR);
42562306a36Sopenharmony_ci	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
42662306a36Sopenharmony_ci	itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
42762306a36Sopenharmony_ci	add_timer(&itv->dma_timer);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic void ivtv_dma_dec_start_xfer(struct ivtv_stream *s)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct ivtv *itv = s->itv;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
43562306a36Sopenharmony_ci	s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
43662306a36Sopenharmony_ci	s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
43762306a36Sopenharmony_ci	s->sg_processed++;
43862306a36Sopenharmony_ci	/* Sync Hardware SG List of buffers */
43962306a36Sopenharmony_ci	ivtv_stream_sync_for_device(s);
44062306a36Sopenharmony_ci	write_reg(s->sg_handle, IVTV_REG_DECDMAADDR);
44162306a36Sopenharmony_ci	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
44262306a36Sopenharmony_ci	itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
44362306a36Sopenharmony_ci	add_timer(&itv->dma_timer);
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci/* start the encoder DMA */
44762306a36Sopenharmony_cistatic void ivtv_dma_enc_start(struct ivtv_stream *s)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	struct ivtv *itv = s->itv;
45062306a36Sopenharmony_ci	struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
45162306a36Sopenharmony_ci	int i;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (s->q_predma.bytesused)
45662306a36Sopenharmony_ci		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	if (ivtv_use_dma(s))
45962306a36Sopenharmony_ci		s->sg_pending[s->sg_pending_size - 1].size += 256;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	/* If this is an MPEG stream, and VBI data is also pending, then append the
46262306a36Sopenharmony_ci	   VBI DMA to the MPEG DMA and transfer both sets of data at once.
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	   VBI DMA is a second class citizen compared to MPEG and mixing them together
46562306a36Sopenharmony_ci	   will confuse the firmware (the end of a VBI DMA is seen as the end of a
46662306a36Sopenharmony_ci	   MPEG DMA, thus effectively dropping an MPEG frame). So instead we make
46762306a36Sopenharmony_ci	   sure we only use the MPEG DMA to transfer the VBI DMA if both are in
46862306a36Sopenharmony_ci	   use. This way no conflicts occur. */
46962306a36Sopenharmony_ci	clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
47062306a36Sopenharmony_ci	if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size &&
47162306a36Sopenharmony_ci			s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) {
47262306a36Sopenharmony_ci		ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused);
47362306a36Sopenharmony_ci		if (ivtv_use_dma(s_vbi))
47462306a36Sopenharmony_ci			s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256;
47562306a36Sopenharmony_ci		for (i = 0; i < s_vbi->sg_pending_size; i++) {
47662306a36Sopenharmony_ci			s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i];
47762306a36Sopenharmony_ci		}
47862306a36Sopenharmony_ci		s_vbi->dma_offset = s_vbi->pending_offset;
47962306a36Sopenharmony_ci		s_vbi->sg_pending_size = 0;
48062306a36Sopenharmony_ci		s_vbi->dma_xfer_cnt++;
48162306a36Sopenharmony_ci		set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
48262306a36Sopenharmony_ci		IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name);
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	s->dma_xfer_cnt++;
48662306a36Sopenharmony_ci	memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
48762306a36Sopenharmony_ci	s->sg_processing_size = s->sg_pending_size;
48862306a36Sopenharmony_ci	s->sg_pending_size = 0;
48962306a36Sopenharmony_ci	s->sg_processed = 0;
49062306a36Sopenharmony_ci	s->dma_offset = s->pending_offset;
49162306a36Sopenharmony_ci	s->dma_backup = s->pending_backup;
49262306a36Sopenharmony_ci	s->dma_pts = s->pending_pts;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (ivtv_use_pio(s)) {
49562306a36Sopenharmony_ci		set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags);
49662306a36Sopenharmony_ci		set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
49762306a36Sopenharmony_ci		set_bit(IVTV_F_I_PIO, &itv->i_flags);
49862306a36Sopenharmony_ci		itv->cur_pio_stream = s->type;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci	else {
50162306a36Sopenharmony_ci		itv->dma_retries = 0;
50262306a36Sopenharmony_ci		ivtv_dma_enc_start_xfer(s);
50362306a36Sopenharmony_ci		set_bit(IVTV_F_I_DMA, &itv->i_flags);
50462306a36Sopenharmony_ci		itv->cur_dma_stream = s->type;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic void ivtv_dma_dec_start(struct ivtv_stream *s)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct ivtv *itv = s->itv;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	if (s->q_predma.bytesused)
51362306a36Sopenharmony_ci		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
51462306a36Sopenharmony_ci	s->dma_xfer_cnt++;
51562306a36Sopenharmony_ci	memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
51662306a36Sopenharmony_ci	s->sg_processing_size = s->sg_pending_size;
51762306a36Sopenharmony_ci	s->sg_pending_size = 0;
51862306a36Sopenharmony_ci	s->sg_processed = 0;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name);
52162306a36Sopenharmony_ci	itv->dma_retries = 0;
52262306a36Sopenharmony_ci	ivtv_dma_dec_start_xfer(s);
52362306a36Sopenharmony_ci	set_bit(IVTV_F_I_DMA, &itv->i_flags);
52462306a36Sopenharmony_ci	itv->cur_dma_stream = s->type;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic void ivtv_irq_dma_read(struct ivtv *itv)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct ivtv_stream *s = NULL;
53062306a36Sopenharmony_ci	struct ivtv_buffer *buf;
53162306a36Sopenharmony_ci	int hw_stream_type = 0;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	IVTV_DEBUG_HI_IRQ("DEC DMA READ\n");
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	del_timer(&itv->dma_timer);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0)
53862306a36Sopenharmony_ci		return;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
54162306a36Sopenharmony_ci		s = &itv->streams[itv->cur_dma_stream];
54262306a36Sopenharmony_ci		ivtv_stream_sync_for_cpu(s);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci		if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
54562306a36Sopenharmony_ci			IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n",
54662306a36Sopenharmony_ci					read_reg(IVTV_REG_DMASTATUS),
54762306a36Sopenharmony_ci					s->sg_processed, s->sg_processing_size, itv->dma_retries);
54862306a36Sopenharmony_ci			write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
54962306a36Sopenharmony_ci			if (itv->dma_retries == 3) {
55062306a36Sopenharmony_ci				/* Too many retries, give up on this frame */
55162306a36Sopenharmony_ci				itv->dma_retries = 0;
55262306a36Sopenharmony_ci				s->sg_processed = s->sg_processing_size;
55362306a36Sopenharmony_ci			}
55462306a36Sopenharmony_ci			else {
55562306a36Sopenharmony_ci				/* Retry, starting with the first xfer segment.
55662306a36Sopenharmony_ci				   Just retrying the current segment is not sufficient. */
55762306a36Sopenharmony_ci				s->sg_processed = 0;
55862306a36Sopenharmony_ci				itv->dma_retries++;
55962306a36Sopenharmony_ci			}
56062306a36Sopenharmony_ci		}
56162306a36Sopenharmony_ci		if (s->sg_processed < s->sg_processing_size) {
56262306a36Sopenharmony_ci			/* DMA next buffer */
56362306a36Sopenharmony_ci			ivtv_dma_dec_start_xfer(s);
56462306a36Sopenharmony_ci			return;
56562306a36Sopenharmony_ci		}
56662306a36Sopenharmony_ci		if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
56762306a36Sopenharmony_ci			hw_stream_type = 2;
56862306a36Sopenharmony_ci		IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		/* For some reason must kick the firmware, like PIO mode,
57162306a36Sopenharmony_ci		   I think this tells the firmware we are done and the size
57262306a36Sopenharmony_ci		   of the xfer so it can calculate what we need next.
57362306a36Sopenharmony_ci		   I think we can do this part ourselves but would have to
57462306a36Sopenharmony_ci		   fully calculate xfer info ourselves and not use interrupts
57562306a36Sopenharmony_ci		 */
57662306a36Sopenharmony_ci		ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, s->q_dma.bytesused,
57762306a36Sopenharmony_ci				hw_stream_type);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		/* Free last DMA call */
58062306a36Sopenharmony_ci		while ((buf = ivtv_dequeue(s, &s->q_dma)) != NULL) {
58162306a36Sopenharmony_ci			ivtv_buf_sync_for_cpu(s, buf);
58262306a36Sopenharmony_ci			ivtv_enqueue(s, buf, &s->q_free);
58362306a36Sopenharmony_ci		}
58462306a36Sopenharmony_ci		wake_up(&s->waitq);
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
58762306a36Sopenharmony_ci	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
58862306a36Sopenharmony_ci	itv->cur_dma_stream = -1;
58962306a36Sopenharmony_ci	wake_up(&itv->dma_waitq);
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cistatic void ivtv_irq_enc_dma_complete(struct ivtv *itv)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	u32 data[CX2341X_MBOX_MAX_DATA];
59562306a36Sopenharmony_ci	struct ivtv_stream *s;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data);
59862306a36Sopenharmony_ci	IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	del_timer(&itv->dma_timer);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (itv->cur_dma_stream < 0)
60362306a36Sopenharmony_ci		return;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	s = &itv->streams[itv->cur_dma_stream];
60662306a36Sopenharmony_ci	ivtv_stream_sync_for_cpu(s);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	if (data[0] & 0x18) {
60962306a36Sopenharmony_ci		IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0],
61062306a36Sopenharmony_ci			s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries);
61162306a36Sopenharmony_ci		write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
61262306a36Sopenharmony_ci		if (itv->dma_retries == 3) {
61362306a36Sopenharmony_ci			/* Too many retries, give up on this frame */
61462306a36Sopenharmony_ci			itv->dma_retries = 0;
61562306a36Sopenharmony_ci			s->sg_processed = s->sg_processing_size;
61662306a36Sopenharmony_ci		}
61762306a36Sopenharmony_ci		else {
61862306a36Sopenharmony_ci			/* Retry, starting with the first xfer segment.
61962306a36Sopenharmony_ci			   Just retrying the current segment is not sufficient. */
62062306a36Sopenharmony_ci			s->sg_processed = 0;
62162306a36Sopenharmony_ci			itv->dma_retries++;
62262306a36Sopenharmony_ci		}
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci	if (s->sg_processed < s->sg_processing_size) {
62562306a36Sopenharmony_ci		/* DMA next buffer */
62662306a36Sopenharmony_ci		ivtv_dma_enc_start_xfer(s);
62762306a36Sopenharmony_ci		return;
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
63062306a36Sopenharmony_ci	itv->cur_dma_stream = -1;
63162306a36Sopenharmony_ci	dma_post(s);
63262306a36Sopenharmony_ci	if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
63362306a36Sopenharmony_ci		s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
63462306a36Sopenharmony_ci		dma_post(s);
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci	s->sg_processing_size = 0;
63762306a36Sopenharmony_ci	s->sg_processed = 0;
63862306a36Sopenharmony_ci	wake_up(&itv->dma_waitq);
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic void ivtv_irq_enc_pio_complete(struct ivtv *itv)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	struct ivtv_stream *s;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS) {
64662306a36Sopenharmony_ci		itv->cur_pio_stream = -1;
64762306a36Sopenharmony_ci		return;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci	s = &itv->streams[itv->cur_pio_stream];
65062306a36Sopenharmony_ci	IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name);
65162306a36Sopenharmony_ci	clear_bit(IVTV_F_I_PIO, &itv->i_flags);
65262306a36Sopenharmony_ci	itv->cur_pio_stream = -1;
65362306a36Sopenharmony_ci	dma_post(s);
65462306a36Sopenharmony_ci	if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
65562306a36Sopenharmony_ci		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 0);
65662306a36Sopenharmony_ci	else if (s->type == IVTV_ENC_STREAM_TYPE_YUV)
65762306a36Sopenharmony_ci		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 1);
65862306a36Sopenharmony_ci	else if (s->type == IVTV_ENC_STREAM_TYPE_PCM)
65962306a36Sopenharmony_ci		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2);
66062306a36Sopenharmony_ci	clear_bit(IVTV_F_I_PIO, &itv->i_flags);
66162306a36Sopenharmony_ci	if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
66262306a36Sopenharmony_ci		s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
66362306a36Sopenharmony_ci		dma_post(s);
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci	wake_up(&itv->dma_waitq);
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cistatic void ivtv_irq_dma_err(struct ivtv *itv)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	u32 data[CX2341X_MBOX_MAX_DATA];
67162306a36Sopenharmony_ci	u32 status;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	del_timer(&itv->dma_timer);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data);
67662306a36Sopenharmony_ci	status = read_reg(IVTV_REG_DMASTATUS);
67762306a36Sopenharmony_ci	IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1],
67862306a36Sopenharmony_ci				status, itv->cur_dma_stream);
67962306a36Sopenharmony_ci	/*
68062306a36Sopenharmony_ci	 * We do *not* write back to the IVTV_REG_DMASTATUS register to
68162306a36Sopenharmony_ci	 * clear the error status, if either the encoder write (0x02) or
68262306a36Sopenharmony_ci	 * decoder read (0x01) bus master DMA operation do not indicate
68362306a36Sopenharmony_ci	 * completed.  We can race with the DMA engine, which may have
68462306a36Sopenharmony_ci	 * transitioned to completed status *after* we read the register.
68562306a36Sopenharmony_ci	 * Setting a IVTV_REG_DMASTATUS flag back to "busy" status, after the
68662306a36Sopenharmony_ci	 * DMA engine has completed, will cause the DMA engine to stop working.
68762306a36Sopenharmony_ci	 */
68862306a36Sopenharmony_ci	status &= 0x3;
68962306a36Sopenharmony_ci	if (status == 0x3)
69062306a36Sopenharmony_ci		write_reg(status, IVTV_REG_DMASTATUS);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) &&
69362306a36Sopenharmony_ci	    itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) {
69462306a36Sopenharmony_ci		struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream];
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci		if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
69762306a36Sopenharmony_ci			/* retry */
69862306a36Sopenharmony_ci			/*
69962306a36Sopenharmony_ci			 * FIXME - handle cases of DMA error similar to
70062306a36Sopenharmony_ci			 * encoder below, except conditioned on status & 0x1
70162306a36Sopenharmony_ci			 */
70262306a36Sopenharmony_ci			ivtv_dma_dec_start(s);
70362306a36Sopenharmony_ci			return;
70462306a36Sopenharmony_ci		} else {
70562306a36Sopenharmony_ci			if ((status & 0x2) == 0) {
70662306a36Sopenharmony_ci				/*
70762306a36Sopenharmony_ci				 * CX2341x Bus Master DMA write is ongoing.
70862306a36Sopenharmony_ci				 * Reset the timer and let it complete.
70962306a36Sopenharmony_ci				 */
71062306a36Sopenharmony_ci				itv->dma_timer.expires =
71162306a36Sopenharmony_ci						jiffies + msecs_to_jiffies(600);
71262306a36Sopenharmony_ci				add_timer(&itv->dma_timer);
71362306a36Sopenharmony_ci				return;
71462306a36Sopenharmony_ci			}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci			if (itv->dma_retries < 3) {
71762306a36Sopenharmony_ci				/*
71862306a36Sopenharmony_ci				 * CX2341x Bus Master DMA write has ended.
71962306a36Sopenharmony_ci				 * Retry the write, starting with the first
72062306a36Sopenharmony_ci				 * xfer segment. Just retrying the current
72162306a36Sopenharmony_ci				 * segment is not sufficient.
72262306a36Sopenharmony_ci				 */
72362306a36Sopenharmony_ci				s->sg_processed = 0;
72462306a36Sopenharmony_ci				itv->dma_retries++;
72562306a36Sopenharmony_ci				ivtv_dma_enc_start_xfer(s);
72662306a36Sopenharmony_ci				return;
72762306a36Sopenharmony_ci			}
72862306a36Sopenharmony_ci			/* Too many retries, give up on this one */
72962306a36Sopenharmony_ci		}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci	if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
73362306a36Sopenharmony_ci		ivtv_udma_start(itv);
73462306a36Sopenharmony_ci		return;
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
73762306a36Sopenharmony_ci	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
73862306a36Sopenharmony_ci	itv->cur_dma_stream = -1;
73962306a36Sopenharmony_ci	wake_up(&itv->dma_waitq);
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic void ivtv_irq_enc_start_cap(struct ivtv *itv)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	u32 data[CX2341X_MBOX_MAX_DATA];
74562306a36Sopenharmony_ci	struct ivtv_stream *s;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	/* Get DMA destination and size arguments from card */
74862306a36Sopenharmony_ci	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, 7, data);
74962306a36Sopenharmony_ci	IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (data[0] > 2 || data[1] == 0 || data[2] == 0) {
75262306a36Sopenharmony_ci		IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n",
75362306a36Sopenharmony_ci				data[0], data[1], data[2]);
75462306a36Sopenharmony_ci		return;
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci	s = &itv->streams[ivtv_stream_map[data[0]]];
75762306a36Sopenharmony_ci	if (!stream_enc_dma_append(s, data)) {
75862306a36Sopenharmony_ci		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cistatic void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
76362306a36Sopenharmony_ci{
76462306a36Sopenharmony_ci	u32 data[CX2341X_MBOX_MAX_DATA];
76562306a36Sopenharmony_ci	struct ivtv_stream *s;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
76862306a36Sopenharmony_ci	s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	if (!stream_enc_dma_append(s, data))
77162306a36Sopenharmony_ci		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	u32 data[CX2341X_MBOX_MAX_DATA];
77762306a36Sopenharmony_ci	struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n");
78062306a36Sopenharmony_ci	if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) &&
78162306a36Sopenharmony_ci			!stream_enc_dma_append(s, data)) {
78262306a36Sopenharmony_ci		set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags);
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic void ivtv_irq_dec_data_req(struct ivtv *itv)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	u32 data[CX2341X_MBOX_MAX_DATA];
78962306a36Sopenharmony_ci	struct ivtv_stream *s;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	/* YUV or MPG */
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
79462306a36Sopenharmony_ci		ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data);
79562306a36Sopenharmony_ci		itv->dma_data_req_size =
79662306a36Sopenharmony_ci				 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
79762306a36Sopenharmony_ci		itv->dma_data_req_offset = data[1];
79862306a36Sopenharmony_ci		if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0)
79962306a36Sopenharmony_ci			ivtv_yuv_frame_complete(itv);
80062306a36Sopenharmony_ci		s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci	else {
80362306a36Sopenharmony_ci		ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 3, data);
80462306a36Sopenharmony_ci		itv->dma_data_req_size = min_t(u32, data[2], 0x10000);
80562306a36Sopenharmony_ci		itv->dma_data_req_offset = data[1];
80662306a36Sopenharmony_ci		s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci	IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
80962306a36Sopenharmony_ci		       itv->dma_data_req_offset, itv->dma_data_req_size);
81062306a36Sopenharmony_ci	if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) {
81162306a36Sopenharmony_ci		set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci	else {
81462306a36Sopenharmony_ci		if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
81562306a36Sopenharmony_ci			ivtv_yuv_setup_stream_frame(itv);
81662306a36Sopenharmony_ci		clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
81762306a36Sopenharmony_ci		ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
81862306a36Sopenharmony_ci		ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0);
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic void ivtv_irq_vsync(struct ivtv *itv)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	/* The vsync interrupt is unusual in that it won't clear until
82562306a36Sopenharmony_ci	 * the end of the first line for the current field, at which
82662306a36Sopenharmony_ci	 * point it clears itself. This can result in repeated vsync
82762306a36Sopenharmony_ci	 * interrupts, or a missed vsync. Read some of the registers
82862306a36Sopenharmony_ci	 * to determine the line being displayed and ensure we handle
82962306a36Sopenharmony_ci	 * one vsync per frame.
83062306a36Sopenharmony_ci	 */
83162306a36Sopenharmony_ci	unsigned int frame = read_reg(IVTV_REG_DEC_LINE_FIELD) & 1;
83262306a36Sopenharmony_ci	struct yuv_playback_info *yi = &itv->yuv_info;
83362306a36Sopenharmony_ci	int last_dma_frame = atomic_read(&yi->next_dma_frame);
83462306a36Sopenharmony_ci	struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame];
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	if (((frame ^ f->sync_field) == 0 &&
83962306a36Sopenharmony_ci		((itv->last_vsync_field & 1) ^ f->sync_field)) ||
84062306a36Sopenharmony_ci			(frame != (itv->last_vsync_field & 1) && !f->interlaced)) {
84162306a36Sopenharmony_ci		int next_dma_frame = last_dma_frame;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci		if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) {
84462306a36Sopenharmony_ci			if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) {
84562306a36Sopenharmony_ci				write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
84662306a36Sopenharmony_ci				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
84762306a36Sopenharmony_ci				write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
84862306a36Sopenharmony_ci				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
84962306a36Sopenharmony_ci				next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS;
85062306a36Sopenharmony_ci				atomic_set(&yi->next_dma_frame, next_dma_frame);
85162306a36Sopenharmony_ci				yi->fields_lapsed = -1;
85262306a36Sopenharmony_ci				yi->running = 1;
85362306a36Sopenharmony_ci			}
85462306a36Sopenharmony_ci		}
85562306a36Sopenharmony_ci	}
85662306a36Sopenharmony_ci	if (frame != (itv->last_vsync_field & 1)) {
85762306a36Sopenharmony_ci		static const struct v4l2_event evtop = {
85862306a36Sopenharmony_ci			.type = V4L2_EVENT_VSYNC,
85962306a36Sopenharmony_ci			.u.vsync.field = V4L2_FIELD_TOP,
86062306a36Sopenharmony_ci		};
86162306a36Sopenharmony_ci		static const struct v4l2_event evbottom = {
86262306a36Sopenharmony_ci			.type = V4L2_EVENT_VSYNC,
86362306a36Sopenharmony_ci			.u.vsync.field = V4L2_FIELD_BOTTOM,
86462306a36Sopenharmony_ci		};
86562306a36Sopenharmony_ci		struct ivtv_stream *s = ivtv_get_output_stream(itv);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci		itv->last_vsync_field += 1;
86862306a36Sopenharmony_ci		if (frame == 0) {
86962306a36Sopenharmony_ci			clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
87062306a36Sopenharmony_ci			clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags);
87162306a36Sopenharmony_ci		}
87262306a36Sopenharmony_ci		else {
87362306a36Sopenharmony_ci			set_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags);
87462306a36Sopenharmony_ci		}
87562306a36Sopenharmony_ci		if (test_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags)) {
87662306a36Sopenharmony_ci			set_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags);
87762306a36Sopenharmony_ci			wake_up(&itv->event_waitq);
87862306a36Sopenharmony_ci			if (s)
87962306a36Sopenharmony_ci				wake_up(&s->waitq);
88062306a36Sopenharmony_ci		}
88162306a36Sopenharmony_ci		if (s && s->vdev.v4l2_dev)
88262306a36Sopenharmony_ci			v4l2_event_queue(&s->vdev, frame ? &evtop : &evbottom);
88362306a36Sopenharmony_ci		wake_up(&itv->vsync_waitq);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci		/* Send VBI to saa7127 */
88662306a36Sopenharmony_ci		if (frame && (itv->output_mode == OUT_PASSTHROUGH ||
88762306a36Sopenharmony_ci			test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) ||
88862306a36Sopenharmony_ci			test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) ||
88962306a36Sopenharmony_ci			test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) {
89062306a36Sopenharmony_ci			set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags);
89162306a36Sopenharmony_ci			set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
89262306a36Sopenharmony_ci		}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci		/* Check if we need to update the yuv registers */
89562306a36Sopenharmony_ci		if (yi->running && (yi->yuv_forced_update || f->update)) {
89662306a36Sopenharmony_ci			if (!f->update) {
89762306a36Sopenharmony_ci				last_dma_frame =
89862306a36Sopenharmony_ci					(u8)(atomic_read(&yi->next_dma_frame) -
89962306a36Sopenharmony_ci						 1) % IVTV_YUV_BUFFERS;
90062306a36Sopenharmony_ci				f = &yi->new_frame_info[last_dma_frame];
90162306a36Sopenharmony_ci			}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci			if (f->src_w) {
90462306a36Sopenharmony_ci				yi->update_frame = last_dma_frame;
90562306a36Sopenharmony_ci				f->update = 0;
90662306a36Sopenharmony_ci				yi->yuv_forced_update = 0;
90762306a36Sopenharmony_ci				set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags);
90862306a36Sopenharmony_ci				set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
90962306a36Sopenharmony_ci			}
91062306a36Sopenharmony_ci		}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci		yi->fields_lapsed++;
91362306a36Sopenharmony_ci	}
91462306a36Sopenharmony_ci}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci#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)
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ciirqreturn_t ivtv_irq_handler(int irq, void *dev_id)
91962306a36Sopenharmony_ci{
92062306a36Sopenharmony_ci	struct ivtv *itv = (struct ivtv *)dev_id;
92162306a36Sopenharmony_ci	u32 combo;
92262306a36Sopenharmony_ci	u32 stat;
92362306a36Sopenharmony_ci	int i;
92462306a36Sopenharmony_ci	u8 vsync_force = 0;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	spin_lock(&itv->dma_reg_lock);
92762306a36Sopenharmony_ci	/* get contents of irq status register */
92862306a36Sopenharmony_ci	stat = read_reg(IVTV_REG_IRQSTATUS);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	combo = ~itv->irqmask & stat;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	/* Clear out IRQ */
93362306a36Sopenharmony_ci	if (combo) write_reg(combo, IVTV_REG_IRQSTATUS);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	if (0 == combo) {
93662306a36Sopenharmony_ci		/* The vsync interrupt is unusual and clears itself. If we
93762306a36Sopenharmony_ci		 * took too long, we may have missed it. Do some checks
93862306a36Sopenharmony_ci		 */
93962306a36Sopenharmony_ci		if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
94062306a36Sopenharmony_ci			/* vsync is enabled, see if we're in a new field */
94162306a36Sopenharmony_ci			if ((itv->last_vsync_field & 1) !=
94262306a36Sopenharmony_ci			    (read_reg(IVTV_REG_DEC_LINE_FIELD) & 1)) {
94362306a36Sopenharmony_ci				/* New field, looks like we missed it */
94462306a36Sopenharmony_ci				IVTV_DEBUG_YUV("VSync interrupt missed %d\n",
94562306a36Sopenharmony_ci				       read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16);
94662306a36Sopenharmony_ci				vsync_force = 1;
94762306a36Sopenharmony_ci			}
94862306a36Sopenharmony_ci		}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		if (!vsync_force) {
95162306a36Sopenharmony_ci			/* No Vsync expected, wasn't for us */
95262306a36Sopenharmony_ci			spin_unlock(&itv->dma_reg_lock);
95362306a36Sopenharmony_ci			return IRQ_NONE;
95462306a36Sopenharmony_ci		}
95562306a36Sopenharmony_ci	}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	/* Exclude interrupts noted below from the output, otherwise the log is flooded with
95862306a36Sopenharmony_ci	   these messages */
95962306a36Sopenharmony_ci	if (combo & ~0xff6d0400)
96062306a36Sopenharmony_ci		IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) {
96362306a36Sopenharmony_ci		IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n");
96462306a36Sopenharmony_ci	}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	if (combo & IVTV_IRQ_DMA_READ) {
96762306a36Sopenharmony_ci		ivtv_irq_dma_read(itv);
96862306a36Sopenharmony_ci	}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) {
97162306a36Sopenharmony_ci		ivtv_irq_enc_dma_complete(itv);
97262306a36Sopenharmony_ci	}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	if (combo & IVTV_IRQ_ENC_PIO_COMPLETE) {
97562306a36Sopenharmony_ci		ivtv_irq_enc_pio_complete(itv);
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	if (combo & IVTV_IRQ_DMA_ERR) {
97962306a36Sopenharmony_ci		ivtv_irq_dma_err(itv);
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	if (combo & IVTV_IRQ_ENC_START_CAP) {
98362306a36Sopenharmony_ci		ivtv_irq_enc_start_cap(itv);
98462306a36Sopenharmony_ci	}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	if (combo & IVTV_IRQ_ENC_VBI_CAP) {
98762306a36Sopenharmony_ci		ivtv_irq_enc_vbi_cap(itv);
98862306a36Sopenharmony_ci	}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) {
99162306a36Sopenharmony_ci		ivtv_irq_dec_vbi_reinsert(itv);
99262306a36Sopenharmony_ci	}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	if (combo & IVTV_IRQ_ENC_EOS) {
99562306a36Sopenharmony_ci		IVTV_DEBUG_IRQ("ENC EOS\n");
99662306a36Sopenharmony_ci		set_bit(IVTV_F_I_EOS, &itv->i_flags);
99762306a36Sopenharmony_ci		wake_up(&itv->eos_waitq);
99862306a36Sopenharmony_ci	}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	if (combo & IVTV_IRQ_DEC_DATA_REQ) {
100162306a36Sopenharmony_ci		ivtv_irq_dec_data_req(itv);
100262306a36Sopenharmony_ci	}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	/* Decoder Vertical Sync - We can't rely on 'combo', so check if vsync enabled */
100562306a36Sopenharmony_ci	if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
100662306a36Sopenharmony_ci		ivtv_irq_vsync(itv);
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	if (combo & IVTV_IRQ_ENC_VIM_RST) {
101062306a36Sopenharmony_ci		IVTV_DEBUG_IRQ("VIM RST\n");
101162306a36Sopenharmony_ci		/*ivtv_vapi(itv, CX2341X_ENC_REFRESH_INPUT, 0); */
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) {
101562306a36Sopenharmony_ci		IVTV_DEBUG_INFO("Stereo mode changed\n");
101662306a36Sopenharmony_ci	}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
101962306a36Sopenharmony_ci		itv->irq_rr_idx++;
102062306a36Sopenharmony_ci		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
102162306a36Sopenharmony_ci			int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
102262306a36Sopenharmony_ci			struct ivtv_stream *s = &itv->streams[idx];
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci			if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags))
102562306a36Sopenharmony_ci				continue;
102662306a36Sopenharmony_ci			if (s->type >= IVTV_DEC_STREAM_TYPE_MPG)
102762306a36Sopenharmony_ci				ivtv_dma_dec_start(s);
102862306a36Sopenharmony_ci			else
102962306a36Sopenharmony_ci				ivtv_dma_enc_start(s);
103062306a36Sopenharmony_ci			break;
103162306a36Sopenharmony_ci		}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci		if (i == IVTV_MAX_STREAMS &&
103462306a36Sopenharmony_ci		    test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
103562306a36Sopenharmony_ci			ivtv_udma_start(itv);
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) {
103962306a36Sopenharmony_ci		itv->irq_rr_idx++;
104062306a36Sopenharmony_ci		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
104162306a36Sopenharmony_ci			int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
104262306a36Sopenharmony_ci			struct ivtv_stream *s = &itv->streams[idx];
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci			if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags))
104562306a36Sopenharmony_ci				continue;
104662306a36Sopenharmony_ci			if (s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type < IVTV_DEC_STREAM_TYPE_MPG)
104762306a36Sopenharmony_ci				ivtv_dma_enc_start(s);
104862306a36Sopenharmony_ci			break;
104962306a36Sopenharmony_ci		}
105062306a36Sopenharmony_ci	}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) {
105362306a36Sopenharmony_ci		kthread_queue_work(&itv->irq_worker, &itv->irq_work);
105462306a36Sopenharmony_ci	}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	spin_unlock(&itv->dma_reg_lock);
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	/* If we've just handled a 'forced' vsync, it's safest to say it
105962306a36Sopenharmony_ci	 * wasn't ours. Another device may have triggered it at just
106062306a36Sopenharmony_ci	 * the right time.
106162306a36Sopenharmony_ci	 */
106262306a36Sopenharmony_ci	return vsync_force ? IRQ_NONE : IRQ_HANDLED;
106362306a36Sopenharmony_ci}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_civoid ivtv_unfinished_dma(struct timer_list *t)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	struct ivtv *itv = from_timer(itv, t, dma_timer);
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
107062306a36Sopenharmony_ci		return;
107162306a36Sopenharmony_ci	IVTV_ERR("DMA TIMEOUT %08x %d\n", read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
107462306a36Sopenharmony_ci	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
107562306a36Sopenharmony_ci	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
107662306a36Sopenharmony_ci	itv->cur_dma_stream = -1;
107762306a36Sopenharmony_ci	wake_up(&itv->dma_waitq);
107862306a36Sopenharmony_ci}
1079