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