18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* interrupt handling 38c2ecf20Sopenharmony_ci Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> 48c2ecf20Sopenharmony_ci Copyright (C) 2004 Chris Kennedy <c@groovy.org> 58c2ecf20Sopenharmony_ci Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "ivtv-driver.h" 108c2ecf20Sopenharmony_ci#include "ivtv-queue.h" 118c2ecf20Sopenharmony_ci#include "ivtv-udma.h" 128c2ecf20Sopenharmony_ci#include "ivtv-irq.h" 138c2ecf20Sopenharmony_ci#include "ivtv-mailbox.h" 148c2ecf20Sopenharmony_ci#include "ivtv-vbi.h" 158c2ecf20Sopenharmony_ci#include "ivtv-yuv.h" 168c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define DMA_MAGIC_COOKIE 0x000001fe 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic void ivtv_dma_dec_start(struct ivtv_stream *s); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic const int ivtv_stream_map[] = { 238c2ecf20Sopenharmony_ci IVTV_ENC_STREAM_TYPE_MPG, 248c2ecf20Sopenharmony_ci IVTV_ENC_STREAM_TYPE_YUV, 258c2ecf20Sopenharmony_ci IVTV_ENC_STREAM_TYPE_PCM, 268c2ecf20Sopenharmony_ci IVTV_ENC_STREAM_TYPE_VBI, 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic void ivtv_pcm_work_handler(struct ivtv *itv) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM]; 328c2ecf20Sopenharmony_ci struct ivtv_buffer *buf; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci /* Pass the PCM data to ivtv-alsa */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci while (1) { 378c2ecf20Sopenharmony_ci /* 388c2ecf20Sopenharmony_ci * Users should not be using both the ALSA and V4L2 PCM audio 398c2ecf20Sopenharmony_ci * capture interfaces at the same time. If the user is doing 408c2ecf20Sopenharmony_ci * this, there maybe a buffer in q_io to grab, use, and put 418c2ecf20Sopenharmony_ci * back in rotation. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci buf = ivtv_dequeue(s, &s->q_io); 448c2ecf20Sopenharmony_ci if (buf == NULL) 458c2ecf20Sopenharmony_ci buf = ivtv_dequeue(s, &s->q_full); 468c2ecf20Sopenharmony_ci if (buf == NULL) 478c2ecf20Sopenharmony_ci break; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (buf->readpos < buf->bytesused) 508c2ecf20Sopenharmony_ci itv->pcm_announce_callback(itv->alsa, 518c2ecf20Sopenharmony_ci (u8 *)(buf->buf + buf->readpos), 528c2ecf20Sopenharmony_ci (size_t)(buf->bytesused - buf->readpos)); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci ivtv_enqueue(s, buf, &s->q_free); 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void ivtv_pio_work_handler(struct ivtv *itv) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream]; 618c2ecf20Sopenharmony_ci struct ivtv_buffer *buf; 628c2ecf20Sopenharmony_ci int i = 0; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n"); 658c2ecf20Sopenharmony_ci if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS || 668c2ecf20Sopenharmony_ci s->vdev.v4l2_dev == NULL || !ivtv_use_pio(s)) { 678c2ecf20Sopenharmony_ci itv->cur_pio_stream = -1; 688c2ecf20Sopenharmony_ci /* trigger PIO complete user interrupt */ 698c2ecf20Sopenharmony_ci write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); 708c2ecf20Sopenharmony_ci return; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name); 738c2ecf20Sopenharmony_ci list_for_each_entry(buf, &s->q_dma.list, list) { 748c2ecf20Sopenharmony_ci u32 size = s->sg_processing[i].size & 0x3ffff; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* Copy the data from the card to the buffer */ 778c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { 788c2ecf20Sopenharmony_ci memcpy_fromio(buf->buf, itv->dec_mem + s->sg_processing[i].src - IVTV_DECODER_OFFSET, size); 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci else { 818c2ecf20Sopenharmony_ci memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size); 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci i++; 848c2ecf20Sopenharmony_ci if (i == s->sg_processing_size) 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_civoid ivtv_irq_work_handler(struct kthread_work *work) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct ivtv *itv = container_of(work, struct ivtv, irq_work); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags)) 958c2ecf20Sopenharmony_ci ivtv_pio_work_handler(itv); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags)) 988c2ecf20Sopenharmony_ci ivtv_vbi_work_handler(itv); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags)) 1018c2ecf20Sopenharmony_ci ivtv_yuv_work_handler(itv); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PCM, &itv->i_flags)) 1048c2ecf20Sopenharmony_ci ivtv_pcm_work_handler(itv); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* Determine the required DMA size, setup enough buffers in the predma queue and 1088c2ecf20Sopenharmony_ci actually copy the data from the card to the buffers in case a PIO transfer is 1098c2ecf20Sopenharmony_ci required for this stream. 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_cistatic int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MAX_DATA]) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct ivtv *itv = s->itv; 1148c2ecf20Sopenharmony_ci struct ivtv_buffer *buf; 1158c2ecf20Sopenharmony_ci u32 bytes_needed = 0; 1168c2ecf20Sopenharmony_ci u32 offset, size; 1178c2ecf20Sopenharmony_ci u32 UVoffset = 0, UVsize = 0; 1188c2ecf20Sopenharmony_ci int skip_bufs = s->q_predma.buffers; 1198c2ecf20Sopenharmony_ci int idx = s->sg_pending_size; 1208c2ecf20Sopenharmony_ci int rc; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* sanity checks */ 1238c2ecf20Sopenharmony_ci if (s->vdev.v4l2_dev == NULL) { 1248c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("Stream %s not started\n", s->name); 1258c2ecf20Sopenharmony_ci return -1; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci if (!test_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { 1288c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("Stream %s not open\n", s->name); 1298c2ecf20Sopenharmony_ci return -1; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* determine offset, size and PTS for the various streams */ 1338c2ecf20Sopenharmony_ci switch (s->type) { 1348c2ecf20Sopenharmony_ci case IVTV_ENC_STREAM_TYPE_MPG: 1358c2ecf20Sopenharmony_ci offset = data[1]; 1368c2ecf20Sopenharmony_ci size = data[2]; 1378c2ecf20Sopenharmony_ci s->pending_pts = 0; 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci case IVTV_ENC_STREAM_TYPE_YUV: 1418c2ecf20Sopenharmony_ci offset = data[1]; 1428c2ecf20Sopenharmony_ci size = data[2]; 1438c2ecf20Sopenharmony_ci UVoffset = data[3]; 1448c2ecf20Sopenharmony_ci UVsize = data[4]; 1458c2ecf20Sopenharmony_ci s->pending_pts = ((u64) data[5] << 32) | data[6]; 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci case IVTV_ENC_STREAM_TYPE_PCM: 1498c2ecf20Sopenharmony_ci offset = data[1] + 12; 1508c2ecf20Sopenharmony_ci size = data[2] - 12; 1518c2ecf20Sopenharmony_ci s->pending_pts = read_dec(offset - 8) | 1528c2ecf20Sopenharmony_ci ((u64)(read_dec(offset - 12)) << 32); 1538c2ecf20Sopenharmony_ci if (itv->has_cx23415) 1548c2ecf20Sopenharmony_ci offset += IVTV_DECODER_OFFSET; 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci case IVTV_ENC_STREAM_TYPE_VBI: 1588c2ecf20Sopenharmony_ci size = itv->vbi.enc_size * itv->vbi.fpi; 1598c2ecf20Sopenharmony_ci offset = read_enc(itv->vbi.enc_start - 4) + 12; 1608c2ecf20Sopenharmony_ci if (offset == 12) { 1618c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("VBI offset == 0\n"); 1628c2ecf20Sopenharmony_ci return -1; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci s->pending_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci case IVTV_DEC_STREAM_TYPE_VBI: 1688c2ecf20Sopenharmony_ci size = read_dec(itv->vbi.dec_start + 4) + 8; 1698c2ecf20Sopenharmony_ci offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start; 1708c2ecf20Sopenharmony_ci s->pending_pts = 0; 1718c2ecf20Sopenharmony_ci offset += IVTV_DECODER_OFFSET; 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci default: 1748c2ecf20Sopenharmony_ci /* shouldn't happen */ 1758c2ecf20Sopenharmony_ci return -1; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* if this is the start of the DMA then fill in the magic cookie */ 1798c2ecf20Sopenharmony_ci if (s->sg_pending_size == 0 && ivtv_use_dma(s)) { 1808c2ecf20Sopenharmony_ci if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || 1818c2ecf20Sopenharmony_ci s->type == IVTV_DEC_STREAM_TYPE_VBI)) { 1828c2ecf20Sopenharmony_ci s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET); 1838c2ecf20Sopenharmony_ci write_dec_sync(DMA_MAGIC_COOKIE, offset - IVTV_DECODER_OFFSET); 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci else { 1868c2ecf20Sopenharmony_ci s->pending_backup = read_enc(offset); 1878c2ecf20Sopenharmony_ci write_enc_sync(DMA_MAGIC_COOKIE, offset); 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci s->pending_offset = offset; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci bytes_needed = size; 1938c2ecf20Sopenharmony_ci if (s->type == IVTV_ENC_STREAM_TYPE_YUV) { 1948c2ecf20Sopenharmony_ci /* The size for the Y samples needs to be rounded upwards to a 1958c2ecf20Sopenharmony_ci multiple of the buf_size. The UV samples then start in the 1968c2ecf20Sopenharmony_ci next buffer. */ 1978c2ecf20Sopenharmony_ci bytes_needed = s->buf_size * ((bytes_needed + s->buf_size - 1) / s->buf_size); 1988c2ecf20Sopenharmony_ci bytes_needed += UVsize; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n", 2028c2ecf20Sopenharmony_ci ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed); 2058c2ecf20Sopenharmony_ci if (rc < 0) { /* Insufficient buffers */ 2068c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("Cannot obtain %d bytes for %s data transfer\n", 2078c2ecf20Sopenharmony_ci bytes_needed, s->name); 2088c2ecf20Sopenharmony_ci return -1; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci if (rc && !s->buffers_stolen && test_bit(IVTV_F_S_APPL_IO, &s->s_flags)) { 2118c2ecf20Sopenharmony_ci IVTV_WARN("All %s stream buffers are full. Dropping data.\n", s->name); 2128c2ecf20Sopenharmony_ci IVTV_WARN("Cause: the application is not reading fast enough.\n"); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci s->buffers_stolen = rc; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* got the buffers, now fill in sg_pending */ 2178c2ecf20Sopenharmony_ci buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); 2188c2ecf20Sopenharmony_ci memset(buf->buf, 0, 128); 2198c2ecf20Sopenharmony_ci list_for_each_entry(buf, &s->q_predma.list, list) { 2208c2ecf20Sopenharmony_ci if (skip_bufs-- > 0) 2218c2ecf20Sopenharmony_ci continue; 2228c2ecf20Sopenharmony_ci s->sg_pending[idx].dst = buf->dma_handle; 2238c2ecf20Sopenharmony_ci s->sg_pending[idx].src = offset; 2248c2ecf20Sopenharmony_ci s->sg_pending[idx].size = s->buf_size; 2258c2ecf20Sopenharmony_ci buf->bytesused = min(size, s->buf_size); 2268c2ecf20Sopenharmony_ci buf->dma_xfer_cnt = s->dma_xfer_cnt; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci s->q_predma.bytesused += buf->bytesused; 2298c2ecf20Sopenharmony_ci size -= buf->bytesused; 2308c2ecf20Sopenharmony_ci offset += s->buf_size; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* Sync SG buffers */ 2338c2ecf20Sopenharmony_ci ivtv_buf_sync_for_device(s, buf); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (size == 0) { /* YUV */ 2368c2ecf20Sopenharmony_ci /* process the UV section */ 2378c2ecf20Sopenharmony_ci offset = UVoffset; 2388c2ecf20Sopenharmony_ci size = UVsize; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci idx++; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci s->sg_pending_size = idx; 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic void dma_post(struct ivtv_stream *s) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct ivtv *itv = s->itv; 2498c2ecf20Sopenharmony_ci struct ivtv_buffer *buf = NULL; 2508c2ecf20Sopenharmony_ci struct list_head *p; 2518c2ecf20Sopenharmony_ci u32 offset; 2528c2ecf20Sopenharmony_ci __le32 *u32buf; 2538c2ecf20Sopenharmony_ci int x = 0; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA", 2568c2ecf20Sopenharmony_ci s->name, s->dma_offset); 2578c2ecf20Sopenharmony_ci list_for_each(p, &s->q_dma.list) { 2588c2ecf20Sopenharmony_ci buf = list_entry(p, struct ivtv_buffer, list); 2598c2ecf20Sopenharmony_ci u32buf = (__le32 *)buf->buf; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* Sync Buffer */ 2628c2ecf20Sopenharmony_ci ivtv_buf_sync_for_cpu(s, buf); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (x == 0 && ivtv_use_dma(s)) { 2658c2ecf20Sopenharmony_ci offset = s->dma_last_offset; 2668c2ecf20Sopenharmony_ci if (le32_to_cpu(u32buf[offset / 4]) != DMA_MAGIC_COOKIE) 2678c2ecf20Sopenharmony_ci { 2688c2ecf20Sopenharmony_ci for (offset = 0; offset < 64; offset++) 2698c2ecf20Sopenharmony_ci if (le32_to_cpu(u32buf[offset]) == DMA_MAGIC_COOKIE) 2708c2ecf20Sopenharmony_ci break; 2718c2ecf20Sopenharmony_ci offset *= 4; 2728c2ecf20Sopenharmony_ci if (offset == 256) { 2738c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name); 2748c2ecf20Sopenharmony_ci offset = s->dma_last_offset; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci if (s->dma_last_offset != offset) 2778c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("%s: offset %d -> %d\n", s->name, s->dma_last_offset, offset); 2788c2ecf20Sopenharmony_ci s->dma_last_offset = offset; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || 2818c2ecf20Sopenharmony_ci s->type == IVTV_DEC_STREAM_TYPE_VBI)) { 2828c2ecf20Sopenharmony_ci write_dec_sync(0, s->dma_offset - IVTV_DECODER_OFFSET); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci else { 2858c2ecf20Sopenharmony_ci write_enc_sync(0, s->dma_offset); 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci if (offset) { 2888c2ecf20Sopenharmony_ci buf->bytesused -= offset; 2898c2ecf20Sopenharmony_ci memcpy(buf->buf, buf->buf + offset, buf->bytesused + offset); 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci *u32buf = cpu_to_le32(s->dma_backup); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci x++; 2948c2ecf20Sopenharmony_ci /* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */ 2958c2ecf20Sopenharmony_ci if (s->type == IVTV_ENC_STREAM_TYPE_MPG || 2968c2ecf20Sopenharmony_ci s->type == IVTV_ENC_STREAM_TYPE_VBI) 2978c2ecf20Sopenharmony_ci buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci if (buf) 3008c2ecf20Sopenharmony_ci buf->bytesused += s->dma_last_offset; 3018c2ecf20Sopenharmony_ci if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) { 3028c2ecf20Sopenharmony_ci list_for_each_entry(buf, &s->q_dma.list, list) { 3038c2ecf20Sopenharmony_ci /* Parse and Groom VBI Data */ 3048c2ecf20Sopenharmony_ci s->q_dma.bytesused -= buf->bytesused; 3058c2ecf20Sopenharmony_ci ivtv_process_vbi_data(itv, buf, 0, s->type); 3068c2ecf20Sopenharmony_ci s->q_dma.bytesused += buf->bytesused; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci if (s->fh == NULL) { 3098c2ecf20Sopenharmony_ci ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); 3108c2ecf20Sopenharmony_ci return; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (s->type == IVTV_ENC_STREAM_TYPE_PCM && 3178c2ecf20Sopenharmony_ci itv->pcm_announce_callback != NULL) { 3188c2ecf20Sopenharmony_ci /* 3198c2ecf20Sopenharmony_ci * Set up the work handler to pass the data to ivtv-alsa. 3208c2ecf20Sopenharmony_ci * 3218c2ecf20Sopenharmony_ci * We just use q_full and let the work handler race with users 3228c2ecf20Sopenharmony_ci * making ivtv-fileops.c calls on the PCM device node. 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * Users should not be using both the ALSA and V4L2 PCM audio 3258c2ecf20Sopenharmony_ci * capture interfaces at the same time. If the user does this, 3268c2ecf20Sopenharmony_ci * fragments of data will just go out each interface as they 3278c2ecf20Sopenharmony_ci * race for PCM data. 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_WORK_HANDLER_PCM, &itv->i_flags); 3308c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (s->fh) 3348c2ecf20Sopenharmony_ci wake_up(&s->waitq); 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_civoid ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct ivtv *itv = s->itv; 3408c2ecf20Sopenharmony_ci struct yuv_playback_info *yi = &itv->yuv_info; 3418c2ecf20Sopenharmony_ci u8 frame = yi->draw_frame; 3428c2ecf20Sopenharmony_ci struct yuv_frame_info *f = &yi->new_frame_info[frame]; 3438c2ecf20Sopenharmony_ci struct ivtv_buffer *buf; 3448c2ecf20Sopenharmony_ci u32 y_size = 720 * ((f->src_h + 31) & ~31); 3458c2ecf20Sopenharmony_ci u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; 3468c2ecf20Sopenharmony_ci int y_done = 0; 3478c2ecf20Sopenharmony_ci int bytes_written = 0; 3488c2ecf20Sopenharmony_ci int idx = 0; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* Insert buffer block for YUV if needed */ 3538c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) { 3548c2ecf20Sopenharmony_ci if (yi->blanking_dmaptr) { 3558c2ecf20Sopenharmony_ci s->sg_pending[idx].src = yi->blanking_dmaptr; 3568c2ecf20Sopenharmony_ci s->sg_pending[idx].dst = offset; 3578c2ecf20Sopenharmony_ci s->sg_pending[idx].size = 720 * 16; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci offset += 720 * 16; 3608c2ecf20Sopenharmony_ci idx++; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci list_for_each_entry(buf, &s->q_predma.list, list) { 3648c2ecf20Sopenharmony_ci /* YUV UV Offset from Y Buffer */ 3658c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && 3668c2ecf20Sopenharmony_ci (bytes_written + buf->bytesused) >= y_size) { 3678c2ecf20Sopenharmony_ci s->sg_pending[idx].src = buf->dma_handle; 3688c2ecf20Sopenharmony_ci s->sg_pending[idx].dst = offset; 3698c2ecf20Sopenharmony_ci s->sg_pending[idx].size = y_size - bytes_written; 3708c2ecf20Sopenharmony_ci offset = uv_offset; 3718c2ecf20Sopenharmony_ci if (s->sg_pending[idx].size != buf->bytesused) { 3728c2ecf20Sopenharmony_ci idx++; 3738c2ecf20Sopenharmony_ci s->sg_pending[idx].src = 3748c2ecf20Sopenharmony_ci buf->dma_handle + s->sg_pending[idx - 1].size; 3758c2ecf20Sopenharmony_ci s->sg_pending[idx].dst = offset; 3768c2ecf20Sopenharmony_ci s->sg_pending[idx].size = 3778c2ecf20Sopenharmony_ci buf->bytesused - s->sg_pending[idx - 1].size; 3788c2ecf20Sopenharmony_ci offset += s->sg_pending[idx].size; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci y_done = 1; 3818c2ecf20Sopenharmony_ci } else { 3828c2ecf20Sopenharmony_ci s->sg_pending[idx].src = buf->dma_handle; 3838c2ecf20Sopenharmony_ci s->sg_pending[idx].dst = offset; 3848c2ecf20Sopenharmony_ci s->sg_pending[idx].size = buf->bytesused; 3858c2ecf20Sopenharmony_ci offset += buf->bytesused; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci bytes_written += buf->bytesused; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Sync SG buffers */ 3908c2ecf20Sopenharmony_ci ivtv_buf_sync_for_device(s, buf); 3918c2ecf20Sopenharmony_ci idx++; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci s->sg_pending_size = idx; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* Sync Hardware SG List of buffers */ 3968c2ecf20Sopenharmony_ci ivtv_stream_sync_for_device(s); 3978c2ecf20Sopenharmony_ci if (lock) { 3988c2ecf20Sopenharmony_ci unsigned long flags = 0; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci spin_lock_irqsave(&itv->dma_reg_lock, flags); 4018c2ecf20Sopenharmony_ci if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) 4028c2ecf20Sopenharmony_ci ivtv_dma_dec_start(s); 4038c2ecf20Sopenharmony_ci else 4048c2ecf20Sopenharmony_ci set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); 4058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&itv->dma_reg_lock, flags); 4068c2ecf20Sopenharmony_ci } else { 4078c2ecf20Sopenharmony_ci if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) 4088c2ecf20Sopenharmony_ci ivtv_dma_dec_start(s); 4098c2ecf20Sopenharmony_ci else 4108c2ecf20Sopenharmony_ci set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic void ivtv_dma_enc_start_xfer(struct ivtv_stream *s) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci struct ivtv *itv = s->itv; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); 4198c2ecf20Sopenharmony_ci s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); 4208c2ecf20Sopenharmony_ci s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); 4218c2ecf20Sopenharmony_ci s->sg_processed++; 4228c2ecf20Sopenharmony_ci /* Sync Hardware SG List of buffers */ 4238c2ecf20Sopenharmony_ci ivtv_stream_sync_for_device(s); 4248c2ecf20Sopenharmony_ci write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR); 4258c2ecf20Sopenharmony_ci write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); 4268c2ecf20Sopenharmony_ci itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); 4278c2ecf20Sopenharmony_ci add_timer(&itv->dma_timer); 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic void ivtv_dma_dec_start_xfer(struct ivtv_stream *s) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct ivtv *itv = s->itv; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); 4358c2ecf20Sopenharmony_ci s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); 4368c2ecf20Sopenharmony_ci s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); 4378c2ecf20Sopenharmony_ci s->sg_processed++; 4388c2ecf20Sopenharmony_ci /* Sync Hardware SG List of buffers */ 4398c2ecf20Sopenharmony_ci ivtv_stream_sync_for_device(s); 4408c2ecf20Sopenharmony_ci write_reg(s->sg_handle, IVTV_REG_DECDMAADDR); 4418c2ecf20Sopenharmony_ci write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); 4428c2ecf20Sopenharmony_ci itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); 4438c2ecf20Sopenharmony_ci add_timer(&itv->dma_timer); 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/* start the encoder DMA */ 4478c2ecf20Sopenharmony_cistatic void ivtv_dma_enc_start(struct ivtv_stream *s) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct ivtv *itv = s->itv; 4508c2ecf20Sopenharmony_ci struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; 4518c2ecf20Sopenharmony_ci int i; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (s->q_predma.bytesused) 4568c2ecf20Sopenharmony_ci ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (ivtv_use_dma(s)) 4598c2ecf20Sopenharmony_ci s->sg_pending[s->sg_pending_size - 1].size += 256; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* If this is an MPEG stream, and VBI data is also pending, then append the 4628c2ecf20Sopenharmony_ci VBI DMA to the MPEG DMA and transfer both sets of data at once. 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci VBI DMA is a second class citizen compared to MPEG and mixing them together 4658c2ecf20Sopenharmony_ci will confuse the firmware (the end of a VBI DMA is seen as the end of a 4668c2ecf20Sopenharmony_ci MPEG DMA, thus effectively dropping an MPEG frame). So instead we make 4678c2ecf20Sopenharmony_ci sure we only use the MPEG DMA to transfer the VBI DMA if both are in 4688c2ecf20Sopenharmony_ci use. This way no conflicts occur. */ 4698c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); 4708c2ecf20Sopenharmony_ci if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size && 4718c2ecf20Sopenharmony_ci s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) { 4728c2ecf20Sopenharmony_ci ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused); 4738c2ecf20Sopenharmony_ci if (ivtv_use_dma(s_vbi)) 4748c2ecf20Sopenharmony_ci s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256; 4758c2ecf20Sopenharmony_ci for (i = 0; i < s_vbi->sg_pending_size; i++) { 4768c2ecf20Sopenharmony_ci s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i]; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci s_vbi->dma_offset = s_vbi->pending_offset; 4798c2ecf20Sopenharmony_ci s_vbi->sg_pending_size = 0; 4808c2ecf20Sopenharmony_ci s_vbi->dma_xfer_cnt++; 4818c2ecf20Sopenharmony_ci set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); 4828c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name); 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci s->dma_xfer_cnt++; 4868c2ecf20Sopenharmony_ci memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size); 4878c2ecf20Sopenharmony_ci s->sg_processing_size = s->sg_pending_size; 4888c2ecf20Sopenharmony_ci s->sg_pending_size = 0; 4898c2ecf20Sopenharmony_ci s->sg_processed = 0; 4908c2ecf20Sopenharmony_ci s->dma_offset = s->pending_offset; 4918c2ecf20Sopenharmony_ci s->dma_backup = s->pending_backup; 4928c2ecf20Sopenharmony_ci s->dma_pts = s->pending_pts; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (ivtv_use_pio(s)) { 4958c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags); 4968c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); 4978c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_PIO, &itv->i_flags); 4988c2ecf20Sopenharmony_ci itv->cur_pio_stream = s->type; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci else { 5018c2ecf20Sopenharmony_ci itv->dma_retries = 0; 5028c2ecf20Sopenharmony_ci ivtv_dma_enc_start_xfer(s); 5038c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_DMA, &itv->i_flags); 5048c2ecf20Sopenharmony_ci itv->cur_dma_stream = s->type; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic void ivtv_dma_dec_start(struct ivtv_stream *s) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci struct ivtv *itv = s->itv; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (s->q_predma.bytesused) 5138c2ecf20Sopenharmony_ci ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); 5148c2ecf20Sopenharmony_ci s->dma_xfer_cnt++; 5158c2ecf20Sopenharmony_ci memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size); 5168c2ecf20Sopenharmony_ci s->sg_processing_size = s->sg_pending_size; 5178c2ecf20Sopenharmony_ci s->sg_pending_size = 0; 5188c2ecf20Sopenharmony_ci s->sg_processed = 0; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name); 5218c2ecf20Sopenharmony_ci itv->dma_retries = 0; 5228c2ecf20Sopenharmony_ci ivtv_dma_dec_start_xfer(s); 5238c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_DMA, &itv->i_flags); 5248c2ecf20Sopenharmony_ci itv->cur_dma_stream = s->type; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic void ivtv_irq_dma_read(struct ivtv *itv) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct ivtv_stream *s = NULL; 5308c2ecf20Sopenharmony_ci struct ivtv_buffer *buf; 5318c2ecf20Sopenharmony_ci int hw_stream_type = 0; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_IRQ("DEC DMA READ\n"); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci del_timer(&itv->dma_timer); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0) 5388c2ecf20Sopenharmony_ci return; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { 5418c2ecf20Sopenharmony_ci s = &itv->streams[itv->cur_dma_stream]; 5428c2ecf20Sopenharmony_ci ivtv_stream_sync_for_cpu(s); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { 5458c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n", 5468c2ecf20Sopenharmony_ci read_reg(IVTV_REG_DMASTATUS), 5478c2ecf20Sopenharmony_ci s->sg_processed, s->sg_processing_size, itv->dma_retries); 5488c2ecf20Sopenharmony_ci write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); 5498c2ecf20Sopenharmony_ci if (itv->dma_retries == 3) { 5508c2ecf20Sopenharmony_ci /* Too many retries, give up on this frame */ 5518c2ecf20Sopenharmony_ci itv->dma_retries = 0; 5528c2ecf20Sopenharmony_ci s->sg_processed = s->sg_processing_size; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci else { 5558c2ecf20Sopenharmony_ci /* Retry, starting with the first xfer segment. 5568c2ecf20Sopenharmony_ci Just retrying the current segment is not sufficient. */ 5578c2ecf20Sopenharmony_ci s->sg_processed = 0; 5588c2ecf20Sopenharmony_ci itv->dma_retries++; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci if (s->sg_processed < s->sg_processing_size) { 5628c2ecf20Sopenharmony_ci /* DMA next buffer */ 5638c2ecf20Sopenharmony_ci ivtv_dma_dec_start_xfer(s); 5648c2ecf20Sopenharmony_ci return; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_YUV) 5678c2ecf20Sopenharmony_ci hw_stream_type = 2; 5688c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* For some reason must kick the firmware, like PIO mode, 5718c2ecf20Sopenharmony_ci I think this tells the firmware we are done and the size 5728c2ecf20Sopenharmony_ci of the xfer so it can calculate what we need next. 5738c2ecf20Sopenharmony_ci I think we can do this part ourselves but would have to 5748c2ecf20Sopenharmony_ci fully calculate xfer info ourselves and not use interrupts 5758c2ecf20Sopenharmony_ci */ 5768c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, s->q_dma.bytesused, 5778c2ecf20Sopenharmony_ci hw_stream_type); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* Free last DMA call */ 5808c2ecf20Sopenharmony_ci while ((buf = ivtv_dequeue(s, &s->q_dma)) != NULL) { 5818c2ecf20Sopenharmony_ci ivtv_buf_sync_for_cpu(s, buf); 5828c2ecf20Sopenharmony_ci ivtv_enqueue(s, buf, &s->q_free); 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci wake_up(&s->waitq); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_UDMA, &itv->i_flags); 5878c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_DMA, &itv->i_flags); 5888c2ecf20Sopenharmony_ci itv->cur_dma_stream = -1; 5898c2ecf20Sopenharmony_ci wake_up(&itv->dma_waitq); 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic void ivtv_irq_enc_dma_complete(struct ivtv *itv) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci u32 data[CX2341X_MBOX_MAX_DATA]; 5958c2ecf20Sopenharmony_ci struct ivtv_stream *s; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data); 5988c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci del_timer(&itv->dma_timer); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (itv->cur_dma_stream < 0) 6038c2ecf20Sopenharmony_ci return; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci s = &itv->streams[itv->cur_dma_stream]; 6068c2ecf20Sopenharmony_ci ivtv_stream_sync_for_cpu(s); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (data[0] & 0x18) { 6098c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0], 6108c2ecf20Sopenharmony_ci s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries); 6118c2ecf20Sopenharmony_ci write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); 6128c2ecf20Sopenharmony_ci if (itv->dma_retries == 3) { 6138c2ecf20Sopenharmony_ci /* Too many retries, give up on this frame */ 6148c2ecf20Sopenharmony_ci itv->dma_retries = 0; 6158c2ecf20Sopenharmony_ci s->sg_processed = s->sg_processing_size; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci else { 6188c2ecf20Sopenharmony_ci /* Retry, starting with the first xfer segment. 6198c2ecf20Sopenharmony_ci Just retrying the current segment is not sufficient. */ 6208c2ecf20Sopenharmony_ci s->sg_processed = 0; 6218c2ecf20Sopenharmony_ci itv->dma_retries++; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci if (s->sg_processed < s->sg_processing_size) { 6258c2ecf20Sopenharmony_ci /* DMA next buffer */ 6268c2ecf20Sopenharmony_ci ivtv_dma_enc_start_xfer(s); 6278c2ecf20Sopenharmony_ci return; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_DMA, &itv->i_flags); 6308c2ecf20Sopenharmony_ci itv->cur_dma_stream = -1; 6318c2ecf20Sopenharmony_ci dma_post(s); 6328c2ecf20Sopenharmony_ci if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { 6338c2ecf20Sopenharmony_ci s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; 6348c2ecf20Sopenharmony_ci dma_post(s); 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci s->sg_processing_size = 0; 6378c2ecf20Sopenharmony_ci s->sg_processed = 0; 6388c2ecf20Sopenharmony_ci wake_up(&itv->dma_waitq); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic void ivtv_irq_enc_pio_complete(struct ivtv *itv) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct ivtv_stream *s; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS) { 6468c2ecf20Sopenharmony_ci itv->cur_pio_stream = -1; 6478c2ecf20Sopenharmony_ci return; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci s = &itv->streams[itv->cur_pio_stream]; 6508c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name); 6518c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_PIO, &itv->i_flags); 6528c2ecf20Sopenharmony_ci itv->cur_pio_stream = -1; 6538c2ecf20Sopenharmony_ci dma_post(s); 6548c2ecf20Sopenharmony_ci if (s->type == IVTV_ENC_STREAM_TYPE_MPG) 6558c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 0); 6568c2ecf20Sopenharmony_ci else if (s->type == IVTV_ENC_STREAM_TYPE_YUV) 6578c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 1); 6588c2ecf20Sopenharmony_ci else if (s->type == IVTV_ENC_STREAM_TYPE_PCM) 6598c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2); 6608c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_PIO, &itv->i_flags); 6618c2ecf20Sopenharmony_ci if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { 6628c2ecf20Sopenharmony_ci s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; 6638c2ecf20Sopenharmony_ci dma_post(s); 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci wake_up(&itv->dma_waitq); 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic void ivtv_irq_dma_err(struct ivtv *itv) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci u32 data[CX2341X_MBOX_MAX_DATA]; 6718c2ecf20Sopenharmony_ci u32 status; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci del_timer(&itv->dma_timer); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data); 6768c2ecf20Sopenharmony_ci status = read_reg(IVTV_REG_DMASTATUS); 6778c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1], 6788c2ecf20Sopenharmony_ci status, itv->cur_dma_stream); 6798c2ecf20Sopenharmony_ci /* 6808c2ecf20Sopenharmony_ci * We do *not* write back to the IVTV_REG_DMASTATUS register to 6818c2ecf20Sopenharmony_ci * clear the error status, if either the encoder write (0x02) or 6828c2ecf20Sopenharmony_ci * decoder read (0x01) bus master DMA operation do not indicate 6838c2ecf20Sopenharmony_ci * completed. We can race with the DMA engine, which may have 6848c2ecf20Sopenharmony_ci * transitioned to completed status *after* we read the register. 6858c2ecf20Sopenharmony_ci * Setting a IVTV_REG_DMASTATUS flag back to "busy" status, after the 6868c2ecf20Sopenharmony_ci * DMA engine has completed, will cause the DMA engine to stop working. 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_ci status &= 0x3; 6898c2ecf20Sopenharmony_ci if (status == 0x3) 6908c2ecf20Sopenharmony_ci write_reg(status, IVTV_REG_DMASTATUS); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && 6938c2ecf20Sopenharmony_ci itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) { 6948c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream]; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { 6978c2ecf20Sopenharmony_ci /* retry */ 6988c2ecf20Sopenharmony_ci /* 6998c2ecf20Sopenharmony_ci * FIXME - handle cases of DMA error similar to 7008c2ecf20Sopenharmony_ci * encoder below, except conditioned on status & 0x1 7018c2ecf20Sopenharmony_ci */ 7028c2ecf20Sopenharmony_ci ivtv_dma_dec_start(s); 7038c2ecf20Sopenharmony_ci return; 7048c2ecf20Sopenharmony_ci } else { 7058c2ecf20Sopenharmony_ci if ((status & 0x2) == 0) { 7068c2ecf20Sopenharmony_ci /* 7078c2ecf20Sopenharmony_ci * CX2341x Bus Master DMA write is ongoing. 7088c2ecf20Sopenharmony_ci * Reset the timer and let it complete. 7098c2ecf20Sopenharmony_ci */ 7108c2ecf20Sopenharmony_ci itv->dma_timer.expires = 7118c2ecf20Sopenharmony_ci jiffies + msecs_to_jiffies(600); 7128c2ecf20Sopenharmony_ci add_timer(&itv->dma_timer); 7138c2ecf20Sopenharmony_ci return; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (itv->dma_retries < 3) { 7178c2ecf20Sopenharmony_ci /* 7188c2ecf20Sopenharmony_ci * CX2341x Bus Master DMA write has ended. 7198c2ecf20Sopenharmony_ci * Retry the write, starting with the first 7208c2ecf20Sopenharmony_ci * xfer segment. Just retrying the current 7218c2ecf20Sopenharmony_ci * segment is not sufficient. 7228c2ecf20Sopenharmony_ci */ 7238c2ecf20Sopenharmony_ci s->sg_processed = 0; 7248c2ecf20Sopenharmony_ci itv->dma_retries++; 7258c2ecf20Sopenharmony_ci ivtv_dma_enc_start_xfer(s); 7268c2ecf20Sopenharmony_ci return; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci /* Too many retries, give up on this one */ 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { 7338c2ecf20Sopenharmony_ci ivtv_udma_start(itv); 7348c2ecf20Sopenharmony_ci return; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_UDMA, &itv->i_flags); 7378c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_DMA, &itv->i_flags); 7388c2ecf20Sopenharmony_ci itv->cur_dma_stream = -1; 7398c2ecf20Sopenharmony_ci wake_up(&itv->dma_waitq); 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic void ivtv_irq_enc_start_cap(struct ivtv *itv) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci u32 data[CX2341X_MBOX_MAX_DATA]; 7458c2ecf20Sopenharmony_ci struct ivtv_stream *s; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* Get DMA destination and size arguments from card */ 7488c2ecf20Sopenharmony_ci ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, 7, data); 7498c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (data[0] > 2 || data[1] == 0 || data[2] == 0) { 7528c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n", 7538c2ecf20Sopenharmony_ci data[0], data[1], data[2]); 7548c2ecf20Sopenharmony_ci return; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci s = &itv->streams[ivtv_stream_map[data[0]]]; 7578c2ecf20Sopenharmony_ci if (!stream_enc_dma_append(s, data)) { 7588c2ecf20Sopenharmony_ci set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags); 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic void ivtv_irq_enc_vbi_cap(struct ivtv *itv) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci u32 data[CX2341X_MBOX_MAX_DATA]; 7658c2ecf20Sopenharmony_ci struct ivtv_stream *s; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n"); 7688c2ecf20Sopenharmony_ci s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (!stream_enc_dma_append(s, data)) 7718c2ecf20Sopenharmony_ci set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags); 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci u32 data[CX2341X_MBOX_MAX_DATA]; 7778c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n"); 7808c2ecf20Sopenharmony_ci if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) && 7818c2ecf20Sopenharmony_ci !stream_enc_dma_append(s, data)) { 7828c2ecf20Sopenharmony_ci set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags); 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic void ivtv_irq_dec_data_req(struct ivtv *itv) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci u32 data[CX2341X_MBOX_MAX_DATA]; 7898c2ecf20Sopenharmony_ci struct ivtv_stream *s; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci /* YUV or MPG */ 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { 7948c2ecf20Sopenharmony_ci ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data); 7958c2ecf20Sopenharmony_ci itv->dma_data_req_size = 7968c2ecf20Sopenharmony_ci 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); 7978c2ecf20Sopenharmony_ci itv->dma_data_req_offset = data[1]; 7988c2ecf20Sopenharmony_ci if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0) 7998c2ecf20Sopenharmony_ci ivtv_yuv_frame_complete(itv); 8008c2ecf20Sopenharmony_ci s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci else { 8038c2ecf20Sopenharmony_ci ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 3, data); 8048c2ecf20Sopenharmony_ci itv->dma_data_req_size = min_t(u32, data[2], 0x10000); 8058c2ecf20Sopenharmony_ci itv->dma_data_req_offset = data[1]; 8068c2ecf20Sopenharmony_ci s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused, 8098c2ecf20Sopenharmony_ci itv->dma_data_req_offset, itv->dma_data_req_size); 8108c2ecf20Sopenharmony_ci if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) { 8118c2ecf20Sopenharmony_ci set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci else { 8148c2ecf20Sopenharmony_ci if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) 8158c2ecf20Sopenharmony_ci ivtv_yuv_setup_stream_frame(itv); 8168c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); 8178c2ecf20Sopenharmony_ci ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); 8188c2ecf20Sopenharmony_ci ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0); 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic void ivtv_irq_vsync(struct ivtv *itv) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci /* The vsync interrupt is unusual in that it won't clear until 8258c2ecf20Sopenharmony_ci * the end of the first line for the current field, at which 8268c2ecf20Sopenharmony_ci * point it clears itself. This can result in repeated vsync 8278c2ecf20Sopenharmony_ci * interrupts, or a missed vsync. Read some of the registers 8288c2ecf20Sopenharmony_ci * to determine the line being displayed and ensure we handle 8298c2ecf20Sopenharmony_ci * one vsync per frame. 8308c2ecf20Sopenharmony_ci */ 8318c2ecf20Sopenharmony_ci unsigned int frame = read_reg(IVTV_REG_DEC_LINE_FIELD) & 1; 8328c2ecf20Sopenharmony_ci struct yuv_playback_info *yi = &itv->yuv_info; 8338c2ecf20Sopenharmony_ci int last_dma_frame = atomic_read(&yi->next_dma_frame); 8348c2ecf20Sopenharmony_ci struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame]; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (((frame ^ f->sync_field) == 0 && 8398c2ecf20Sopenharmony_ci ((itv->last_vsync_field & 1) ^ f->sync_field)) || 8408c2ecf20Sopenharmony_ci (frame != (itv->last_vsync_field & 1) && !f->interlaced)) { 8418c2ecf20Sopenharmony_ci int next_dma_frame = last_dma_frame; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) { 8448c2ecf20Sopenharmony_ci if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) { 8458c2ecf20Sopenharmony_ci write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); 8468c2ecf20Sopenharmony_ci write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); 8478c2ecf20Sopenharmony_ci write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); 8488c2ecf20Sopenharmony_ci write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); 8498c2ecf20Sopenharmony_ci next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS; 8508c2ecf20Sopenharmony_ci atomic_set(&yi->next_dma_frame, next_dma_frame); 8518c2ecf20Sopenharmony_ci yi->fields_lapsed = -1; 8528c2ecf20Sopenharmony_ci yi->running = 1; 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci if (frame != (itv->last_vsync_field & 1)) { 8578c2ecf20Sopenharmony_ci static const struct v4l2_event evtop = { 8588c2ecf20Sopenharmony_ci .type = V4L2_EVENT_VSYNC, 8598c2ecf20Sopenharmony_ci .u.vsync.field = V4L2_FIELD_TOP, 8608c2ecf20Sopenharmony_ci }; 8618c2ecf20Sopenharmony_ci static const struct v4l2_event evbottom = { 8628c2ecf20Sopenharmony_ci .type = V4L2_EVENT_VSYNC, 8638c2ecf20Sopenharmony_ci .u.vsync.field = V4L2_FIELD_BOTTOM, 8648c2ecf20Sopenharmony_ci }; 8658c2ecf20Sopenharmony_ci struct ivtv_stream *s = ivtv_get_output_stream(itv); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci itv->last_vsync_field += 1; 8688c2ecf20Sopenharmony_ci if (frame == 0) { 8698c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); 8708c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci else { 8738c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci if (test_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags)) { 8768c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags); 8778c2ecf20Sopenharmony_ci wake_up(&itv->event_waitq); 8788c2ecf20Sopenharmony_ci if (s) 8798c2ecf20Sopenharmony_ci wake_up(&s->waitq); 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci if (s && s->vdev.v4l2_dev) 8828c2ecf20Sopenharmony_ci v4l2_event_queue(&s->vdev, frame ? &evtop : &evbottom); 8838c2ecf20Sopenharmony_ci wake_up(&itv->vsync_waitq); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci /* Send VBI to saa7127 */ 8868c2ecf20Sopenharmony_ci if (frame && (itv->output_mode == OUT_PASSTHROUGH || 8878c2ecf20Sopenharmony_ci test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) || 8888c2ecf20Sopenharmony_ci test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) || 8898c2ecf20Sopenharmony_ci test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) { 8908c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags); 8918c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* Check if we need to update the yuv registers */ 8958c2ecf20Sopenharmony_ci if (yi->running && (yi->yuv_forced_update || f->update)) { 8968c2ecf20Sopenharmony_ci if (!f->update) { 8978c2ecf20Sopenharmony_ci last_dma_frame = 8988c2ecf20Sopenharmony_ci (u8)(atomic_read(&yi->next_dma_frame) - 8998c2ecf20Sopenharmony_ci 1) % IVTV_YUV_BUFFERS; 9008c2ecf20Sopenharmony_ci f = &yi->new_frame_info[last_dma_frame]; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (f->src_w) { 9048c2ecf20Sopenharmony_ci yi->update_frame = last_dma_frame; 9058c2ecf20Sopenharmony_ci f->update = 0; 9068c2ecf20Sopenharmony_ci yi->yuv_forced_update = 0; 9078c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags); 9088c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci yi->fields_lapsed++; 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_VBI_RE_INSERT) 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ciirqreturn_t ivtv_irq_handler(int irq, void *dev_id) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci struct ivtv *itv = (struct ivtv *)dev_id; 9218c2ecf20Sopenharmony_ci u32 combo; 9228c2ecf20Sopenharmony_ci u32 stat; 9238c2ecf20Sopenharmony_ci int i; 9248c2ecf20Sopenharmony_ci u8 vsync_force = 0; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci spin_lock(&itv->dma_reg_lock); 9278c2ecf20Sopenharmony_ci /* get contents of irq status register */ 9288c2ecf20Sopenharmony_ci stat = read_reg(IVTV_REG_IRQSTATUS); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci combo = ~itv->irqmask & stat; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci /* Clear out IRQ */ 9338c2ecf20Sopenharmony_ci if (combo) write_reg(combo, IVTV_REG_IRQSTATUS); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (0 == combo) { 9368c2ecf20Sopenharmony_ci /* The vsync interrupt is unusual and clears itself. If we 9378c2ecf20Sopenharmony_ci * took too long, we may have missed it. Do some checks 9388c2ecf20Sopenharmony_ci */ 9398c2ecf20Sopenharmony_ci if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { 9408c2ecf20Sopenharmony_ci /* vsync is enabled, see if we're in a new field */ 9418c2ecf20Sopenharmony_ci if ((itv->last_vsync_field & 1) != 9428c2ecf20Sopenharmony_ci (read_reg(IVTV_REG_DEC_LINE_FIELD) & 1)) { 9438c2ecf20Sopenharmony_ci /* New field, looks like we missed it */ 9448c2ecf20Sopenharmony_ci IVTV_DEBUG_YUV("VSync interrupt missed %d\n", 9458c2ecf20Sopenharmony_ci read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16); 9468c2ecf20Sopenharmony_ci vsync_force = 1; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci if (!vsync_force) { 9518c2ecf20Sopenharmony_ci /* No Vsync expected, wasn't for us */ 9528c2ecf20Sopenharmony_ci spin_unlock(&itv->dma_reg_lock); 9538c2ecf20Sopenharmony_ci return IRQ_NONE; 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci /* Exclude interrupts noted below from the output, otherwise the log is flooded with 9588c2ecf20Sopenharmony_ci these messages */ 9598c2ecf20Sopenharmony_ci if (combo & ~0xff6d0400) 9608c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) { 9638c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n"); 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci if (combo & IVTV_IRQ_DMA_READ) { 9678c2ecf20Sopenharmony_ci ivtv_irq_dma_read(itv); 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) { 9718c2ecf20Sopenharmony_ci ivtv_irq_enc_dma_complete(itv); 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (combo & IVTV_IRQ_ENC_PIO_COMPLETE) { 9758c2ecf20Sopenharmony_ci ivtv_irq_enc_pio_complete(itv); 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci if (combo & IVTV_IRQ_DMA_ERR) { 9798c2ecf20Sopenharmony_ci ivtv_irq_dma_err(itv); 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (combo & IVTV_IRQ_ENC_START_CAP) { 9838c2ecf20Sopenharmony_ci ivtv_irq_enc_start_cap(itv); 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (combo & IVTV_IRQ_ENC_VBI_CAP) { 9878c2ecf20Sopenharmony_ci ivtv_irq_enc_vbi_cap(itv); 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) { 9918c2ecf20Sopenharmony_ci ivtv_irq_dec_vbi_reinsert(itv); 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (combo & IVTV_IRQ_ENC_EOS) { 9958c2ecf20Sopenharmony_ci IVTV_DEBUG_IRQ("ENC EOS\n"); 9968c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_EOS, &itv->i_flags); 9978c2ecf20Sopenharmony_ci wake_up(&itv->eos_waitq); 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (combo & IVTV_IRQ_DEC_DATA_REQ) { 10018c2ecf20Sopenharmony_ci ivtv_irq_dec_data_req(itv); 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci /* Decoder Vertical Sync - We can't rely on 'combo', so check if vsync enabled */ 10058c2ecf20Sopenharmony_ci if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { 10068c2ecf20Sopenharmony_ci ivtv_irq_vsync(itv); 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (combo & IVTV_IRQ_ENC_VIM_RST) { 10108c2ecf20Sopenharmony_ci IVTV_DEBUG_IRQ("VIM RST\n"); 10118c2ecf20Sopenharmony_ci /*ivtv_vapi(itv, CX2341X_ENC_REFRESH_INPUT, 0); */ 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) { 10158c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("Stereo mode changed\n"); 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) { 10198c2ecf20Sopenharmony_ci itv->irq_rr_idx++; 10208c2ecf20Sopenharmony_ci for (i = 0; i < IVTV_MAX_STREAMS; i++) { 10218c2ecf20Sopenharmony_ci int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; 10228c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[idx]; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) 10258c2ecf20Sopenharmony_ci continue; 10268c2ecf20Sopenharmony_ci if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) 10278c2ecf20Sopenharmony_ci ivtv_dma_dec_start(s); 10288c2ecf20Sopenharmony_ci else 10298c2ecf20Sopenharmony_ci ivtv_dma_enc_start(s); 10308c2ecf20Sopenharmony_ci break; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (i == IVTV_MAX_STREAMS && 10348c2ecf20Sopenharmony_ci test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) 10358c2ecf20Sopenharmony_ci ivtv_udma_start(itv); 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) { 10398c2ecf20Sopenharmony_ci itv->irq_rr_idx++; 10408c2ecf20Sopenharmony_ci for (i = 0; i < IVTV_MAX_STREAMS; i++) { 10418c2ecf20Sopenharmony_ci int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; 10428c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[idx]; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags)) 10458c2ecf20Sopenharmony_ci continue; 10468c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type < IVTV_DEC_STREAM_TYPE_MPG) 10478c2ecf20Sopenharmony_ci ivtv_dma_enc_start(s); 10488c2ecf20Sopenharmony_ci break; 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) { 10538c2ecf20Sopenharmony_ci kthread_queue_work(&itv->irq_worker, &itv->irq_work); 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci spin_unlock(&itv->dma_reg_lock); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci /* If we've just handled a 'forced' vsync, it's safest to say it 10598c2ecf20Sopenharmony_ci * wasn't ours. Another device may have triggered it at just 10608c2ecf20Sopenharmony_ci * the right time. 10618c2ecf20Sopenharmony_ci */ 10628c2ecf20Sopenharmony_ci return vsync_force ? IRQ_NONE : IRQ_HANDLED; 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_civoid ivtv_unfinished_dma(struct timer_list *t) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci struct ivtv *itv = from_timer(itv, t, dma_timer); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) 10708c2ecf20Sopenharmony_ci return; 10718c2ecf20Sopenharmony_ci IVTV_ERR("DMA TIMEOUT %08x %d\n", read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); 10748c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_UDMA, &itv->i_flags); 10758c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_DMA, &itv->i_flags); 10768c2ecf20Sopenharmony_ci itv->cur_dma_stream = -1; 10778c2ecf20Sopenharmony_ci wake_up(&itv->dma_waitq); 10788c2ecf20Sopenharmony_ci} 1079