18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * cobalt V4L2 API 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Derived from ivtv-ioctl.c and cx18-fileops.c 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. 88c2ecf20Sopenharmony_ci * All rights reserved. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/math64.h> 148c2ecf20Sopenharmony_ci#include <linux/pci.h> 158c2ecf20Sopenharmony_ci#include <linux/v4l2-dv-timings.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 188c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 198c2ecf20Sopenharmony_ci#include <media/v4l2-dv-timings.h> 208c2ecf20Sopenharmony_ci#include <media/i2c/adv7604.h> 218c2ecf20Sopenharmony_ci#include <media/i2c/adv7842.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "cobalt-alsa.h" 248c2ecf20Sopenharmony_ci#include "cobalt-cpld.h" 258c2ecf20Sopenharmony_ci#include "cobalt-driver.h" 268c2ecf20Sopenharmony_ci#include "cobalt-v4l2.h" 278c2ecf20Sopenharmony_ci#include "cobalt-irq.h" 288c2ecf20Sopenharmony_ci#include "cobalt-omnitek.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic const struct v4l2_dv_timings cea1080p60 = V4L2_DV_BT_CEA_1920X1080P60; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* vb2 DMA streaming ops */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int cobalt_queue_setup(struct vb2_queue *q, 358c2ecf20Sopenharmony_ci unsigned int *num_buffers, unsigned int *num_planes, 368c2ecf20Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct cobalt_stream *s = q->drv_priv; 398c2ecf20Sopenharmony_ci unsigned size = s->stride * s->height; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (*num_buffers < 3) 428c2ecf20Sopenharmony_ci *num_buffers = 3; 438c2ecf20Sopenharmony_ci if (*num_buffers > NR_BUFS) 448c2ecf20Sopenharmony_ci *num_buffers = NR_BUFS; 458c2ecf20Sopenharmony_ci if (*num_planes) 468c2ecf20Sopenharmony_ci return sizes[0] < size ? -EINVAL : 0; 478c2ecf20Sopenharmony_ci *num_planes = 1; 488c2ecf20Sopenharmony_ci sizes[0] = size; 498c2ecf20Sopenharmony_ci return 0; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int cobalt_buf_init(struct vb2_buffer *vb) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci struct cobalt_stream *s = vb->vb2_queue->drv_priv; 558c2ecf20Sopenharmony_ci struct cobalt *cobalt = s->cobalt; 568c2ecf20Sopenharmony_ci const size_t max_pages_per_line = 578c2ecf20Sopenharmony_ci (COBALT_MAX_WIDTH * COBALT_MAX_BPP) / PAGE_SIZE + 2; 588c2ecf20Sopenharmony_ci const size_t bytes = 598c2ecf20Sopenharmony_ci COBALT_MAX_HEIGHT * max_pages_per_line * 0x20; 608c2ecf20Sopenharmony_ci const size_t audio_bytes = ((1920 * 4) / PAGE_SIZE + 1) * 0x20; 618c2ecf20Sopenharmony_ci struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->index]; 628c2ecf20Sopenharmony_ci struct sg_table *sg_desc = vb2_dma_sg_plane_desc(vb, 0); 638c2ecf20Sopenharmony_ci unsigned size; 648c2ecf20Sopenharmony_ci int ret; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci size = s->stride * s->height; 678c2ecf20Sopenharmony_ci if (vb2_plane_size(vb, 0) < size) { 688c2ecf20Sopenharmony_ci cobalt_info("data will not fit into plane (%lu < %u)\n", 698c2ecf20Sopenharmony_ci vb2_plane_size(vb, 0), size); 708c2ecf20Sopenharmony_ci return -EINVAL; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (desc->virt == NULL) { 748c2ecf20Sopenharmony_ci desc->dev = &cobalt->pci_dev->dev; 758c2ecf20Sopenharmony_ci descriptor_list_allocate(desc, 768c2ecf20Sopenharmony_ci s->is_audio ? audio_bytes : bytes); 778c2ecf20Sopenharmony_ci if (desc->virt == NULL) 788c2ecf20Sopenharmony_ci return -ENOMEM; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci ret = descriptor_list_create(cobalt, sg_desc->sgl, 818c2ecf20Sopenharmony_ci !s->is_output, sg_desc->nents, size, 828c2ecf20Sopenharmony_ci s->width * s->bpp, s->stride, desc); 838c2ecf20Sopenharmony_ci if (ret) 848c2ecf20Sopenharmony_ci descriptor_list_free(desc); 858c2ecf20Sopenharmony_ci return ret; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void cobalt_buf_cleanup(struct vb2_buffer *vb) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct cobalt_stream *s = vb->vb2_queue->drv_priv; 918c2ecf20Sopenharmony_ci struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->index]; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci descriptor_list_free(desc); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic int cobalt_buf_prepare(struct vb2_buffer *vb) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 998c2ecf20Sopenharmony_ci struct cobalt_stream *s = vb->vb2_queue->drv_priv; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci vb2_set_plane_payload(vb, 0, s->stride * s->height); 1028c2ecf20Sopenharmony_ci vbuf->field = V4L2_FIELD_NONE; 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void chain_all_buffers(struct cobalt_stream *s) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci struct sg_dma_desc_info *desc[NR_BUFS]; 1098c2ecf20Sopenharmony_ci struct cobalt_buffer *cb; 1108c2ecf20Sopenharmony_ci struct list_head *p; 1118c2ecf20Sopenharmony_ci int i = 0; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci list_for_each(p, &s->bufs) { 1148c2ecf20Sopenharmony_ci cb = list_entry(p, struct cobalt_buffer, list); 1158c2ecf20Sopenharmony_ci desc[i] = &s->dma_desc_info[cb->vb.vb2_buf.index]; 1168c2ecf20Sopenharmony_ci if (i > 0) 1178c2ecf20Sopenharmony_ci descriptor_list_chain(desc[i-1], desc[i]); 1188c2ecf20Sopenharmony_ci i++; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic void cobalt_buf_queue(struct vb2_buffer *vb) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1258c2ecf20Sopenharmony_ci struct vb2_queue *q = vb->vb2_queue; 1268c2ecf20Sopenharmony_ci struct cobalt_stream *s = q->drv_priv; 1278c2ecf20Sopenharmony_ci struct cobalt_buffer *cb = to_cobalt_buffer(vbuf); 1288c2ecf20Sopenharmony_ci struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->index]; 1298c2ecf20Sopenharmony_ci unsigned long flags; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* Prepare new buffer */ 1328c2ecf20Sopenharmony_ci descriptor_list_loopback(desc); 1338c2ecf20Sopenharmony_ci descriptor_list_interrupt_disable(desc); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci spin_lock_irqsave(&s->irqlock, flags); 1368c2ecf20Sopenharmony_ci list_add_tail(&cb->list, &s->bufs); 1378c2ecf20Sopenharmony_ci chain_all_buffers(s); 1388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&s->irqlock, flags); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic void cobalt_enable_output(struct cobalt_stream *s) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct cobalt *cobalt = s->cobalt; 1448c2ecf20Sopenharmony_ci struct v4l2_bt_timings *bt = &s->timings.bt; 1458c2ecf20Sopenharmony_ci struct m00514_syncgen_flow_evcnt_regmap __iomem *vo = 1468c2ecf20Sopenharmony_ci COBALT_TX_BASE(cobalt); 1478c2ecf20Sopenharmony_ci unsigned fmt = s->pixfmt != V4L2_PIX_FMT_BGR32 ? 1488c2ecf20Sopenharmony_ci M00514_CONTROL_BITMAP_FORMAT_16_BPP_MSK : 0; 1498c2ecf20Sopenharmony_ci struct v4l2_subdev_format sd_fmt = { 1508c2ecf20Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 1518c2ecf20Sopenharmony_ci }; 1528c2ecf20Sopenharmony_ci u64 clk = bt->pixelclock; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (bt->flags & V4L2_DV_FL_REDUCED_FPS) 1558c2ecf20Sopenharmony_ci clk = div_u64(clk * 1000ULL, 1001); 1568c2ecf20Sopenharmony_ci if (!cobalt_cpld_set_freq(cobalt, clk)) { 1578c2ecf20Sopenharmony_ci cobalt_err("pixelclock out of range\n"); 1588c2ecf20Sopenharmony_ci return; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci sd_fmt.format.colorspace = s->colorspace; 1628c2ecf20Sopenharmony_ci sd_fmt.format.xfer_func = s->xfer_func; 1638c2ecf20Sopenharmony_ci sd_fmt.format.ycbcr_enc = s->ycbcr_enc; 1648c2ecf20Sopenharmony_ci sd_fmt.format.quantization = s->quantization; 1658c2ecf20Sopenharmony_ci sd_fmt.format.width = bt->width; 1668c2ecf20Sopenharmony_ci sd_fmt.format.height = bt->height; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Set up FDMA packer */ 1698c2ecf20Sopenharmony_ci switch (s->pixfmt) { 1708c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 1718c2ecf20Sopenharmony_ci sd_fmt.format.code = MEDIA_BUS_FMT_UYVY8_1X16; 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_BGR32: 1748c2ecf20Sopenharmony_ci sd_fmt.format.code = MEDIA_BUS_FMT_RGB888_1X24; 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci iowrite32(0, &vo->control); 1808c2ecf20Sopenharmony_ci /* 1080p60 */ 1818c2ecf20Sopenharmony_ci iowrite32(bt->hsync, &vo->sync_generator_h_sync_length); 1828c2ecf20Sopenharmony_ci iowrite32(bt->hbackporch, &vo->sync_generator_h_backporch_length); 1838c2ecf20Sopenharmony_ci iowrite32(bt->width, &vo->sync_generator_h_active_length); 1848c2ecf20Sopenharmony_ci iowrite32(bt->hfrontporch, &vo->sync_generator_h_frontporch_length); 1858c2ecf20Sopenharmony_ci iowrite32(bt->vsync, &vo->sync_generator_v_sync_length); 1868c2ecf20Sopenharmony_ci iowrite32(bt->vbackporch, &vo->sync_generator_v_backporch_length); 1878c2ecf20Sopenharmony_ci iowrite32(bt->height, &vo->sync_generator_v_active_length); 1888c2ecf20Sopenharmony_ci iowrite32(bt->vfrontporch, &vo->sync_generator_v_frontporch_length); 1898c2ecf20Sopenharmony_ci iowrite32(0x9900c1, &vo->error_color); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci iowrite32(M00514_CONTROL_BITMAP_SYNC_GENERATOR_LOAD_PARAM_MSK | fmt, 1928c2ecf20Sopenharmony_ci &vo->control); 1938c2ecf20Sopenharmony_ci iowrite32(M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK | fmt, &vo->control); 1948c2ecf20Sopenharmony_ci iowrite32(M00514_CONTROL_BITMAP_SYNC_GENERATOR_ENABLE_MSK | 1958c2ecf20Sopenharmony_ci M00514_CONTROL_BITMAP_FLOW_CTRL_OUTPUT_ENABLE_MSK | 1968c2ecf20Sopenharmony_ci fmt, &vo->control); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic void cobalt_enable_input(struct cobalt_stream *s) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct cobalt *cobalt = s->cobalt; 2028c2ecf20Sopenharmony_ci int ch = (int)s->video_channel; 2038c2ecf20Sopenharmony_ci struct m00235_fdma_packer_regmap __iomem *packer; 2048c2ecf20Sopenharmony_ci struct v4l2_subdev_format sd_fmt_yuyv = { 2058c2ecf20Sopenharmony_ci .pad = s->pad_source, 2068c2ecf20Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 2078c2ecf20Sopenharmony_ci .format.code = MEDIA_BUS_FMT_YUYV8_1X16, 2088c2ecf20Sopenharmony_ci }; 2098c2ecf20Sopenharmony_ci struct v4l2_subdev_format sd_fmt_rgb = { 2108c2ecf20Sopenharmony_ci .pad = s->pad_source, 2118c2ecf20Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 2128c2ecf20Sopenharmony_ci .format.code = MEDIA_BUS_FMT_RGB888_1X24, 2138c2ecf20Sopenharmony_ci }; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci cobalt_dbg(1, "video_channel %d (%s, %s)\n", 2168c2ecf20Sopenharmony_ci s->video_channel, 2178c2ecf20Sopenharmony_ci s->input == 0 ? "hdmi" : "generator", 2188c2ecf20Sopenharmony_ci "YUYV"); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci packer = COBALT_CVI_PACKER(cobalt, ch); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* Set up FDMA packer */ 2238c2ecf20Sopenharmony_ci switch (s->pixfmt) { 2248c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 2258c2ecf20Sopenharmony_ci iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK | 2268c2ecf20Sopenharmony_ci (1 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST), 2278c2ecf20Sopenharmony_ci &packer->control); 2288c2ecf20Sopenharmony_ci v4l2_subdev_call(s->sd, pad, set_fmt, NULL, 2298c2ecf20Sopenharmony_ci &sd_fmt_yuyv); 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGB24: 2328c2ecf20Sopenharmony_ci iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK | 2338c2ecf20Sopenharmony_ci (2 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST), 2348c2ecf20Sopenharmony_ci &packer->control); 2358c2ecf20Sopenharmony_ci v4l2_subdev_call(s->sd, pad, set_fmt, NULL, 2368c2ecf20Sopenharmony_ci &sd_fmt_rgb); 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_BGR32: 2398c2ecf20Sopenharmony_ci iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK | 2408c2ecf20Sopenharmony_ci M00235_CONTROL_BITMAP_ENDIAN_FORMAT_MSK | 2418c2ecf20Sopenharmony_ci (3 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST), 2428c2ecf20Sopenharmony_ci &packer->control); 2438c2ecf20Sopenharmony_ci v4l2_subdev_call(s->sd, pad, set_fmt, NULL, 2448c2ecf20Sopenharmony_ci &sd_fmt_rgb); 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic void cobalt_dma_start_streaming(struct cobalt_stream *s) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct cobalt *cobalt = s->cobalt; 2528c2ecf20Sopenharmony_ci int rx = s->video_channel; 2538c2ecf20Sopenharmony_ci struct m00460_evcnt_regmap __iomem *evcnt = 2548c2ecf20Sopenharmony_ci COBALT_CVI_EVCNT(cobalt, rx); 2558c2ecf20Sopenharmony_ci struct cobalt_buffer *cb; 2568c2ecf20Sopenharmony_ci unsigned long flags; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci spin_lock_irqsave(&s->irqlock, flags); 2598c2ecf20Sopenharmony_ci if (!s->is_output) { 2608c2ecf20Sopenharmony_ci iowrite32(M00460_CONTROL_BITMAP_CLEAR_MSK, &evcnt->control); 2618c2ecf20Sopenharmony_ci iowrite32(M00460_CONTROL_BITMAP_ENABLE_MSK, &evcnt->control); 2628c2ecf20Sopenharmony_ci } else { 2638c2ecf20Sopenharmony_ci struct m00514_syncgen_flow_evcnt_regmap __iomem *vo = 2648c2ecf20Sopenharmony_ci COBALT_TX_BASE(cobalt); 2658c2ecf20Sopenharmony_ci u32 ctrl = ioread32(&vo->control); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci ctrl &= ~(M00514_CONTROL_BITMAP_EVCNT_ENABLE_MSK | 2688c2ecf20Sopenharmony_ci M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK); 2698c2ecf20Sopenharmony_ci iowrite32(ctrl | M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK, 2708c2ecf20Sopenharmony_ci &vo->control); 2718c2ecf20Sopenharmony_ci iowrite32(ctrl | M00514_CONTROL_BITMAP_EVCNT_ENABLE_MSK, 2728c2ecf20Sopenharmony_ci &vo->control); 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci cb = list_first_entry(&s->bufs, struct cobalt_buffer, list); 2758c2ecf20Sopenharmony_ci omni_sg_dma_start(s, &s->dma_desc_info[cb->vb.vb2_buf.index]); 2768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&s->irqlock, flags); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic int cobalt_start_streaming(struct vb2_queue *q, unsigned int count) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct cobalt_stream *s = q->drv_priv; 2828c2ecf20Sopenharmony_ci struct cobalt *cobalt = s->cobalt; 2838c2ecf20Sopenharmony_ci struct m00233_video_measure_regmap __iomem *vmr; 2848c2ecf20Sopenharmony_ci struct m00473_freewheel_regmap __iomem *fw; 2858c2ecf20Sopenharmony_ci struct m00479_clk_loss_detector_regmap __iomem *clkloss; 2868c2ecf20Sopenharmony_ci int rx = s->video_channel; 2878c2ecf20Sopenharmony_ci struct m00389_cvi_regmap __iomem *cvi = COBALT_CVI(cobalt, rx); 2888c2ecf20Sopenharmony_ci struct m00460_evcnt_regmap __iomem *evcnt = COBALT_CVI_EVCNT(cobalt, rx); 2898c2ecf20Sopenharmony_ci struct v4l2_bt_timings *bt = &s->timings.bt; 2908c2ecf20Sopenharmony_ci u64 tot_size; 2918c2ecf20Sopenharmony_ci u32 clk_freq; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (s->is_audio) 2948c2ecf20Sopenharmony_ci goto done; 2958c2ecf20Sopenharmony_ci if (s->is_output) { 2968c2ecf20Sopenharmony_ci s->unstable_frame = false; 2978c2ecf20Sopenharmony_ci cobalt_enable_output(s); 2988c2ecf20Sopenharmony_ci goto done; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci cobalt_enable_input(s); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci fw = COBALT_CVI_FREEWHEEL(cobalt, rx); 3048c2ecf20Sopenharmony_ci vmr = COBALT_CVI_VMR(cobalt, rx); 3058c2ecf20Sopenharmony_ci clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci iowrite32(M00460_CONTROL_BITMAP_CLEAR_MSK, &evcnt->control); 3088c2ecf20Sopenharmony_ci iowrite32(M00460_CONTROL_BITMAP_ENABLE_MSK, &evcnt->control); 3098c2ecf20Sopenharmony_ci iowrite32(bt->width, &cvi->frame_width); 3108c2ecf20Sopenharmony_ci iowrite32(bt->height, &cvi->frame_height); 3118c2ecf20Sopenharmony_ci tot_size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); 3128c2ecf20Sopenharmony_ci iowrite32(div_u64((u64)V4L2_DV_BT_FRAME_WIDTH(bt) * COBALT_CLK * 4, 3138c2ecf20Sopenharmony_ci bt->pixelclock), &vmr->hsync_timeout_val); 3148c2ecf20Sopenharmony_ci iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control); 3158c2ecf20Sopenharmony_ci clk_freq = ioread32(&fw->clk_freq); 3168c2ecf20Sopenharmony_ci iowrite32(clk_freq / 1000000, &clkloss->ref_clk_cnt_val); 3178c2ecf20Sopenharmony_ci /* The lower bound for the clock frequency is 0.5% lower as is 3188c2ecf20Sopenharmony_ci * allowed by the spec */ 3198c2ecf20Sopenharmony_ci iowrite32(div_u64(bt->pixelclock * 995, 1000000000), 3208c2ecf20Sopenharmony_ci &clkloss->test_clk_cnt_val); 3218c2ecf20Sopenharmony_ci /* will be enabled after the first frame has been received */ 3228c2ecf20Sopenharmony_ci iowrite32(bt->width * bt->height, &fw->active_length); 3238c2ecf20Sopenharmony_ci iowrite32(div_u64((u64)clk_freq * tot_size, bt->pixelclock), 3248c2ecf20Sopenharmony_ci &fw->total_length); 3258c2ecf20Sopenharmony_ci iowrite32(M00233_IRQ_TRIGGERS_BITMAP_VACTIVE_AREA_MSK | 3268c2ecf20Sopenharmony_ci M00233_IRQ_TRIGGERS_BITMAP_HACTIVE_AREA_MSK, 3278c2ecf20Sopenharmony_ci &vmr->irq_triggers); 3288c2ecf20Sopenharmony_ci iowrite32(0, &cvi->control); 3298c2ecf20Sopenharmony_ci iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci iowrite32(0xff, &fw->output_color); 3328c2ecf20Sopenharmony_ci iowrite32(M00479_CTRL_BITMAP_ENABLE_MSK, &clkloss->ctrl); 3338c2ecf20Sopenharmony_ci iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK | 3348c2ecf20Sopenharmony_ci M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK, &fw->ctrl); 3358c2ecf20Sopenharmony_ci s->unstable_frame = true; 3368c2ecf20Sopenharmony_ci s->enable_freewheel = false; 3378c2ecf20Sopenharmony_ci s->enable_cvi = false; 3388c2ecf20Sopenharmony_ci s->skip_first_frames = 0; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cidone: 3418c2ecf20Sopenharmony_ci s->sequence = 0; 3428c2ecf20Sopenharmony_ci cobalt_dma_start_streaming(s); 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic void cobalt_dma_stop_streaming(struct cobalt_stream *s) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct cobalt *cobalt = s->cobalt; 3498c2ecf20Sopenharmony_ci struct sg_dma_desc_info *desc; 3508c2ecf20Sopenharmony_ci struct cobalt_buffer *cb; 3518c2ecf20Sopenharmony_ci struct list_head *p; 3528c2ecf20Sopenharmony_ci unsigned long flags; 3538c2ecf20Sopenharmony_ci int timeout_msec = 100; 3548c2ecf20Sopenharmony_ci int rx = s->video_channel; 3558c2ecf20Sopenharmony_ci struct m00460_evcnt_regmap __iomem *evcnt = 3568c2ecf20Sopenharmony_ci COBALT_CVI_EVCNT(cobalt, rx); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (!s->is_output) { 3598c2ecf20Sopenharmony_ci iowrite32(0, &evcnt->control); 3608c2ecf20Sopenharmony_ci } else if (!s->is_audio) { 3618c2ecf20Sopenharmony_ci struct m00514_syncgen_flow_evcnt_regmap __iomem *vo = 3628c2ecf20Sopenharmony_ci COBALT_TX_BASE(cobalt); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci iowrite32(M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK, &vo->control); 3658c2ecf20Sopenharmony_ci iowrite32(0, &vo->control); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* Try to stop the DMA engine gracefully */ 3698c2ecf20Sopenharmony_ci spin_lock_irqsave(&s->irqlock, flags); 3708c2ecf20Sopenharmony_ci list_for_each(p, &s->bufs) { 3718c2ecf20Sopenharmony_ci cb = list_entry(p, struct cobalt_buffer, list); 3728c2ecf20Sopenharmony_ci desc = &s->dma_desc_info[cb->vb.vb2_buf.index]; 3738c2ecf20Sopenharmony_ci /* Stop DMA after this descriptor chain */ 3748c2ecf20Sopenharmony_ci descriptor_list_end_of_chain(desc); 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&s->irqlock, flags); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* Wait 100 millisecond for DMA to finish, abort on timeout. */ 3798c2ecf20Sopenharmony_ci if (!wait_event_timeout(s->q.done_wq, is_dma_done(s), 3808c2ecf20Sopenharmony_ci msecs_to_jiffies(timeout_msec))) { 3818c2ecf20Sopenharmony_ci omni_sg_dma_abort_channel(s); 3828c2ecf20Sopenharmony_ci pr_warn("aborted\n"); 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci cobalt_write_bar0(cobalt, DMA_INTERRUPT_STATUS_REG, 3858c2ecf20Sopenharmony_ci 1 << s->dma_channel); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic void cobalt_stop_streaming(struct vb2_queue *q) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct cobalt_stream *s = q->drv_priv; 3918c2ecf20Sopenharmony_ci struct cobalt *cobalt = s->cobalt; 3928c2ecf20Sopenharmony_ci int rx = s->video_channel; 3938c2ecf20Sopenharmony_ci struct m00233_video_measure_regmap __iomem *vmr; 3948c2ecf20Sopenharmony_ci struct m00473_freewheel_regmap __iomem *fw; 3958c2ecf20Sopenharmony_ci struct m00479_clk_loss_detector_regmap __iomem *clkloss; 3968c2ecf20Sopenharmony_ci struct cobalt_buffer *cb; 3978c2ecf20Sopenharmony_ci struct list_head *p, *safe; 3988c2ecf20Sopenharmony_ci unsigned long flags; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci cobalt_dma_stop_streaming(s); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /* Return all buffers to user space */ 4038c2ecf20Sopenharmony_ci spin_lock_irqsave(&s->irqlock, flags); 4048c2ecf20Sopenharmony_ci list_for_each_safe(p, safe, &s->bufs) { 4058c2ecf20Sopenharmony_ci cb = list_entry(p, struct cobalt_buffer, list); 4068c2ecf20Sopenharmony_ci list_del(&cb->list); 4078c2ecf20Sopenharmony_ci vb2_buffer_done(&cb->vb.vb2_buf, VB2_BUF_STATE_ERROR); 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&s->irqlock, flags); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (s->is_audio || s->is_output) 4128c2ecf20Sopenharmony_ci return; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci fw = COBALT_CVI_FREEWHEEL(cobalt, rx); 4158c2ecf20Sopenharmony_ci vmr = COBALT_CVI_VMR(cobalt, rx); 4168c2ecf20Sopenharmony_ci clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx); 4178c2ecf20Sopenharmony_ci iowrite32(0, &vmr->control); 4188c2ecf20Sopenharmony_ci iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control); 4198c2ecf20Sopenharmony_ci iowrite32(0, &fw->ctrl); 4208c2ecf20Sopenharmony_ci iowrite32(0, &clkloss->ctrl); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic const struct vb2_ops cobalt_qops = { 4248c2ecf20Sopenharmony_ci .queue_setup = cobalt_queue_setup, 4258c2ecf20Sopenharmony_ci .buf_init = cobalt_buf_init, 4268c2ecf20Sopenharmony_ci .buf_cleanup = cobalt_buf_cleanup, 4278c2ecf20Sopenharmony_ci .buf_prepare = cobalt_buf_prepare, 4288c2ecf20Sopenharmony_ci .buf_queue = cobalt_buf_queue, 4298c2ecf20Sopenharmony_ci .start_streaming = cobalt_start_streaming, 4308c2ecf20Sopenharmony_ci .stop_streaming = cobalt_stop_streaming, 4318c2ecf20Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 4328c2ecf20Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 4338c2ecf20Sopenharmony_ci}; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/* V4L2 ioctls */ 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 4388c2ecf20Sopenharmony_cistatic int cobalt_cobaltc(struct cobalt *cobalt, unsigned int cmd, void *arg) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci struct v4l2_dbg_register *regs = arg; 4418c2ecf20Sopenharmony_ci void __iomem *adrs = cobalt->bar1 + regs->reg; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci cobalt_info("cobalt_cobaltc: adrs = %p\n", adrs); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 4468c2ecf20Sopenharmony_ci return -EPERM; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci regs->size = 4; 4498c2ecf20Sopenharmony_ci if (cmd == VIDIOC_DBG_S_REGISTER) 4508c2ecf20Sopenharmony_ci iowrite32(regs->val, adrs); 4518c2ecf20Sopenharmony_ci else 4528c2ecf20Sopenharmony_ci regs->val = ioread32(adrs); 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic int cobalt_g_register(struct file *file, void *priv_fh, 4578c2ecf20Sopenharmony_ci struct v4l2_dbg_register *reg) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 4608c2ecf20Sopenharmony_ci struct cobalt *cobalt = s->cobalt; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return cobalt_cobaltc(cobalt, VIDIOC_DBG_G_REGISTER, reg); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int cobalt_s_register(struct file *file, void *priv_fh, 4668c2ecf20Sopenharmony_ci const struct v4l2_dbg_register *reg) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 4698c2ecf20Sopenharmony_ci struct cobalt *cobalt = s->cobalt; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return cobalt_cobaltc(cobalt, VIDIOC_DBG_S_REGISTER, 4728c2ecf20Sopenharmony_ci (struct v4l2_dbg_register *)reg); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci#endif 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic int cobalt_querycap(struct file *file, void *priv_fh, 4778c2ecf20Sopenharmony_ci struct v4l2_capability *vcap) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 4808c2ecf20Sopenharmony_ci struct cobalt *cobalt = s->cobalt; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci strscpy(vcap->driver, "cobalt", sizeof(vcap->driver)); 4838c2ecf20Sopenharmony_ci strscpy(vcap->card, "cobalt", sizeof(vcap->card)); 4848c2ecf20Sopenharmony_ci snprintf(vcap->bus_info, sizeof(vcap->bus_info), 4858c2ecf20Sopenharmony_ci "PCIe:%s", pci_name(cobalt->pci_dev)); 4868c2ecf20Sopenharmony_ci vcap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | 4878c2ecf20Sopenharmony_ci V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS; 4888c2ecf20Sopenharmony_ci if (cobalt->have_hsma_tx) 4898c2ecf20Sopenharmony_ci vcap->capabilities |= V4L2_CAP_VIDEO_OUTPUT; 4908c2ecf20Sopenharmony_ci return 0; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic void cobalt_video_input_status_show(struct cobalt_stream *s) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci struct m00389_cvi_regmap __iomem *cvi; 4968c2ecf20Sopenharmony_ci struct m00233_video_measure_regmap __iomem *vmr; 4978c2ecf20Sopenharmony_ci struct m00473_freewheel_regmap __iomem *fw; 4988c2ecf20Sopenharmony_ci struct m00479_clk_loss_detector_regmap __iomem *clkloss; 4998c2ecf20Sopenharmony_ci struct m00235_fdma_packer_regmap __iomem *packer; 5008c2ecf20Sopenharmony_ci int rx = s->video_channel; 5018c2ecf20Sopenharmony_ci struct cobalt *cobalt = s->cobalt; 5028c2ecf20Sopenharmony_ci u32 cvi_ctrl, cvi_stat; 5038c2ecf20Sopenharmony_ci u32 vmr_ctrl, vmr_stat; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci cvi = COBALT_CVI(cobalt, rx); 5068c2ecf20Sopenharmony_ci vmr = COBALT_CVI_VMR(cobalt, rx); 5078c2ecf20Sopenharmony_ci fw = COBALT_CVI_FREEWHEEL(cobalt, rx); 5088c2ecf20Sopenharmony_ci clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx); 5098c2ecf20Sopenharmony_ci packer = COBALT_CVI_PACKER(cobalt, rx); 5108c2ecf20Sopenharmony_ci cvi_ctrl = ioread32(&cvi->control); 5118c2ecf20Sopenharmony_ci cvi_stat = ioread32(&cvi->status); 5128c2ecf20Sopenharmony_ci vmr_ctrl = ioread32(&vmr->control); 5138c2ecf20Sopenharmony_ci vmr_stat = ioread32(&vmr->status); 5148c2ecf20Sopenharmony_ci cobalt_info("rx%d: cvi resolution: %dx%d\n", rx, 5158c2ecf20Sopenharmony_ci ioread32(&cvi->frame_width), ioread32(&cvi->frame_height)); 5168c2ecf20Sopenharmony_ci cobalt_info("rx%d: cvi control: %s%s%s\n", rx, 5178c2ecf20Sopenharmony_ci (cvi_ctrl & M00389_CONTROL_BITMAP_ENABLE_MSK) ? 5188c2ecf20Sopenharmony_ci "enable " : "disable ", 5198c2ecf20Sopenharmony_ci (cvi_ctrl & M00389_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK) ? 5208c2ecf20Sopenharmony_ci "HSync- " : "HSync+ ", 5218c2ecf20Sopenharmony_ci (cvi_ctrl & M00389_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK) ? 5228c2ecf20Sopenharmony_ci "VSync- " : "VSync+ "); 5238c2ecf20Sopenharmony_ci cobalt_info("rx%d: cvi status: %s%s\n", rx, 5248c2ecf20Sopenharmony_ci (cvi_stat & M00389_STATUS_BITMAP_LOCK_MSK) ? 5258c2ecf20Sopenharmony_ci "lock " : "no-lock ", 5268c2ecf20Sopenharmony_ci (cvi_stat & M00389_STATUS_BITMAP_ERROR_MSK) ? 5278c2ecf20Sopenharmony_ci "error " : "no-error "); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci cobalt_info("rx%d: Measurements: %s%s%s%s%s%s%s\n", rx, 5308c2ecf20Sopenharmony_ci (vmr_ctrl & M00233_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK) ? 5318c2ecf20Sopenharmony_ci "HSync- " : "HSync+ ", 5328c2ecf20Sopenharmony_ci (vmr_ctrl & M00233_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK) ? 5338c2ecf20Sopenharmony_ci "VSync- " : "VSync+ ", 5348c2ecf20Sopenharmony_ci (vmr_ctrl & M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK) ? 5358c2ecf20Sopenharmony_ci "enabled " : "disabled ", 5368c2ecf20Sopenharmony_ci (vmr_ctrl & M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK) ? 5378c2ecf20Sopenharmony_ci "irq-enabled " : "irq-disabled ", 5388c2ecf20Sopenharmony_ci (vmr_ctrl & M00233_CONTROL_BITMAP_UPDATE_ON_HSYNC_MSK) ? 5398c2ecf20Sopenharmony_ci "update-on-hsync " : "", 5408c2ecf20Sopenharmony_ci (vmr_stat & M00233_STATUS_BITMAP_HSYNC_TIMEOUT_MSK) ? 5418c2ecf20Sopenharmony_ci "hsync-timeout " : "", 5428c2ecf20Sopenharmony_ci (vmr_stat & M00233_STATUS_BITMAP_INIT_DONE_MSK) ? 5438c2ecf20Sopenharmony_ci "init-done" : ""); 5448c2ecf20Sopenharmony_ci cobalt_info("rx%d: irq_status: 0x%02x irq_triggers: 0x%02x\n", rx, 5458c2ecf20Sopenharmony_ci ioread32(&vmr->irq_status) & 0xff, 5468c2ecf20Sopenharmony_ci ioread32(&vmr->irq_triggers) & 0xff); 5478c2ecf20Sopenharmony_ci cobalt_info("rx%d: vsync: %d\n", rx, ioread32(&vmr->vsync_time)); 5488c2ecf20Sopenharmony_ci cobalt_info("rx%d: vbp: %d\n", rx, ioread32(&vmr->vback_porch)); 5498c2ecf20Sopenharmony_ci cobalt_info("rx%d: vact: %d\n", rx, ioread32(&vmr->vactive_area)); 5508c2ecf20Sopenharmony_ci cobalt_info("rx%d: vfb: %d\n", rx, ioread32(&vmr->vfront_porch)); 5518c2ecf20Sopenharmony_ci cobalt_info("rx%d: hsync: %d\n", rx, ioread32(&vmr->hsync_time)); 5528c2ecf20Sopenharmony_ci cobalt_info("rx%d: hbp: %d\n", rx, ioread32(&vmr->hback_porch)); 5538c2ecf20Sopenharmony_ci cobalt_info("rx%d: hact: %d\n", rx, ioread32(&vmr->hactive_area)); 5548c2ecf20Sopenharmony_ci cobalt_info("rx%d: hfb: %d\n", rx, ioread32(&vmr->hfront_porch)); 5558c2ecf20Sopenharmony_ci cobalt_info("rx%d: Freewheeling: %s%s%s\n", rx, 5568c2ecf20Sopenharmony_ci (ioread32(&fw->ctrl) & M00473_CTRL_BITMAP_ENABLE_MSK) ? 5578c2ecf20Sopenharmony_ci "enabled " : "disabled ", 5588c2ecf20Sopenharmony_ci (ioread32(&fw->ctrl) & M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK) ? 5598c2ecf20Sopenharmony_ci "forced " : "", 5608c2ecf20Sopenharmony_ci (ioread32(&fw->status) & M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK) ? 5618c2ecf20Sopenharmony_ci "freewheeling " : "video-passthrough "); 5628c2ecf20Sopenharmony_ci iowrite32(0xff, &vmr->irq_status); 5638c2ecf20Sopenharmony_ci cobalt_info("rx%d: Clock Loss Detection: %s%s\n", rx, 5648c2ecf20Sopenharmony_ci (ioread32(&clkloss->ctrl) & M00479_CTRL_BITMAP_ENABLE_MSK) ? 5658c2ecf20Sopenharmony_ci "enabled " : "disabled ", 5668c2ecf20Sopenharmony_ci (ioread32(&clkloss->status) & M00479_STATUS_BITMAP_CLOCK_MISSING_MSK) ? 5678c2ecf20Sopenharmony_ci "clock-missing " : "found-clock "); 5688c2ecf20Sopenharmony_ci cobalt_info("rx%d: Packer: %x\n", rx, ioread32(&packer->control)); 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic int cobalt_log_status(struct file *file, void *priv_fh) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 5748c2ecf20Sopenharmony_ci struct cobalt *cobalt = s->cobalt; 5758c2ecf20Sopenharmony_ci struct m00514_syncgen_flow_evcnt_regmap __iomem *vo = 5768c2ecf20Sopenharmony_ci COBALT_TX_BASE(cobalt); 5778c2ecf20Sopenharmony_ci u8 stat; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci cobalt_info("%s", cobalt->hdl_info); 5808c2ecf20Sopenharmony_ci cobalt_info("sysctrl: %08x, sysstat: %08x\n", 5818c2ecf20Sopenharmony_ci cobalt_g_sysctrl(cobalt), 5828c2ecf20Sopenharmony_ci cobalt_g_sysstat(cobalt)); 5838c2ecf20Sopenharmony_ci cobalt_info("dma channel: %d, video channel: %d\n", 5848c2ecf20Sopenharmony_ci s->dma_channel, s->video_channel); 5858c2ecf20Sopenharmony_ci cobalt_pcie_status_show(cobalt); 5868c2ecf20Sopenharmony_ci cobalt_cpld_status(cobalt); 5878c2ecf20Sopenharmony_ci cobalt_irq_log_status(cobalt); 5888c2ecf20Sopenharmony_ci v4l2_subdev_call(s->sd, core, log_status); 5898c2ecf20Sopenharmony_ci if (!s->is_output) { 5908c2ecf20Sopenharmony_ci cobalt_video_input_status_show(s); 5918c2ecf20Sopenharmony_ci return 0; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci stat = ioread32(&vo->rd_status); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci cobalt_info("tx: status: %s%s\n", 5978c2ecf20Sopenharmony_ci (stat & M00514_RD_STATUS_BITMAP_FLOW_CTRL_NO_DATA_ERROR_MSK) ? 5988c2ecf20Sopenharmony_ci "no_data " : "", 5998c2ecf20Sopenharmony_ci (stat & M00514_RD_STATUS_BITMAP_READY_BUFFER_FULL_MSK) ? 6008c2ecf20Sopenharmony_ci "ready_buffer_full " : ""); 6018c2ecf20Sopenharmony_ci cobalt_info("tx: evcnt: %d\n", ioread32(&vo->rd_evcnt_count)); 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic int cobalt_enum_dv_timings(struct file *file, void *priv_fh, 6068c2ecf20Sopenharmony_ci struct v4l2_enum_dv_timings *timings) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (s->input == 1) { 6118c2ecf20Sopenharmony_ci if (timings->index) 6128c2ecf20Sopenharmony_ci return -EINVAL; 6138c2ecf20Sopenharmony_ci memset(timings->reserved, 0, sizeof(timings->reserved)); 6148c2ecf20Sopenharmony_ci timings->timings = cea1080p60; 6158c2ecf20Sopenharmony_ci return 0; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci timings->pad = 0; 6188c2ecf20Sopenharmony_ci return v4l2_subdev_call(s->sd, 6198c2ecf20Sopenharmony_ci pad, enum_dv_timings, timings); 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic int cobalt_s_dv_timings(struct file *file, void *priv_fh, 6238c2ecf20Sopenharmony_ci struct v4l2_dv_timings *timings) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 6268c2ecf20Sopenharmony_ci int err; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (s->input == 1) { 6298c2ecf20Sopenharmony_ci *timings = cea1080p60; 6308c2ecf20Sopenharmony_ci return 0; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (v4l2_match_dv_timings(timings, &s->timings, 0, true)) 6348c2ecf20Sopenharmony_ci return 0; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (vb2_is_busy(&s->q)) 6378c2ecf20Sopenharmony_ci return -EBUSY; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci err = v4l2_subdev_call(s->sd, 6408c2ecf20Sopenharmony_ci video, s_dv_timings, timings); 6418c2ecf20Sopenharmony_ci if (!err) { 6428c2ecf20Sopenharmony_ci s->timings = *timings; 6438c2ecf20Sopenharmony_ci s->width = timings->bt.width; 6448c2ecf20Sopenharmony_ci s->height = timings->bt.height; 6458c2ecf20Sopenharmony_ci s->stride = timings->bt.width * s->bpp; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci return err; 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic int cobalt_g_dv_timings(struct file *file, void *priv_fh, 6518c2ecf20Sopenharmony_ci struct v4l2_dv_timings *timings) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (s->input == 1) { 6568c2ecf20Sopenharmony_ci *timings = cea1080p60; 6578c2ecf20Sopenharmony_ci return 0; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci return v4l2_subdev_call(s->sd, 6608c2ecf20Sopenharmony_ci video, g_dv_timings, timings); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int cobalt_query_dv_timings(struct file *file, void *priv_fh, 6648c2ecf20Sopenharmony_ci struct v4l2_dv_timings *timings) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci if (s->input == 1) { 6698c2ecf20Sopenharmony_ci *timings = cea1080p60; 6708c2ecf20Sopenharmony_ci return 0; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci return v4l2_subdev_call(s->sd, 6738c2ecf20Sopenharmony_ci video, query_dv_timings, timings); 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic int cobalt_dv_timings_cap(struct file *file, void *priv_fh, 6778c2ecf20Sopenharmony_ci struct v4l2_dv_timings_cap *cap) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci cap->pad = 0; 6828c2ecf20Sopenharmony_ci return v4l2_subdev_call(s->sd, 6838c2ecf20Sopenharmony_ci pad, dv_timings_cap, cap); 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic int cobalt_enum_fmt_vid_cap(struct file *file, void *priv_fh, 6878c2ecf20Sopenharmony_ci struct v4l2_fmtdesc *f) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci switch (f->index) { 6908c2ecf20Sopenharmony_ci case 0: 6918c2ecf20Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_YUYV; 6928c2ecf20Sopenharmony_ci break; 6938c2ecf20Sopenharmony_ci case 1: 6948c2ecf20Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_RGB24; 6958c2ecf20Sopenharmony_ci break; 6968c2ecf20Sopenharmony_ci case 2: 6978c2ecf20Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_BGR32; 6988c2ecf20Sopenharmony_ci break; 6998c2ecf20Sopenharmony_ci default: 7008c2ecf20Sopenharmony_ci return -EINVAL; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci return 0; 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic int cobalt_g_fmt_vid_cap(struct file *file, void *priv_fh, 7078c2ecf20Sopenharmony_ci struct v4l2_format *f) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 7108c2ecf20Sopenharmony_ci struct v4l2_pix_format *pix = &f->fmt.pix; 7118c2ecf20Sopenharmony_ci struct v4l2_subdev_format sd_fmt; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci pix->width = s->width; 7148c2ecf20Sopenharmony_ci pix->height = s->height; 7158c2ecf20Sopenharmony_ci pix->bytesperline = s->stride; 7168c2ecf20Sopenharmony_ci pix->field = V4L2_FIELD_NONE; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (s->input == 1) { 7198c2ecf20Sopenharmony_ci pix->colorspace = V4L2_COLORSPACE_SRGB; 7208c2ecf20Sopenharmony_ci } else { 7218c2ecf20Sopenharmony_ci sd_fmt.pad = s->pad_source; 7228c2ecf20Sopenharmony_ci sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; 7238c2ecf20Sopenharmony_ci v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt); 7248c2ecf20Sopenharmony_ci v4l2_fill_pix_format(pix, &sd_fmt.format); 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci pix->pixelformat = s->pixfmt; 7288c2ecf20Sopenharmony_ci pix->sizeimage = pix->bytesperline * pix->height; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci return 0; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic int cobalt_try_fmt_vid_cap(struct file *file, void *priv_fh, 7348c2ecf20Sopenharmony_ci struct v4l2_format *f) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 7378c2ecf20Sopenharmony_ci struct v4l2_pix_format *pix = &f->fmt.pix; 7388c2ecf20Sopenharmony_ci struct v4l2_subdev_format sd_fmt; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci /* Check for min (QCIF) and max (Full HD) size */ 7418c2ecf20Sopenharmony_ci if ((pix->width < 176) || (pix->height < 144)) { 7428c2ecf20Sopenharmony_ci pix->width = 176; 7438c2ecf20Sopenharmony_ci pix->height = 144; 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if ((pix->width > 1920) || (pix->height > 1080)) { 7478c2ecf20Sopenharmony_ci pix->width = 1920; 7488c2ecf20Sopenharmony_ci pix->height = 1080; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* Make width multiple of 4 */ 7528c2ecf20Sopenharmony_ci pix->width &= ~0x3; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* Make height multiple of 2 */ 7558c2ecf20Sopenharmony_ci pix->height &= ~0x1; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (s->input == 1) { 7588c2ecf20Sopenharmony_ci /* Generator => fixed format only */ 7598c2ecf20Sopenharmony_ci pix->width = 1920; 7608c2ecf20Sopenharmony_ci pix->height = 1080; 7618c2ecf20Sopenharmony_ci pix->colorspace = V4L2_COLORSPACE_SRGB; 7628c2ecf20Sopenharmony_ci } else { 7638c2ecf20Sopenharmony_ci sd_fmt.pad = s->pad_source; 7648c2ecf20Sopenharmony_ci sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; 7658c2ecf20Sopenharmony_ci v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt); 7668c2ecf20Sopenharmony_ci v4l2_fill_pix_format(pix, &sd_fmt.format); 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci switch (pix->pixelformat) { 7708c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 7718c2ecf20Sopenharmony_ci default: 7728c2ecf20Sopenharmony_ci pix->bytesperline = max(pix->bytesperline & ~0x3, 7738c2ecf20Sopenharmony_ci pix->width * COBALT_BYTES_PER_PIXEL_YUYV); 7748c2ecf20Sopenharmony_ci pix->pixelformat = V4L2_PIX_FMT_YUYV; 7758c2ecf20Sopenharmony_ci break; 7768c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGB24: 7778c2ecf20Sopenharmony_ci pix->bytesperline = max(pix->bytesperline & ~0x3, 7788c2ecf20Sopenharmony_ci pix->width * COBALT_BYTES_PER_PIXEL_RGB24); 7798c2ecf20Sopenharmony_ci break; 7808c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_BGR32: 7818c2ecf20Sopenharmony_ci pix->bytesperline = max(pix->bytesperline & ~0x3, 7828c2ecf20Sopenharmony_ci pix->width * COBALT_BYTES_PER_PIXEL_RGB32); 7838c2ecf20Sopenharmony_ci break; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci pix->sizeimage = pix->bytesperline * pix->height; 7878c2ecf20Sopenharmony_ci pix->field = V4L2_FIELD_NONE; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci return 0; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic int cobalt_s_fmt_vid_cap(struct file *file, void *priv_fh, 7938c2ecf20Sopenharmony_ci struct v4l2_format *f) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 7968c2ecf20Sopenharmony_ci struct v4l2_pix_format *pix = &f->fmt.pix; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (vb2_is_busy(&s->q)) 7998c2ecf20Sopenharmony_ci return -EBUSY; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (cobalt_try_fmt_vid_cap(file, priv_fh, f)) 8028c2ecf20Sopenharmony_ci return -EINVAL; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci s->width = pix->width; 8058c2ecf20Sopenharmony_ci s->height = pix->height; 8068c2ecf20Sopenharmony_ci s->stride = pix->bytesperline; 8078c2ecf20Sopenharmony_ci switch (pix->pixelformat) { 8088c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 8098c2ecf20Sopenharmony_ci s->bpp = COBALT_BYTES_PER_PIXEL_YUYV; 8108c2ecf20Sopenharmony_ci break; 8118c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGB24: 8128c2ecf20Sopenharmony_ci s->bpp = COBALT_BYTES_PER_PIXEL_RGB24; 8138c2ecf20Sopenharmony_ci break; 8148c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_BGR32: 8158c2ecf20Sopenharmony_ci s->bpp = COBALT_BYTES_PER_PIXEL_RGB32; 8168c2ecf20Sopenharmony_ci break; 8178c2ecf20Sopenharmony_ci default: 8188c2ecf20Sopenharmony_ci return -EINVAL; 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci s->pixfmt = pix->pixelformat; 8218c2ecf20Sopenharmony_ci cobalt_enable_input(s); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci return 0; 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_cistatic int cobalt_try_fmt_vid_out(struct file *file, void *priv_fh, 8278c2ecf20Sopenharmony_ci struct v4l2_format *f) 8288c2ecf20Sopenharmony_ci{ 8298c2ecf20Sopenharmony_ci struct v4l2_pix_format *pix = &f->fmt.pix; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci /* Check for min (QCIF) and max (Full HD) size */ 8328c2ecf20Sopenharmony_ci if ((pix->width < 176) || (pix->height < 144)) { 8338c2ecf20Sopenharmony_ci pix->width = 176; 8348c2ecf20Sopenharmony_ci pix->height = 144; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if ((pix->width > 1920) || (pix->height > 1080)) { 8388c2ecf20Sopenharmony_ci pix->width = 1920; 8398c2ecf20Sopenharmony_ci pix->height = 1080; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci /* Make width multiple of 4 */ 8438c2ecf20Sopenharmony_ci pix->width &= ~0x3; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* Make height multiple of 2 */ 8468c2ecf20Sopenharmony_ci pix->height &= ~0x1; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci switch (pix->pixelformat) { 8498c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 8508c2ecf20Sopenharmony_ci default: 8518c2ecf20Sopenharmony_ci pix->bytesperline = max(pix->bytesperline & ~0x3, 8528c2ecf20Sopenharmony_ci pix->width * COBALT_BYTES_PER_PIXEL_YUYV); 8538c2ecf20Sopenharmony_ci pix->pixelformat = V4L2_PIX_FMT_YUYV; 8548c2ecf20Sopenharmony_ci break; 8558c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_BGR32: 8568c2ecf20Sopenharmony_ci pix->bytesperline = max(pix->bytesperline & ~0x3, 8578c2ecf20Sopenharmony_ci pix->width * COBALT_BYTES_PER_PIXEL_RGB32); 8588c2ecf20Sopenharmony_ci break; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci pix->sizeimage = pix->bytesperline * pix->height; 8628c2ecf20Sopenharmony_ci pix->field = V4L2_FIELD_NONE; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci return 0; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic int cobalt_g_fmt_vid_out(struct file *file, void *priv_fh, 8688c2ecf20Sopenharmony_ci struct v4l2_format *f) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 8718c2ecf20Sopenharmony_ci struct v4l2_pix_format *pix = &f->fmt.pix; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci pix->width = s->width; 8748c2ecf20Sopenharmony_ci pix->height = s->height; 8758c2ecf20Sopenharmony_ci pix->bytesperline = s->stride; 8768c2ecf20Sopenharmony_ci pix->field = V4L2_FIELD_NONE; 8778c2ecf20Sopenharmony_ci pix->pixelformat = s->pixfmt; 8788c2ecf20Sopenharmony_ci pix->colorspace = s->colorspace; 8798c2ecf20Sopenharmony_ci pix->xfer_func = s->xfer_func; 8808c2ecf20Sopenharmony_ci pix->ycbcr_enc = s->ycbcr_enc; 8818c2ecf20Sopenharmony_ci pix->quantization = s->quantization; 8828c2ecf20Sopenharmony_ci pix->sizeimage = pix->bytesperline * pix->height; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci return 0; 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic int cobalt_enum_fmt_vid_out(struct file *file, void *priv_fh, 8888c2ecf20Sopenharmony_ci struct v4l2_fmtdesc *f) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci switch (f->index) { 8918c2ecf20Sopenharmony_ci case 0: 8928c2ecf20Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_YUYV; 8938c2ecf20Sopenharmony_ci break; 8948c2ecf20Sopenharmony_ci case 1: 8958c2ecf20Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_BGR32; 8968c2ecf20Sopenharmony_ci break; 8978c2ecf20Sopenharmony_ci default: 8988c2ecf20Sopenharmony_ci return -EINVAL; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci return 0; 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cistatic int cobalt_s_fmt_vid_out(struct file *file, void *priv_fh, 9058c2ecf20Sopenharmony_ci struct v4l2_format *f) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 9088c2ecf20Sopenharmony_ci struct v4l2_pix_format *pix = &f->fmt.pix; 9098c2ecf20Sopenharmony_ci struct v4l2_subdev_format sd_fmt = { 0 }; 9108c2ecf20Sopenharmony_ci u32 code; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if (cobalt_try_fmt_vid_out(file, priv_fh, f)) 9138c2ecf20Sopenharmony_ci return -EINVAL; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (vb2_is_busy(&s->q) && (pix->pixelformat != s->pixfmt || 9168c2ecf20Sopenharmony_ci pix->width != s->width || pix->height != s->height || 9178c2ecf20Sopenharmony_ci pix->bytesperline != s->stride)) 9188c2ecf20Sopenharmony_ci return -EBUSY; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci switch (pix->pixelformat) { 9218c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 9228c2ecf20Sopenharmony_ci s->bpp = COBALT_BYTES_PER_PIXEL_YUYV; 9238c2ecf20Sopenharmony_ci code = MEDIA_BUS_FMT_UYVY8_1X16; 9248c2ecf20Sopenharmony_ci break; 9258c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_BGR32: 9268c2ecf20Sopenharmony_ci s->bpp = COBALT_BYTES_PER_PIXEL_RGB32; 9278c2ecf20Sopenharmony_ci code = MEDIA_BUS_FMT_RGB888_1X24; 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci default: 9308c2ecf20Sopenharmony_ci return -EINVAL; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci s->width = pix->width; 9338c2ecf20Sopenharmony_ci s->height = pix->height; 9348c2ecf20Sopenharmony_ci s->stride = pix->bytesperline; 9358c2ecf20Sopenharmony_ci s->pixfmt = pix->pixelformat; 9368c2ecf20Sopenharmony_ci s->colorspace = pix->colorspace; 9378c2ecf20Sopenharmony_ci s->xfer_func = pix->xfer_func; 9388c2ecf20Sopenharmony_ci s->ycbcr_enc = pix->ycbcr_enc; 9398c2ecf20Sopenharmony_ci s->quantization = pix->quantization; 9408c2ecf20Sopenharmony_ci sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; 9418c2ecf20Sopenharmony_ci v4l2_fill_mbus_format(&sd_fmt.format, pix, code); 9428c2ecf20Sopenharmony_ci v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt); 9438c2ecf20Sopenharmony_ci return 0; 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_cistatic int cobalt_enum_input(struct file *file, void *priv_fh, 9478c2ecf20Sopenharmony_ci struct v4l2_input *inp) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (inp->index > 1) 9528c2ecf20Sopenharmony_ci return -EINVAL; 9538c2ecf20Sopenharmony_ci if (inp->index == 0) 9548c2ecf20Sopenharmony_ci snprintf(inp->name, sizeof(inp->name), 9558c2ecf20Sopenharmony_ci "HDMI-%d", s->video_channel); 9568c2ecf20Sopenharmony_ci else 9578c2ecf20Sopenharmony_ci snprintf(inp->name, sizeof(inp->name), 9588c2ecf20Sopenharmony_ci "Generator-%d", s->video_channel); 9598c2ecf20Sopenharmony_ci inp->type = V4L2_INPUT_TYPE_CAMERA; 9608c2ecf20Sopenharmony_ci inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; 9618c2ecf20Sopenharmony_ci if (inp->index == 1) 9628c2ecf20Sopenharmony_ci return 0; 9638c2ecf20Sopenharmony_ci return v4l2_subdev_call(s->sd, 9648c2ecf20Sopenharmony_ci video, g_input_status, &inp->status); 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cistatic int cobalt_g_input(struct file *file, void *priv_fh, unsigned int *i) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci *i = s->input; 9728c2ecf20Sopenharmony_ci return 0; 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic int cobalt_s_input(struct file *file, void *priv_fh, unsigned int i) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci if (i >= 2) 9808c2ecf20Sopenharmony_ci return -EINVAL; 9818c2ecf20Sopenharmony_ci if (vb2_is_busy(&s->q)) 9828c2ecf20Sopenharmony_ci return -EBUSY; 9838c2ecf20Sopenharmony_ci s->input = i; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci cobalt_enable_input(s); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci if (s->input == 1) /* Test Pattern Generator */ 9888c2ecf20Sopenharmony_ci return 0; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci return v4l2_subdev_call(s->sd, video, s_routing, 9918c2ecf20Sopenharmony_ci ADV76XX_PAD_HDMI_PORT_A, 0, 0); 9928c2ecf20Sopenharmony_ci} 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_cistatic int cobalt_enum_output(struct file *file, void *priv_fh, 9958c2ecf20Sopenharmony_ci struct v4l2_output *out) 9968c2ecf20Sopenharmony_ci{ 9978c2ecf20Sopenharmony_ci if (out->index) 9988c2ecf20Sopenharmony_ci return -EINVAL; 9998c2ecf20Sopenharmony_ci snprintf(out->name, sizeof(out->name), "HDMI-%d", out->index); 10008c2ecf20Sopenharmony_ci out->type = V4L2_OUTPUT_TYPE_ANALOG; 10018c2ecf20Sopenharmony_ci out->capabilities = V4L2_OUT_CAP_DV_TIMINGS; 10028c2ecf20Sopenharmony_ci return 0; 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic int cobalt_g_output(struct file *file, void *priv_fh, unsigned int *i) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci *i = 0; 10088c2ecf20Sopenharmony_ci return 0; 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic int cobalt_s_output(struct file *file, void *priv_fh, unsigned int i) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci return i ? -EINVAL : 0; 10148c2ecf20Sopenharmony_ci} 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_cistatic int cobalt_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) 10178c2ecf20Sopenharmony_ci{ 10188c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 10198c2ecf20Sopenharmony_ci u32 pad = edid->pad; 10208c2ecf20Sopenharmony_ci int ret; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (edid->pad >= (s->is_output ? 1 : 2)) 10238c2ecf20Sopenharmony_ci return -EINVAL; 10248c2ecf20Sopenharmony_ci edid->pad = 0; 10258c2ecf20Sopenharmony_ci ret = v4l2_subdev_call(s->sd, pad, get_edid, edid); 10268c2ecf20Sopenharmony_ci edid->pad = pad; 10278c2ecf20Sopenharmony_ci return ret; 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cistatic int cobalt_s_edid(struct file *file, void *fh, struct v4l2_edid *edid) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 10338c2ecf20Sopenharmony_ci u32 pad = edid->pad; 10348c2ecf20Sopenharmony_ci int ret; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if (edid->pad >= 2) 10378c2ecf20Sopenharmony_ci return -EINVAL; 10388c2ecf20Sopenharmony_ci edid->pad = 0; 10398c2ecf20Sopenharmony_ci ret = v4l2_subdev_call(s->sd, pad, set_edid, edid); 10408c2ecf20Sopenharmony_ci edid->pad = pad; 10418c2ecf20Sopenharmony_ci return ret; 10428c2ecf20Sopenharmony_ci} 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_cistatic int cobalt_subscribe_event(struct v4l2_fh *fh, 10458c2ecf20Sopenharmony_ci const struct v4l2_event_subscription *sub) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci switch (sub->type) { 10488c2ecf20Sopenharmony_ci case V4L2_EVENT_SOURCE_CHANGE: 10498c2ecf20Sopenharmony_ci return v4l2_event_subscribe(fh, sub, 4, NULL); 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci return v4l2_ctrl_subscribe_event(fh, sub); 10528c2ecf20Sopenharmony_ci} 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_cistatic int cobalt_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) 10558c2ecf20Sopenharmony_ci{ 10568c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 10578c2ecf20Sopenharmony_ci struct v4l2_fract fps; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 10608c2ecf20Sopenharmony_ci return -EINVAL; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci fps = v4l2_calc_timeperframe(&s->timings); 10638c2ecf20Sopenharmony_ci a->parm.capture.timeperframe.numerator = fps.numerator; 10648c2ecf20Sopenharmony_ci a->parm.capture.timeperframe.denominator = fps.denominator; 10658c2ecf20Sopenharmony_ci a->parm.capture.readbuffers = 3; 10668c2ecf20Sopenharmony_ci return 0; 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_cistatic int cobalt_g_pixelaspect(struct file *file, void *fh, 10708c2ecf20Sopenharmony_ci int type, struct v4l2_fract *f) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 10738c2ecf20Sopenharmony_ci struct v4l2_dv_timings timings; 10748c2ecf20Sopenharmony_ci int err = 0; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 10778c2ecf20Sopenharmony_ci return -EINVAL; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (s->input == 1) 10808c2ecf20Sopenharmony_ci timings = cea1080p60; 10818c2ecf20Sopenharmony_ci else 10828c2ecf20Sopenharmony_ci err = v4l2_subdev_call(s->sd, video, g_dv_timings, &timings); 10838c2ecf20Sopenharmony_ci if (!err) 10848c2ecf20Sopenharmony_ci *f = v4l2_dv_timings_aspect_ratio(&timings); 10858c2ecf20Sopenharmony_ci return err; 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_cistatic int cobalt_g_selection(struct file *file, void *fh, 10898c2ecf20Sopenharmony_ci struct v4l2_selection *sel) 10908c2ecf20Sopenharmony_ci{ 10918c2ecf20Sopenharmony_ci struct cobalt_stream *s = video_drvdata(file); 10928c2ecf20Sopenharmony_ci struct v4l2_dv_timings timings; 10938c2ecf20Sopenharmony_ci int err = 0; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 10968c2ecf20Sopenharmony_ci return -EINVAL; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (s->input == 1) 10998c2ecf20Sopenharmony_ci timings = cea1080p60; 11008c2ecf20Sopenharmony_ci else 11018c2ecf20Sopenharmony_ci err = v4l2_subdev_call(s->sd, video, g_dv_timings, &timings); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (err) 11048c2ecf20Sopenharmony_ci return err; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci switch (sel->target) { 11078c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP_BOUNDS: 11088c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP_DEFAULT: 11098c2ecf20Sopenharmony_ci sel->r.top = 0; 11108c2ecf20Sopenharmony_ci sel->r.left = 0; 11118c2ecf20Sopenharmony_ci sel->r.width = timings.bt.width; 11128c2ecf20Sopenharmony_ci sel->r.height = timings.bt.height; 11138c2ecf20Sopenharmony_ci break; 11148c2ecf20Sopenharmony_ci default: 11158c2ecf20Sopenharmony_ci return -EINVAL; 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci return 0; 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops cobalt_ioctl_ops = { 11218c2ecf20Sopenharmony_ci .vidioc_querycap = cobalt_querycap, 11228c2ecf20Sopenharmony_ci .vidioc_g_parm = cobalt_g_parm, 11238c2ecf20Sopenharmony_ci .vidioc_log_status = cobalt_log_status, 11248c2ecf20Sopenharmony_ci .vidioc_streamon = vb2_ioctl_streamon, 11258c2ecf20Sopenharmony_ci .vidioc_streamoff = vb2_ioctl_streamoff, 11268c2ecf20Sopenharmony_ci .vidioc_g_pixelaspect = cobalt_g_pixelaspect, 11278c2ecf20Sopenharmony_ci .vidioc_g_selection = cobalt_g_selection, 11288c2ecf20Sopenharmony_ci .vidioc_enum_input = cobalt_enum_input, 11298c2ecf20Sopenharmony_ci .vidioc_g_input = cobalt_g_input, 11308c2ecf20Sopenharmony_ci .vidioc_s_input = cobalt_s_input, 11318c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_cap = cobalt_enum_fmt_vid_cap, 11328c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_cap = cobalt_g_fmt_vid_cap, 11338c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_cap = cobalt_s_fmt_vid_cap, 11348c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_cap = cobalt_try_fmt_vid_cap, 11358c2ecf20Sopenharmony_ci .vidioc_enum_output = cobalt_enum_output, 11368c2ecf20Sopenharmony_ci .vidioc_g_output = cobalt_g_output, 11378c2ecf20Sopenharmony_ci .vidioc_s_output = cobalt_s_output, 11388c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_out = cobalt_enum_fmt_vid_out, 11398c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_out = cobalt_g_fmt_vid_out, 11408c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_out = cobalt_s_fmt_vid_out, 11418c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_out = cobalt_try_fmt_vid_out, 11428c2ecf20Sopenharmony_ci .vidioc_s_dv_timings = cobalt_s_dv_timings, 11438c2ecf20Sopenharmony_ci .vidioc_g_dv_timings = cobalt_g_dv_timings, 11448c2ecf20Sopenharmony_ci .vidioc_query_dv_timings = cobalt_query_dv_timings, 11458c2ecf20Sopenharmony_ci .vidioc_enum_dv_timings = cobalt_enum_dv_timings, 11468c2ecf20Sopenharmony_ci .vidioc_dv_timings_cap = cobalt_dv_timings_cap, 11478c2ecf20Sopenharmony_ci .vidioc_g_edid = cobalt_g_edid, 11488c2ecf20Sopenharmony_ci .vidioc_s_edid = cobalt_s_edid, 11498c2ecf20Sopenharmony_ci .vidioc_subscribe_event = cobalt_subscribe_event, 11508c2ecf20Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 11518c2ecf20Sopenharmony_ci .vidioc_reqbufs = vb2_ioctl_reqbufs, 11528c2ecf20Sopenharmony_ci .vidioc_create_bufs = vb2_ioctl_create_bufs, 11538c2ecf20Sopenharmony_ci .vidioc_querybuf = vb2_ioctl_querybuf, 11548c2ecf20Sopenharmony_ci .vidioc_qbuf = vb2_ioctl_qbuf, 11558c2ecf20Sopenharmony_ci .vidioc_dqbuf = vb2_ioctl_dqbuf, 11568c2ecf20Sopenharmony_ci .vidioc_expbuf = vb2_ioctl_expbuf, 11578c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 11588c2ecf20Sopenharmony_ci .vidioc_g_register = cobalt_g_register, 11598c2ecf20Sopenharmony_ci .vidioc_s_register = cobalt_s_register, 11608c2ecf20Sopenharmony_ci#endif 11618c2ecf20Sopenharmony_ci}; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops cobalt_ioctl_empty_ops = { 11648c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 11658c2ecf20Sopenharmony_ci .vidioc_g_register = cobalt_g_register, 11668c2ecf20Sopenharmony_ci .vidioc_s_register = cobalt_s_register, 11678c2ecf20Sopenharmony_ci#endif 11688c2ecf20Sopenharmony_ci}; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci/* Register device nodes */ 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations cobalt_fops = { 11738c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 11748c2ecf20Sopenharmony_ci .open = v4l2_fh_open, 11758c2ecf20Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 11768c2ecf20Sopenharmony_ci .release = vb2_fop_release, 11778c2ecf20Sopenharmony_ci .poll = vb2_fop_poll, 11788c2ecf20Sopenharmony_ci .mmap = vb2_fop_mmap, 11798c2ecf20Sopenharmony_ci .read = vb2_fop_read, 11808c2ecf20Sopenharmony_ci}; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations cobalt_out_fops = { 11838c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 11848c2ecf20Sopenharmony_ci .open = v4l2_fh_open, 11858c2ecf20Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 11868c2ecf20Sopenharmony_ci .release = vb2_fop_release, 11878c2ecf20Sopenharmony_ci .poll = vb2_fop_poll, 11888c2ecf20Sopenharmony_ci .mmap = vb2_fop_mmap, 11898c2ecf20Sopenharmony_ci .write = vb2_fop_write, 11908c2ecf20Sopenharmony_ci}; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations cobalt_empty_fops = { 11938c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 11948c2ecf20Sopenharmony_ci .open = v4l2_fh_open, 11958c2ecf20Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 11968c2ecf20Sopenharmony_ci .release = v4l2_fh_release, 11978c2ecf20Sopenharmony_ci}; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic int cobalt_node_register(struct cobalt *cobalt, int node) 12008c2ecf20Sopenharmony_ci{ 12018c2ecf20Sopenharmony_ci static const struct v4l2_dv_timings dv1080p60 = 12028c2ecf20Sopenharmony_ci V4L2_DV_BT_CEA_1920X1080P60; 12038c2ecf20Sopenharmony_ci struct cobalt_stream *s = cobalt->streams + node; 12048c2ecf20Sopenharmony_ci struct video_device *vdev = &s->vdev; 12058c2ecf20Sopenharmony_ci struct vb2_queue *q = &s->q; 12068c2ecf20Sopenharmony_ci int ret; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci mutex_init(&s->lock); 12098c2ecf20Sopenharmony_ci spin_lock_init(&s->irqlock); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci snprintf(vdev->name, sizeof(vdev->name), 12128c2ecf20Sopenharmony_ci "%s-%d", cobalt->v4l2_dev.name, node); 12138c2ecf20Sopenharmony_ci s->width = 1920; 12148c2ecf20Sopenharmony_ci /* Audio frames are just 4 lines of 1920 bytes */ 12158c2ecf20Sopenharmony_ci s->height = s->is_audio ? 4 : 1080; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (s->is_audio) { 12188c2ecf20Sopenharmony_ci s->bpp = 1; 12198c2ecf20Sopenharmony_ci s->pixfmt = V4L2_PIX_FMT_GREY; 12208c2ecf20Sopenharmony_ci } else if (s->is_output) { 12218c2ecf20Sopenharmony_ci s->bpp = COBALT_BYTES_PER_PIXEL_RGB32; 12228c2ecf20Sopenharmony_ci s->pixfmt = V4L2_PIX_FMT_BGR32; 12238c2ecf20Sopenharmony_ci } else { 12248c2ecf20Sopenharmony_ci s->bpp = COBALT_BYTES_PER_PIXEL_YUYV; 12258c2ecf20Sopenharmony_ci s->pixfmt = V4L2_PIX_FMT_YUYV; 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci s->colorspace = V4L2_COLORSPACE_SRGB; 12288c2ecf20Sopenharmony_ci s->stride = s->width * s->bpp; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci if (!s->is_audio) { 12318c2ecf20Sopenharmony_ci if (s->is_dummy) 12328c2ecf20Sopenharmony_ci cobalt_warn("Setting up dummy video node %d\n", node); 12338c2ecf20Sopenharmony_ci vdev->v4l2_dev = &cobalt->v4l2_dev; 12348c2ecf20Sopenharmony_ci if (s->is_dummy) 12358c2ecf20Sopenharmony_ci vdev->fops = &cobalt_empty_fops; 12368c2ecf20Sopenharmony_ci else 12378c2ecf20Sopenharmony_ci vdev->fops = s->is_output ? &cobalt_out_fops : 12388c2ecf20Sopenharmony_ci &cobalt_fops; 12398c2ecf20Sopenharmony_ci vdev->release = video_device_release_empty; 12408c2ecf20Sopenharmony_ci vdev->vfl_dir = s->is_output ? VFL_DIR_TX : VFL_DIR_RX; 12418c2ecf20Sopenharmony_ci vdev->lock = &s->lock; 12428c2ecf20Sopenharmony_ci if (s->sd) 12438c2ecf20Sopenharmony_ci vdev->ctrl_handler = s->sd->ctrl_handler; 12448c2ecf20Sopenharmony_ci s->timings = dv1080p60; 12458c2ecf20Sopenharmony_ci v4l2_subdev_call(s->sd, video, s_dv_timings, &s->timings); 12468c2ecf20Sopenharmony_ci if (!s->is_output && s->sd) 12478c2ecf20Sopenharmony_ci cobalt_enable_input(s); 12488c2ecf20Sopenharmony_ci vdev->ioctl_ops = s->is_dummy ? &cobalt_ioctl_empty_ops : 12498c2ecf20Sopenharmony_ci &cobalt_ioctl_ops; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&s->bufs); 12538c2ecf20Sopenharmony_ci q->type = s->is_output ? V4L2_BUF_TYPE_VIDEO_OUTPUT : 12548c2ecf20Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_CAPTURE; 12558c2ecf20Sopenharmony_ci q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 12568c2ecf20Sopenharmony_ci q->io_modes |= s->is_output ? VB2_WRITE : VB2_READ; 12578c2ecf20Sopenharmony_ci q->drv_priv = s; 12588c2ecf20Sopenharmony_ci q->buf_struct_size = sizeof(struct cobalt_buffer); 12598c2ecf20Sopenharmony_ci q->ops = &cobalt_qops; 12608c2ecf20Sopenharmony_ci q->mem_ops = &vb2_dma_sg_memops; 12618c2ecf20Sopenharmony_ci q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 12628c2ecf20Sopenharmony_ci q->min_buffers_needed = 2; 12638c2ecf20Sopenharmony_ci q->lock = &s->lock; 12648c2ecf20Sopenharmony_ci q->dev = &cobalt->pci_dev->dev; 12658c2ecf20Sopenharmony_ci vdev->queue = q; 12668c2ecf20Sopenharmony_ci vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; 12678c2ecf20Sopenharmony_ci if (s->is_output) 12688c2ecf20Sopenharmony_ci vdev->device_caps |= V4L2_CAP_VIDEO_OUTPUT; 12698c2ecf20Sopenharmony_ci else 12708c2ecf20Sopenharmony_ci vdev->device_caps |= V4L2_CAP_VIDEO_CAPTURE; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci video_set_drvdata(vdev, s); 12738c2ecf20Sopenharmony_ci ret = vb2_queue_init(q); 12748c2ecf20Sopenharmony_ci if (!s->is_audio && ret == 0) 12758c2ecf20Sopenharmony_ci ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 12768c2ecf20Sopenharmony_ci else if (!s->is_dummy) 12778c2ecf20Sopenharmony_ci ret = cobalt_alsa_init(s); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (ret < 0) { 12808c2ecf20Sopenharmony_ci if (!s->is_audio) 12818c2ecf20Sopenharmony_ci cobalt_err("couldn't register v4l2 device node %d\n", 12828c2ecf20Sopenharmony_ci node); 12838c2ecf20Sopenharmony_ci return ret; 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci cobalt_info("registered node %d\n", node); 12868c2ecf20Sopenharmony_ci return 0; 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci/* Initialize v4l2 variables and register v4l2 devices */ 12908c2ecf20Sopenharmony_ciint cobalt_nodes_register(struct cobalt *cobalt) 12918c2ecf20Sopenharmony_ci{ 12928c2ecf20Sopenharmony_ci int node, ret; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci /* Setup V4L2 Devices */ 12958c2ecf20Sopenharmony_ci for (node = 0; node < COBALT_NUM_STREAMS; node++) { 12968c2ecf20Sopenharmony_ci ret = cobalt_node_register(cobalt, node); 12978c2ecf20Sopenharmony_ci if (ret) 12988c2ecf20Sopenharmony_ci return ret; 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci return 0; 13018c2ecf20Sopenharmony_ci} 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci/* Unregister v4l2 devices */ 13048c2ecf20Sopenharmony_civoid cobalt_nodes_unregister(struct cobalt *cobalt) 13058c2ecf20Sopenharmony_ci{ 13068c2ecf20Sopenharmony_ci int node; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci /* Teardown all streams */ 13098c2ecf20Sopenharmony_ci for (node = 0; node < COBALT_NUM_STREAMS; node++) { 13108c2ecf20Sopenharmony_ci struct cobalt_stream *s = cobalt->streams + node; 13118c2ecf20Sopenharmony_ci struct video_device *vdev = &s->vdev; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci if (!s->is_audio) 13148c2ecf20Sopenharmony_ci video_unregister_device(vdev); 13158c2ecf20Sopenharmony_ci else if (!s->is_dummy) 13168c2ecf20Sopenharmony_ci cobalt_alsa_exit(s); 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci} 1319