18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci */ 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include "cx88.h" 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistatic unsigned int vbi_debug; 128c2ecf20Sopenharmony_cimodule_param(vbi_debug, int, 0644); 138c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define dprintk(level, fmt, arg...) do { \ 168c2ecf20Sopenharmony_ci if (vbi_debug >= level) \ 178c2ecf20Sopenharmony_ci printk(KERN_DEBUG pr_fmt("%s: vbi:" fmt), \ 188c2ecf20Sopenharmony_ci __func__, ##arg); \ 198c2ecf20Sopenharmony_ci} while (0) 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciint cx8800_vbi_fmt(struct file *file, void *priv, 248c2ecf20Sopenharmony_ci struct v4l2_format *f) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct cx8800_dev *dev = video_drvdata(file); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; 298c2ecf20Sopenharmony_ci f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; 308c2ecf20Sopenharmony_ci f->fmt.vbi.offset = 244; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (dev->core->tvnorm & V4L2_STD_525_60) { 338c2ecf20Sopenharmony_ci /* ntsc */ 348c2ecf20Sopenharmony_ci f->fmt.vbi.sampling_rate = 28636363; 358c2ecf20Sopenharmony_ci f->fmt.vbi.start[0] = 10; 368c2ecf20Sopenharmony_ci f->fmt.vbi.start[1] = 273; 378c2ecf20Sopenharmony_ci f->fmt.vbi.count[0] = VBI_LINE_NTSC_COUNT; 388c2ecf20Sopenharmony_ci f->fmt.vbi.count[1] = VBI_LINE_NTSC_COUNT; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci } else if (dev->core->tvnorm & V4L2_STD_625_50) { 418c2ecf20Sopenharmony_ci /* pal */ 428c2ecf20Sopenharmony_ci f->fmt.vbi.sampling_rate = 35468950; 438c2ecf20Sopenharmony_ci f->fmt.vbi.start[0] = V4L2_VBI_ITU_625_F1_START + 5; 448c2ecf20Sopenharmony_ci f->fmt.vbi.start[1] = V4L2_VBI_ITU_625_F2_START + 5; 458c2ecf20Sopenharmony_ci f->fmt.vbi.count[0] = VBI_LINE_PAL_COUNT; 468c2ecf20Sopenharmony_ci f->fmt.vbi.count[1] = VBI_LINE_PAL_COUNT; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci return 0; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int cx8800_start_vbi_dma(struct cx8800_dev *dev, 528c2ecf20Sopenharmony_ci struct cx88_dmaqueue *q, 538c2ecf20Sopenharmony_ci struct cx88_buffer *buf) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct cx88_core *core = dev->core; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* setup fifo + format */ 588c2ecf20Sopenharmony_ci cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH24], 598c2ecf20Sopenharmony_ci VBI_LINE_LENGTH, buf->risc.dma); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci cx_write(MO_VBOS_CONTROL, (1 << 18) | /* comb filter delay fixup */ 628c2ecf20Sopenharmony_ci (1 << 15) | /* enable vbi capture */ 638c2ecf20Sopenharmony_ci (1 << 11)); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* reset counter */ 668c2ecf20Sopenharmony_ci cx_write(MO_VBI_GPCNTRL, GP_COUNT_CONTROL_RESET); 678c2ecf20Sopenharmony_ci q->count = 0; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* enable irqs */ 708c2ecf20Sopenharmony_ci cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); 718c2ecf20Sopenharmony_ci cx_set(MO_VID_INTMSK, 0x0f0088); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* enable capture */ 748c2ecf20Sopenharmony_ci cx_set(VID_CAPTURE_CONTROL, 0x18); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* start dma */ 778c2ecf20Sopenharmony_ci cx_set(MO_DEV_CNTRL2, (1 << 5)); 788c2ecf20Sopenharmony_ci cx_set(MO_VID_DMACNTRL, 0x88); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return 0; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_civoid cx8800_stop_vbi_dma(struct cx8800_dev *dev) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct cx88_core *core = dev->core; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* stop dma */ 888c2ecf20Sopenharmony_ci cx_clear(MO_VID_DMACNTRL, 0x88); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* disable capture */ 918c2ecf20Sopenharmony_ci cx_clear(VID_CAPTURE_CONTROL, 0x18); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* disable irqs */ 948c2ecf20Sopenharmony_ci cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); 958c2ecf20Sopenharmony_ci cx_clear(MO_VID_INTMSK, 0x0f0088); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ciint cx8800_restart_vbi_queue(struct cx8800_dev *dev, 998c2ecf20Sopenharmony_ci struct cx88_dmaqueue *q) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct cx88_buffer *buf; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (list_empty(&q->active)) 1048c2ecf20Sopenharmony_ci return 0; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci buf = list_entry(q->active.next, struct cx88_buffer, list); 1078c2ecf20Sopenharmony_ci dprintk(2, "restart_queue [%p/%d]: restart dma\n", 1088c2ecf20Sopenharmony_ci buf, buf->vb.vb2_buf.index); 1098c2ecf20Sopenharmony_ci cx8800_start_vbi_dma(dev, q, buf); 1108c2ecf20Sopenharmony_ci return 0; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */ 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int queue_setup(struct vb2_queue *q, 1168c2ecf20Sopenharmony_ci unsigned int *num_buffers, unsigned int *num_planes, 1178c2ecf20Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct cx8800_dev *dev = q->drv_priv; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci *num_planes = 1; 1228c2ecf20Sopenharmony_ci if (dev->core->tvnorm & V4L2_STD_525_60) 1238c2ecf20Sopenharmony_ci sizes[0] = VBI_LINE_NTSC_COUNT * VBI_LINE_LENGTH * 2; 1248c2ecf20Sopenharmony_ci else 1258c2ecf20Sopenharmony_ci sizes[0] = VBI_LINE_PAL_COUNT * VBI_LINE_LENGTH * 2; 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int buffer_prepare(struct vb2_buffer *vb) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1328c2ecf20Sopenharmony_ci struct cx8800_dev *dev = vb->vb2_queue->drv_priv; 1338c2ecf20Sopenharmony_ci struct cx88_buffer *buf = container_of(vbuf, struct cx88_buffer, vb); 1348c2ecf20Sopenharmony_ci struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); 1358c2ecf20Sopenharmony_ci unsigned int lines; 1368c2ecf20Sopenharmony_ci unsigned int size; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (dev->core->tvnorm & V4L2_STD_525_60) 1398c2ecf20Sopenharmony_ci lines = VBI_LINE_NTSC_COUNT; 1408c2ecf20Sopenharmony_ci else 1418c2ecf20Sopenharmony_ci lines = VBI_LINE_PAL_COUNT; 1428c2ecf20Sopenharmony_ci size = lines * VBI_LINE_LENGTH * 2; 1438c2ecf20Sopenharmony_ci if (vb2_plane_size(vb, 0) < size) 1448c2ecf20Sopenharmony_ci return -EINVAL; 1458c2ecf20Sopenharmony_ci vb2_set_plane_payload(vb, 0, size); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return cx88_risc_buffer(dev->pci, &buf->risc, sgt->sgl, 1488c2ecf20Sopenharmony_ci 0, VBI_LINE_LENGTH * lines, 1498c2ecf20Sopenharmony_ci VBI_LINE_LENGTH, 0, 1508c2ecf20Sopenharmony_ci lines); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic void buffer_finish(struct vb2_buffer *vb) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1568c2ecf20Sopenharmony_ci struct cx8800_dev *dev = vb->vb2_queue->drv_priv; 1578c2ecf20Sopenharmony_ci struct cx88_buffer *buf = container_of(vbuf, struct cx88_buffer, vb); 1588c2ecf20Sopenharmony_ci struct cx88_riscmem *risc = &buf->risc; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (risc->cpu) 1618c2ecf20Sopenharmony_ci pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma); 1628c2ecf20Sopenharmony_ci memset(risc, 0, sizeof(*risc)); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void buffer_queue(struct vb2_buffer *vb) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1688c2ecf20Sopenharmony_ci struct cx8800_dev *dev = vb->vb2_queue->drv_priv; 1698c2ecf20Sopenharmony_ci struct cx88_buffer *buf = container_of(vbuf, struct cx88_buffer, vb); 1708c2ecf20Sopenharmony_ci struct cx88_buffer *prev; 1718c2ecf20Sopenharmony_ci struct cx88_dmaqueue *q = &dev->vbiq; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* add jump to start */ 1748c2ecf20Sopenharmony_ci buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 8); 1758c2ecf20Sopenharmony_ci buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC); 1768c2ecf20Sopenharmony_ci buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 8); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (list_empty(&q->active)) { 1798c2ecf20Sopenharmony_ci list_add_tail(&buf->list, &q->active); 1808c2ecf20Sopenharmony_ci dprintk(2, "[%p/%d] vbi_queue - first active\n", 1818c2ecf20Sopenharmony_ci buf, buf->vb.vb2_buf.index); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci } else { 1848c2ecf20Sopenharmony_ci buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); 1858c2ecf20Sopenharmony_ci prev = list_entry(q->active.prev, struct cx88_buffer, list); 1868c2ecf20Sopenharmony_ci list_add_tail(&buf->list, &q->active); 1878c2ecf20Sopenharmony_ci prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); 1888c2ecf20Sopenharmony_ci dprintk(2, "[%p/%d] buffer_queue - append to active\n", 1898c2ecf20Sopenharmony_ci buf, buf->vb.vb2_buf.index); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int start_streaming(struct vb2_queue *q, unsigned int count) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct cx8800_dev *dev = q->drv_priv; 1968c2ecf20Sopenharmony_ci struct cx88_dmaqueue *dmaq = &dev->vbiq; 1978c2ecf20Sopenharmony_ci struct cx88_buffer *buf = list_entry(dmaq->active.next, 1988c2ecf20Sopenharmony_ci struct cx88_buffer, list); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci cx8800_start_vbi_dma(dev, dmaq, buf); 2018c2ecf20Sopenharmony_ci return 0; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void stop_streaming(struct vb2_queue *q) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct cx8800_dev *dev = q->drv_priv; 2078c2ecf20Sopenharmony_ci struct cx88_core *core = dev->core; 2088c2ecf20Sopenharmony_ci struct cx88_dmaqueue *dmaq = &dev->vbiq; 2098c2ecf20Sopenharmony_ci unsigned long flags; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci cx_clear(MO_VID_DMACNTRL, 0x11); 2128c2ecf20Sopenharmony_ci cx_clear(VID_CAPTURE_CONTROL, 0x06); 2138c2ecf20Sopenharmony_ci cx8800_stop_vbi_dma(dev); 2148c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->slock, flags); 2158c2ecf20Sopenharmony_ci while (!list_empty(&dmaq->active)) { 2168c2ecf20Sopenharmony_ci struct cx88_buffer *buf = list_entry(dmaq->active.next, 2178c2ecf20Sopenharmony_ci struct cx88_buffer, list); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci list_del(&buf->list); 2208c2ecf20Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->slock, flags); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ciconst struct vb2_ops cx8800_vbi_qops = { 2268c2ecf20Sopenharmony_ci .queue_setup = queue_setup, 2278c2ecf20Sopenharmony_ci .buf_prepare = buffer_prepare, 2288c2ecf20Sopenharmony_ci .buf_finish = buffer_finish, 2298c2ecf20Sopenharmony_ci .buf_queue = buffer_queue, 2308c2ecf20Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 2318c2ecf20Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 2328c2ecf20Sopenharmony_ci .start_streaming = start_streaming, 2338c2ecf20Sopenharmony_ci .stop_streaming = stop_streaming, 2348c2ecf20Sopenharmony_ci}; 235