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