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