File Index
Files and directories
Sign in
FILE

cobalt-v4l2.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/pci/cobalt/cobalt-v4l2.c C
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  cobalt V4L2 API
   4 *
   5 *  Derived from ivtv-ioctl.c and cx18-fileops.c
   6 *
   7 *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
   8 *  All rights reserved.
   9 */
  10
  11#include <linux/dma-mapping.h>
  12#include <linux/delay.h>
  13#include <linux/math64.h>
  14#include <linux/pci.h>
  15#include <linux/v4l2-dv-timings.h>
  16
  17#include <media/v4l2-ctrls.h>
  18#include <media/v4l2-event.h>
  19#include <media/v4l2-dv-timings.h>
  20#include <media/i2c/adv7604.h>
  21#include <media/i2c/adv7842.h>
  22
  23#include "cobalt-alsa.h"
  24#include "cobalt-cpld.h"
  25#include "cobalt-driver.h"
  26#include "cobalt-v4l2.h"
  27#include "cobalt-irq.h"
  28#include "cobalt-omnitek.h"
  29
  30static const struct v4l2_dv_timings cea1080p60 = V4L2_DV_BT_CEA_1920X1080P60;
  31
  32/* vb2 DMA streaming ops */
  33
  34static int cobalt_queue_setup(struct vb2_queue *q,
  35			unsigned int *num_buffers, unsigned int *num_planes,
  36			unsigned int sizes[], struct device *alloc_devs[])
  37{
  38	struct cobalt_stream *s = q->drv_priv;
  39	unsigned size = s->stride * s->height;
  40
  41	if (*num_buffers < 3)
  42		*num_buffers = 3;
  43	if (*num_buffers > NR_BUFS)
  44		*num_buffers = NR_BUFS;
  45	if (*num_planes)
  46		return sizes[0] < size ? -EINVAL : 0;
  47	*num_planes = 1;
  48	sizes[0] = size;
  49	return 0;
  50}
  51
  52static int cobalt_buf_init(struct vb2_buffer *vb)
  53{
  54	struct cobalt_stream *s = vb->vb2_queue->drv_priv;
  55	struct cobalt *cobalt = s->cobalt;
  56	const size_t max_pages_per_line =
  57		(COBALT_MAX_WIDTH * COBALT_MAX_BPP) / PAGE_SIZE + 2;
  58	const size_t bytes =
  59		COBALT_MAX_HEIGHT * max_pages_per_line * 0x20;
  60	const size_t audio_bytes = ((1920 * 4) / PAGE_SIZE + 1) * 0x20;
  61	struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->index];
  62	struct sg_table *sg_desc = vb2_dma_sg_plane_desc(vb, 0);
  63	unsigned size;
  64	int ret;
  65
  66	size = s->stride * s->height;
  67	if (vb2_plane_size(vb, 0) < size) {
  68		cobalt_info("data will not fit into plane (%lu < %u)\n",
  69					vb2_plane_size(vb, 0), size);
  70		return -EINVAL;
  71	}
  72
  73	if (desc->virt == NULL) {
  74		desc->dev = &cobalt->pci_dev->dev;
  75		descriptor_list_allocate(desc,
  76			s->is_audio ? audio_bytes : bytes);
  77		if (desc->virt == NULL)
  78			return -ENOMEM;
  79	}
  80	ret = descriptor_list_create(cobalt, sg_desc->sgl,
  81			!s->is_output, sg_desc->nents, size,
  82			s->width * s->bpp, s->stride, desc);
  83	if (ret)
  84		descriptor_list_free(desc);
  85	return ret;
  86}
  87
  88static void cobalt_buf_cleanup(struct vb2_buffer *vb)
  89{
  90	struct cobalt_stream *s = vb->vb2_queue->drv_priv;
  91	struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->index];
  92
  93	descriptor_list_free(desc);
  94}
  95
  96static int cobalt_buf_prepare(struct vb2_buffer *vb)
  97{
  98	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
  99	struct cobalt_stream *s = vb->vb2_queue->drv_priv;
 100
 101	vb2_set_plane_payload(vb, 0, s->stride * s->height);
 102	vbuf->field = V4L2_FIELD_NONE;
 103	return 0;
 104}
 105
 106static void chain_all_buffers(struct cobalt_stream *s)
 107{
 108	struct sg_dma_desc_info *desc[NR_BUFS];
 109	struct cobalt_buffer *cb;
 110	int i = 0;
 111
 112	list_for_each_entry(cb, &s->bufs, list) {
 113		desc[i] = &s->dma_desc_info[cb->vb.vb2_buf.index];
 114		if (i > 0)
 115			descriptor_list_chain(desc[i-1], desc[i]);
 116		i++;
 117	}
 118}
 119
 120static void cobalt_buf_queue(struct vb2_buffer *vb)
 121{
 122	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 123	struct vb2_queue *q = vb->vb2_queue;
 124	struct cobalt_stream *s = q->drv_priv;
 125	struct cobalt_buffer *cb = to_cobalt_buffer(vbuf);
 126	struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->index];
 127	unsigned long flags;
 128
 129	/* Prepare new buffer */
 130	descriptor_list_loopback(desc);
 131	descriptor_list_interrupt_disable(desc);
 132
 133	spin_lock_irqsave(&s->irqlock, flags);
 134	list_add_tail(&cb->list, &s->bufs);
 135	chain_all_buffers(s);
 136	spin_unlock_irqrestore(&s->irqlock, flags);
 137}
 138
 139static void cobalt_enable_output(struct cobalt_stream *s)
 140{
 141	struct cobalt *cobalt = s->cobalt;
 142	struct v4l2_bt_timings *bt = &s->timings.bt;
 143	struct m00514_syncgen_flow_evcnt_regmap __iomem *vo =
 144		COBALT_TX_BASE(cobalt);
 145	unsigned fmt = s->pixfmt != V4L2_PIX_FMT_BGR32 ?
 146			M00514_CONTROL_BITMAP_FORMAT_16_BPP_MSK : 0;
 147	struct v4l2_subdev_format sd_fmt = {
 148		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
 149	};
 150	u64 clk = bt->pixelclock;
 151
 152	if (bt->flags & V4L2_DV_FL_REDUCED_FPS)
 153		clk = div_u64(clk * 1000ULL, 1001);
 154	if (!cobalt_cpld_set_freq(cobalt, clk)) {
 155		cobalt_err("pixelclock out of range\n");
 156		return;
 157	}
 158
 159	sd_fmt.format.colorspace = s->colorspace;
 160	sd_fmt.format.xfer_func = s->xfer_func;
 161	sd_fmt.format.ycbcr_enc = s->ycbcr_enc;
 162	sd_fmt.format.quantization = s->quantization;
 163	sd_fmt.format.width = bt->width;
 164	sd_fmt.format.height = bt->height;
 165
 166	/* Set up FDMA packer */
 167	switch (s->pixfmt) {
 168	case V4L2_PIX_FMT_YUYV:
 169		sd_fmt.format.code = MEDIA_BUS_FMT_UYVY8_1X16;
 170		break;
 171	case V4L2_PIX_FMT_BGR32:
 172		sd_fmt.format.code = MEDIA_BUS_FMT_RGB888_1X24;
 173		break;
 174	}
 175	v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt);
 176
 177	iowrite32(0, &vo->control);
 178	/* 1080p60 */
 179	iowrite32(bt->hsync, &vo->sync_generator_h_sync_length);
 180	iowrite32(bt->hbackporch, &vo->sync_generator_h_backporch_length);
 181	iowrite32(bt->width, &vo->sync_generator_h_active_length);
 182	iowrite32(bt->hfrontporch, &vo->sync_generator_h_frontporch_length);
 183	iowrite32(bt->vsync, &vo->sync_generator_v_sync_length);
 184	iowrite32(bt->vbackporch, &vo->sync_generator_v_backporch_length);
 185	iowrite32(bt->height, &vo->sync_generator_v_active_length);
 186	iowrite32(bt->vfrontporch, &vo->sync_generator_v_frontporch_length);
 187	iowrite32(0x9900c1, &vo->error_color);
 188
 189	iowrite32(M00514_CONTROL_BITMAP_SYNC_GENERATOR_LOAD_PARAM_MSK | fmt,
 190		  &vo->control);
 191	iowrite32(M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK | fmt, &vo->control);
 192	iowrite32(M00514_CONTROL_BITMAP_SYNC_GENERATOR_ENABLE_MSK |
 193		  M00514_CONTROL_BITMAP_FLOW_CTRL_OUTPUT_ENABLE_MSK |
 194		  fmt, &vo->control);
 195}
 196
 197static void cobalt_enable_input(struct cobalt_stream *s)
 198{
 199	struct cobalt *cobalt = s->cobalt;
 200	int ch = (int)s->video_channel;
 201	struct m00235_fdma_packer_regmap __iomem *packer;
 202	struct v4l2_subdev_format sd_fmt_yuyv = {
 203		.pad = s->pad_source,
 204		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
 205		.format.code = MEDIA_BUS_FMT_YUYV8_1X16,
 206	};
 207	struct v4l2_subdev_format sd_fmt_rgb = {
 208		.pad = s->pad_source,
 209		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
 210		.format.code = MEDIA_BUS_FMT_RGB888_1X24,
 211	};
 212
 213	cobalt_dbg(1, "video_channel %d (%s, %s)\n",
 214		   s->video_channel,
 215		   s->input == 0 ? "hdmi" : "generator",
 216		   "YUYV");
 217
 218	packer = COBALT_CVI_PACKER(cobalt, ch);
 219
 220	/* Set up FDMA packer */
 221	switch (s->pixfmt) {
 222	case V4L2_PIX_FMT_YUYV:
 223		iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK |
 224			  (1 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST),
 225			  &packer->control);
 226		v4l2_subdev_call(s->sd, pad, set_fmt, NULL,
 227				 &sd_fmt_yuyv);
 228		break;
 229	case V4L2_PIX_FMT_RGB24:
 230		iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK |
 231			  (2 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST),
 232			  &packer->control);
 233		v4l2_subdev_call(s->sd, pad, set_fmt, NULL,
 234				 &sd_fmt_rgb);
 235		break;
 236	case V4L2_PIX_FMT_BGR32:
 237		iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK |
 238			  M00235_CONTROL_BITMAP_ENDIAN_FORMAT_MSK |
 239			  (3 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST),
 240			  &packer->control);
 241		v4l2_subdev_call(s->sd, pad, set_fmt, NULL,
 242				 &sd_fmt_rgb);
 243		break;
 244	}
 245}
 246
 247static void cobalt_dma_start_streaming(struct cobalt_stream *s)
 248{
 249	struct cobalt *cobalt = s->cobalt;
 250	int rx = s->video_channel;
 251	struct m00460_evcnt_regmap __iomem *evcnt =
 252		COBALT_CVI_EVCNT(cobalt, rx);
 253	struct cobalt_buffer *cb;
 254	unsigned long flags;
 255
 256	spin_lock_irqsave(&s->irqlock, flags);
 257	if (!s->is_output) {
 258		iowrite32(M00460_CONTROL_BITMAP_CLEAR_MSK, &evcnt->control);
 259		iowrite32(M00460_CONTROL_BITMAP_ENABLE_MSK, &evcnt->control);
 260	} else {
 261		struct m00514_syncgen_flow_evcnt_regmap __iomem *vo =
 262			COBALT_TX_BASE(cobalt);
 263		u32 ctrl = ioread32(&vo->control);
 264
 265		ctrl &= ~(M00514_CONTROL_BITMAP_EVCNT_ENABLE_MSK |
 266			  M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK);
 267		iowrite32(ctrl | M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK,
 268			  &vo->control);
 269		iowrite32(ctrl | M00514_CONTROL_BITMAP_EVCNT_ENABLE_MSK,
 270			  &vo->control);
 271	}
 272	cb = list_first_entry(&s->bufs, struct cobalt_buffer, list);
 273	omni_sg_dma_start(s, &s->dma_desc_info[cb->vb.vb2_buf.index]);
 274	spin_unlock_irqrestore(&s->irqlock, flags);
 275}
 276
 277static int cobalt_start_streaming(struct vb2_queue *q, unsigned int count)
 278{
 279	struct cobalt_stream *s = q->drv_priv;
 280	struct cobalt *cobalt = s->cobalt;
 281	struct m00233_video_measure_regmap __iomem *vmr;
 282	struct m00473_freewheel_regmap __iomem *fw;
 283	struct m00479_clk_loss_detector_regmap __iomem *clkloss;
 284	int rx = s->video_channel;
 285	struct m00389_cvi_regmap __iomem *cvi = COBALT_CVI(cobalt, rx);
 286	struct m00460_evcnt_regmap __iomem *evcnt = COBALT_CVI_EVCNT(cobalt, rx);
 287	struct v4l2_bt_timings *bt = &s->timings.bt;
 288	u64 tot_size;
 289	u32 clk_freq;
 290
 291	if (s->is_audio)
 292		goto done;
 293	if (s->is_output) {
 294		s->unstable_frame = false;
 295		cobalt_enable_output(s);
 296		goto done;
 297	}
 298
 299	cobalt_enable_input(s);
 300
 301	fw = COBALT_CVI_FREEWHEEL(cobalt, rx);
 302	vmr = COBALT_CVI_VMR(cobalt, rx);
 303	clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx);
 304
 305	iowrite32(M00460_CONTROL_BITMAP_CLEAR_MSK, &evcnt->control);
 306	iowrite32(M00460_CONTROL_BITMAP_ENABLE_MSK, &evcnt->control);
 307	iowrite32(bt->width, &cvi->frame_width);
 308	iowrite32(bt->height, &cvi->frame_height);
 309	tot_size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
 310	iowrite32(div_u64((u64)V4L2_DV_BT_FRAME_WIDTH(bt) * COBALT_CLK * 4,
 311			  bt->pixelclock), &vmr->hsync_timeout_val);
 312	iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control);
 313	clk_freq = ioread32(&fw->clk_freq);
 314	iowrite32(clk_freq / 1000000, &clkloss->ref_clk_cnt_val);
 315	/* The lower bound for the clock frequency is 0.5% lower as is
 316	 * allowed by the spec */
 317	iowrite32(div_u64(bt->pixelclock * 995, 1000000000),
 318		  &clkloss->test_clk_cnt_val);
 319	/* will be enabled after the first frame has been received */
 320	iowrite32(bt->width * bt->height, &fw->active_length);
 321	iowrite32(div_u64((u64)clk_freq * tot_size, bt->pixelclock),
 322		  &fw->total_length);
 323	iowrite32(M00233_IRQ_TRIGGERS_BITMAP_VACTIVE_AREA_MSK |
 324		  M00233_IRQ_TRIGGERS_BITMAP_HACTIVE_AREA_MSK,
 325		  &vmr->irq_triggers);
 326	iowrite32(0, &cvi->control);
 327	iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control);
 328
 329	iowrite32(0xff, &fw->output_color);
 330	iowrite32(M00479_CTRL_BITMAP_ENABLE_MSK, &clkloss->ctrl);
 331	iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK |
 332		  M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK, &fw->ctrl);
 333	s->unstable_frame = true;
 334	s->enable_freewheel = false;
 335	s->enable_cvi = false;
 336	s->skip_first_frames = 0;
 337
 338done:
 339	s->sequence = 0;
 340	cobalt_dma_start_streaming(s);
 341	return 0;
 342}
 343
 344static void cobalt_dma_stop_streaming(struct cobalt_stream *s)
 345{
 346	struct cobalt *cobalt = s->cobalt;
 347	struct sg_dma_desc_info *desc;
 348	struct cobalt_buffer *cb;
 349	unsigned long flags;
 350	int timeout_msec = 100;
 351	int rx = s->video_channel;
 352	struct m00460_evcnt_regmap __iomem *evcnt =
 353		COBALT_CVI_EVCNT(cobalt, rx);
 354
 355	if (!s->is_output) {
 356		iowrite32(0, &evcnt->control);
 357	} else if (!s->is_audio) {
 358		struct m00514_syncgen_flow_evcnt_regmap __iomem *vo =
 359			COBALT_TX_BASE(cobalt);
 360
 361		iowrite32(M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK, &vo->control);
 362		iowrite32(0, &vo->control);
 363	}
 364
 365	/* Try to stop the DMA engine gracefully */
 366	spin_lock_irqsave(&s->irqlock, flags);
 367	list_for_each_entry(cb, &s->bufs, list) {
 368		desc = &s->dma_desc_info[cb->vb.vb2_buf.index];
 369		/* Stop DMA after this descriptor chain */
 370		descriptor_list_end_of_chain(desc);
 371	}
 372	spin_unlock_irqrestore(&s->irqlock, flags);
 373
 374	/* Wait 100 millisecond for DMA to finish, abort on timeout. */
 375	if (!wait_event_timeout(s->q.done_wq, is_dma_done(s),
 376				msecs_to_jiffies(timeout_msec))) {
 377		omni_sg_dma_abort_channel(s);
 378		pr_warn("aborted\n");
 379	}
 380	cobalt_write_bar0(cobalt, DMA_INTERRUPT_STATUS_REG,
 381			1 << s->dma_channel);
 382}
 383
 384static void cobalt_stop_streaming(struct vb2_queue *q)
 385{
 386	struct cobalt_stream *s = q->drv_priv;
 387	struct cobalt *cobalt = s->cobalt;
 388	int rx = s->video_channel;
 389	struct m00233_video_measure_regmap __iomem *vmr;
 390	struct m00473_freewheel_regmap __iomem *fw;
 391	struct m00479_clk_loss_detector_regmap __iomem *clkloss;
 392	struct cobalt_buffer *cb;
 393	struct list_head *p, *safe;
 394	unsigned long flags;
 395
 396	cobalt_dma_stop_streaming(s);
 397
 398	/* Return all buffers to user space */
 399	spin_lock_irqsave(&s->irqlock, flags);
 400	list_for_each_safe(p, safe, &s->bufs) {
 401		cb = list_entry(p, struct cobalt_buffer, list);
 402		list_del(&cb->list);
 403		vb2_buffer_done(&cb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
 404	}
 405	spin_unlock_irqrestore(&s->irqlock, flags);
 406
 407	if (s->is_audio || s->is_output)
 408		return;
 409
 410	fw = COBALT_CVI_FREEWHEEL(cobalt, rx);
 411	vmr = COBALT_CVI_VMR(cobalt, rx);
 412	clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx);
 413	iowrite32(0, &vmr->control);
 414	iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control);
 415	iowrite32(0, &fw->ctrl);
 416	iowrite32(0, &clkloss->ctrl);
 417}
 418
 419static const struct vb2_ops cobalt_qops = {
 420	.queue_setup = cobalt_queue_setup,
 421	.buf_init = cobalt_buf_init,
 422	.buf_cleanup = cobalt_buf_cleanup,
 423	.buf_prepare = cobalt_buf_prepare,
 424	.buf_queue = cobalt_buf_queue,
 425	.start_streaming = cobalt_start_streaming,
 426	.stop_streaming = cobalt_stop_streaming,
 427};
 428
 429/* V4L2 ioctls */
 430
 431#ifdef CONFIG_VIDEO_ADV_DEBUG
 432static int cobalt_cobaltc(struct cobalt *cobalt, unsigned int cmd, void *arg)
 433{
 434	struct v4l2_dbg_register *regs = arg;
 435	void __iomem *adrs = cobalt->bar1 + regs->reg;
 436
 437	cobalt_info("cobalt_cobaltc: adrs = %p\n", adrs);
 438
 439	if (!capable(CAP_SYS_ADMIN))
 440		return -EPERM;
 441
 442	regs->size = 4;
 443	if (cmd == VIDIOC_DBG_S_REGISTER)
 444		iowrite32(regs->val, adrs);
 445	else
 446		regs->val = ioread32(adrs);
 447	return 0;
 448}
 449
 450static int cobalt_g_register(struct file *file, void *priv,
 451		struct v4l2_dbg_register *reg)
 452{
 453	struct cobalt_stream *s = video_drvdata(file);
 454	struct cobalt *cobalt = s->cobalt;
 455
 456	return cobalt_cobaltc(cobalt, VIDIOC_DBG_G_REGISTER, reg);
 457}
 458
 459static int cobalt_s_register(struct file *file, void *priv,
 460		const struct v4l2_dbg_register *reg)
 461{
 462	struct cobalt_stream *s = video_drvdata(file);
 463	struct cobalt *cobalt = s->cobalt;
 464
 465	return cobalt_cobaltc(cobalt, VIDIOC_DBG_S_REGISTER,
 466			(struct v4l2_dbg_register *)reg);
 467}
 468#endif
 469
 470static int cobalt_querycap(struct file *file, void *priv,
 471				struct v4l2_capability *vcap)
 472{
 473	struct cobalt_stream *s = video_drvdata(file);
 474	struct cobalt *cobalt = s->cobalt;
 475
 476	strscpy(vcap->driver, "cobalt", sizeof(vcap->driver));
 477	strscpy(vcap->card, "cobalt", sizeof(vcap->card));
 478	snprintf(vcap->bus_info, sizeof(vcap->bus_info),
 479		 "PCIe:%s", pci_name(cobalt->pci_dev));
 480	vcap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE |
 481		V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS;
 482	if (cobalt->have_hsma_tx)
 483		vcap->capabilities |= V4L2_CAP_VIDEO_OUTPUT;
 484	return 0;
 485}
 486
 487static void cobalt_video_input_status_show(struct cobalt_stream *s)
 488{
 489	struct m00389_cvi_regmap __iomem *cvi;
 490	struct m00233_video_measure_regmap __iomem *vmr;
 491	struct m00473_freewheel_regmap __iomem *fw;
 492	struct m00479_clk_loss_detector_regmap __iomem *clkloss;
 493	struct m00235_fdma_packer_regmap __iomem *packer;
 494	int rx = s->video_channel;
 495	struct cobalt *cobalt = s->cobalt;
 496	u32 cvi_ctrl, cvi_stat;
 497	u32 vmr_ctrl, vmr_stat;
 498
 499	cvi = COBALT_CVI(cobalt, rx);
 500	vmr = COBALT_CVI_VMR(cobalt, rx);
 501	fw = COBALT_CVI_FREEWHEEL(cobalt, rx);
 502	clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx);
 503	packer = COBALT_CVI_PACKER(cobalt, rx);
 504	cvi_ctrl = ioread32(&cvi->control);
 505	cvi_stat = ioread32(&cvi->status);
 506	vmr_ctrl = ioread32(&vmr->control);
 507	vmr_stat = ioread32(&vmr->status);
 508	cobalt_info("rx%d: cvi resolution: %dx%d\n", rx,
 509		    ioread32(&cvi->frame_width), ioread32(&cvi->frame_height));
 510	cobalt_info("rx%d: cvi control: %s%s%s\n", rx,
 511		(cvi_ctrl & M00389_CONTROL_BITMAP_ENABLE_MSK) ?
 512			"enable " : "disable ",
 513		(cvi_ctrl & M00389_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK) ?
 514			"HSync- " : "HSync+ ",
 515		(cvi_ctrl & M00389_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK) ?
 516			"VSync- " : "VSync+ ");
 517	cobalt_info("rx%d: cvi status: %s%s\n", rx,
 518		(cvi_stat & M00389_STATUS_BITMAP_LOCK_MSK) ?
 519			"lock " : "no-lock ",
 520		(cvi_stat & M00389_STATUS_BITMAP_ERROR_MSK) ?
 521			"error " : "no-error ");
 522
 523	cobalt_info("rx%d: Measurements: %s%s%s%s%s%s%s\n", rx,
 524		(vmr_ctrl & M00233_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK) ?
 525			"HSync- " : "HSync+ ",
 526		(vmr_ctrl & M00233_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK) ?
 527			"VSync- " : "VSync+ ",
 528		(vmr_ctrl & M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK) ?
 529			"enabled " : "disabled ",
 530		(vmr_ctrl & M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK) ?
 531			"irq-enabled " : "irq-disabled ",
 532		(vmr_ctrl & M00233_CONTROL_BITMAP_UPDATE_ON_HSYNC_MSK) ?
 533			"update-on-hsync " : "",
 534		(vmr_stat & M00233_STATUS_BITMAP_HSYNC_TIMEOUT_MSK) ?
 535			"hsync-timeout " : "",
 536		(vmr_stat & M00233_STATUS_BITMAP_INIT_DONE_MSK) ?
 537			"init-done" : "");
 538	cobalt_info("rx%d: irq_status: 0x%02x irq_triggers: 0x%02x\n", rx,
 539			ioread32(&vmr->irq_status) & 0xff,
 540			ioread32(&vmr->irq_triggers) & 0xff);
 541	cobalt_info("rx%d: vsync: %d\n", rx, ioread32(&vmr->vsync_time));
 542	cobalt_info("rx%d: vbp: %d\n", rx, ioread32(&vmr->vback_porch));
 543	cobalt_info("rx%d: vact: %d\n", rx, ioread32(&vmr->vactive_area));
 544	cobalt_info("rx%d: vfb: %d\n", rx, ioread32(&vmr->vfront_porch));
 545	cobalt_info("rx%d: hsync: %d\n", rx, ioread32(&vmr->hsync_time));
 546	cobalt_info("rx%d: hbp: %d\n", rx, ioread32(&vmr->hback_porch));
 547	cobalt_info("rx%d: hact: %d\n", rx, ioread32(&vmr->hactive_area));
 548	cobalt_info("rx%d: hfb: %d\n", rx, ioread32(&vmr->hfront_porch));
 549	cobalt_info("rx%d: Freewheeling: %s%s%s\n", rx,
 550		(ioread32(&fw->ctrl) & M00473_CTRL_BITMAP_ENABLE_MSK) ?
 551			"enabled " : "disabled ",
 552		(ioread32(&fw->ctrl) & M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK) ?
 553			"forced " : "",
 554		(ioread32(&fw->status) & M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK) ?
 555			"freewheeling " : "video-passthrough ");
 556	iowrite32(0xff, &vmr->irq_status);
 557	cobalt_info("rx%d: Clock Loss Detection: %s%s\n", rx,
 558		(ioread32(&clkloss->ctrl) & M00479_CTRL_BITMAP_ENABLE_MSK) ?
 559			"enabled " : "disabled ",
 560		(ioread32(&clkloss->status) & M00479_STATUS_BITMAP_CLOCK_MISSING_MSK) ?
 561			"clock-missing " : "found-clock ");
 562	cobalt_info("rx%d: Packer: %x\n", rx, ioread32(&packer->control));
 563}
 564
 565static int cobalt_log_status(struct file *file, void *priv)
 566{
 567	struct cobalt_stream *s = video_drvdata(file);
 568	struct cobalt *cobalt = s->cobalt;
 569	struct m00514_syncgen_flow_evcnt_regmap __iomem *vo =
 570		COBALT_TX_BASE(cobalt);
 571	u8 stat;
 572
 573	cobalt_info("%s", cobalt->hdl_info);
 574	cobalt_info("sysctrl: %08x, sysstat: %08x\n",
 575			cobalt_g_sysctrl(cobalt),
 576			cobalt_g_sysstat(cobalt));
 577	cobalt_info("dma channel: %d, video channel: %d\n",
 578			s->dma_channel, s->video_channel);
 579	cobalt_pcie_status_show(cobalt);
 580	cobalt_cpld_status(cobalt);
 581	cobalt_irq_log_status(cobalt);
 582	v4l2_subdev_call(s->sd, core, log_status);
 583	if (!s->is_output) {
 584		cobalt_video_input_status_show(s);
 585		return 0;
 586	}
 587
 588	stat = ioread32(&vo->rd_status);
 589
 590	cobalt_info("tx: status: %s%s\n",
 591		(stat & M00514_RD_STATUS_BITMAP_FLOW_CTRL_NO_DATA_ERROR_MSK) ?
 592			"no_data " : "",
 593		(stat & M00514_RD_STATUS_BITMAP_READY_BUFFER_FULL_MSK) ?
 594			"ready_buffer_full " : "");
 595	cobalt_info("tx: evcnt: %d\n", ioread32(&vo->rd_evcnt_count));
 596	return 0;
 597}
 598
 599static int cobalt_enum_dv_timings(struct file *file, void *priv,
 600				    struct v4l2_enum_dv_timings *timings)
 601{
 602	struct cobalt_stream *s = video_drvdata(file);
 603
 604	if (s->input == 1) {
 605		if (timings->index)
 606			return -EINVAL;
 607		memset(timings->reserved, 0, sizeof(timings->reserved));
 608		timings->timings = cea1080p60;
 609		return 0;
 610	}
 611	timings->pad = 0;
 612	return v4l2_subdev_call(s->sd,
 613			pad, enum_dv_timings, timings);
 614}
 615
 616static int cobalt_s_dv_timings(struct file *file, void *priv,
 617				    struct v4l2_dv_timings *timings)
 618{
 619	struct cobalt_stream *s = video_drvdata(file);
 620	int err;
 621
 622	if (s->input == 1) {
 623		*timings = cea1080p60;
 624		return 0;
 625	}
 626
 627	if (v4l2_match_dv_timings(timings, &s->timings, 0, true))
 628		return 0;
 629
 630	if (vb2_is_busy(&s->q))
 631		return -EBUSY;
 632
 633	err = v4l2_subdev_call(s->sd,
 634			pad, s_dv_timings, 0, timings);
 635	if (!err) {
 636		s->timings = *timings;
 637		s->width = timings->bt.width;
 638		s->height = timings->bt.height;
 639		s->stride = timings->bt.width * s->bpp;
 640	}
 641	return err;
 642}
 643
 644static int cobalt_g_dv_timings(struct file *file, void *priv,
 645				    struct v4l2_dv_timings *timings)
 646{
 647	struct cobalt_stream *s = video_drvdata(file);
 648
 649	if (s->input == 1) {
 650		*timings = cea1080p60;
 651		return 0;
 652	}
 653	return v4l2_subdev_call(s->sd,
 654			pad, g_dv_timings, 0, timings);
 655}
 656
 657static int cobalt_query_dv_timings(struct file *file, void *priv,
 658				    struct v4l2_dv_timings *timings)
 659{
 660	struct cobalt_stream *s = video_drvdata(file);
 661
 662	if (s->input == 1) {
 663		*timings = cea1080p60;
 664		return 0;
 665	}
 666	return v4l2_subdev_call(s->sd,
 667			pad, query_dv_timings, 0, timings);
 668}
 669
 670static int cobalt_dv_timings_cap(struct file *file, void *priv,
 671				    struct v4l2_dv_timings_cap *cap)
 672{
 673	struct cobalt_stream *s = video_drvdata(file);
 674
 675	cap->pad = 0;
 676	return v4l2_subdev_call(s->sd,
 677			pad, dv_timings_cap, cap);
 678}
 679
 680static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv,
 681		struct v4l2_fmtdesc *f)
 682{
 683	switch (f->index) {
 684	case 0:
 685		f->pixelformat = V4L2_PIX_FMT_YUYV;
 686		break;
 687	case 1:
 688		f->pixelformat = V4L2_PIX_FMT_RGB24;
 689		break;
 690	case 2:
 691		f->pixelformat = V4L2_PIX_FMT_BGR32;
 692		break;
 693	default:
 694		return -EINVAL;
 695	}
 696
 697	return 0;
 698}
 699
 700static int cobalt_g_fmt_vid_cap(struct file *file, void *priv,
 701		struct v4l2_format *f)
 702{
 703	struct cobalt_stream *s = video_drvdata(file);
 704	struct v4l2_pix_format *pix = &f->fmt.pix;
 705
 706	pix->width = s->width;
 707	pix->height = s->height;
 708	pix->bytesperline = s->stride;
 709	pix->field = V4L2_FIELD_NONE;
 710
 711	if (s->input == 1) {
 712		pix->colorspace = V4L2_COLORSPACE_SRGB;
 713	} else {
 714		struct v4l2_subdev_format sd_fmt = {
 715			.pad = s->pad_source,
 716			.which = V4L2_SUBDEV_FORMAT_ACTIVE,
 717		};
 718
 719		v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt);
 720		v4l2_fill_pix_format(pix, &sd_fmt.format);
 721	}
 722
 723	pix->pixelformat = s->pixfmt;
 724	pix->sizeimage = pix->bytesperline * pix->height;
 725
 726	return 0;
 727}
 728
 729static int cobalt_try_fmt_vid_cap(struct file *file, void *priv,
 730		struct v4l2_format *f)
 731{
 732	struct cobalt_stream *s = video_drvdata(file);
 733	struct v4l2_pix_format *pix = &f->fmt.pix;
 734
 735	/* Check for min (QCIF) and max (Full HD) size */
 736	if ((pix->width < 176) || (pix->height < 144)) {
 737		pix->width = 176;
 738		pix->height = 144;
 739	}
 740
 741	if ((pix->width > 1920) || (pix->height > 1080)) {
 742		pix->width = 1920;
 743		pix->height = 1080;
 744	}
 745
 746	/* Make width multiple of 4 */
 747	pix->width &= ~0x3;
 748
 749	/* Make height multiple of 2 */
 750	pix->height &= ~0x1;
 751
 752	if (s->input == 1) {
 753		/* Generator => fixed format only */
 754		pix->width = 1920;
 755		pix->height = 1080;
 756		pix->colorspace = V4L2_COLORSPACE_SRGB;
 757	} else {
 758		struct v4l2_subdev_format sd_fmt = {
 759			.pad = s->pad_source,
 760			.which = V4L2_SUBDEV_FORMAT_ACTIVE,
 761		};
 762
 763		v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt);
 764		v4l2_fill_pix_format(pix, &sd_fmt.format);
 765	}
 766
 767	switch (pix->pixelformat) {
 768	case V4L2_PIX_FMT_YUYV:
 769	default:
 770		pix->bytesperline = max(pix->bytesperline & ~0x3,
 771				pix->width * COBALT_BYTES_PER_PIXEL_YUYV);
 772		pix->pixelformat = V4L2_PIX_FMT_YUYV;
 773		break;
 774	case V4L2_PIX_FMT_RGB24:
 775		pix->bytesperline = max(pix->bytesperline & ~0x3,
 776				pix->width * COBALT_BYTES_PER_PIXEL_RGB24);
 777		break;
 778	case V4L2_PIX_FMT_BGR32:
 779		pix->bytesperline = max(pix->bytesperline & ~0x3,
 780				pix->width * COBALT_BYTES_PER_PIXEL_RGB32);
 781		break;
 782	}
 783
 784	pix->sizeimage = pix->bytesperline * pix->height;
 785	pix->field = V4L2_FIELD_NONE;
 786
 787	return 0;
 788}
 789
 790static int cobalt_s_fmt_vid_cap(struct file *file, void *priv,
 791		struct v4l2_format *f)
 792{
 793	struct cobalt_stream *s = video_drvdata(file);
 794	struct v4l2_pix_format *pix = &f->fmt.pix;
 795
 796	if (vb2_is_busy(&s->q))
 797		return -EBUSY;
 798
 799	if (cobalt_try_fmt_vid_cap(file, priv, f))
 800		return -EINVAL;
 801
 802	s->width = pix->width;
 803	s->height = pix->height;
 804	s->stride = pix->bytesperline;
 805	switch (pix->pixelformat) {
 806	case V4L2_PIX_FMT_YUYV:
 807		s->bpp = COBALT_BYTES_PER_PIXEL_YUYV;
 808		break;
 809	case V4L2_PIX_FMT_RGB24:
 810		s->bpp = COBALT_BYTES_PER_PIXEL_RGB24;
 811		break;
 812	case V4L2_PIX_FMT_BGR32:
 813		s->bpp = COBALT_BYTES_PER_PIXEL_RGB32;
 814		break;
 815	default:
 816		return -EINVAL;
 817	}
 818	s->pixfmt = pix->pixelformat;
 819	cobalt_enable_input(s);
 820
 821	return 0;
 822}
 823
 824static int cobalt_try_fmt_vid_out(struct file *file, void *priv,
 825		struct v4l2_format *f)
 826{
 827	struct v4l2_pix_format *pix = &f->fmt.pix;
 828
 829	/* Check for min (QCIF) and max (Full HD) size */
 830	if ((pix->width < 176) || (pix->height < 144)) {
 831		pix->width = 176;
 832		pix->height = 144;
 833	}
 834
 835	if ((pix->width > 1920) || (pix->height > 1080)) {
 836		pix->width = 1920;
 837		pix->height = 1080;
 838	}
 839
 840	/* Make width multiple of 4 */
 841	pix->width &= ~0x3;
 842
 843	/* Make height multiple of 2 */
 844	pix->height &= ~0x1;
 845
 846	switch (pix->pixelformat) {
 847	case V4L2_PIX_FMT_YUYV:
 848	default:
 849		pix->bytesperline = max(pix->bytesperline & ~0x3,
 850				pix->width * COBALT_BYTES_PER_PIXEL_YUYV);
 851		pix->pixelformat = V4L2_PIX_FMT_YUYV;
 852		break;
 853	case V4L2_PIX_FMT_BGR32:
 854		pix->bytesperline = max(pix->bytesperline & ~0x3,
 855				pix->width * COBALT_BYTES_PER_PIXEL_RGB32);
 856		break;
 857	}
 858
 859	pix->sizeimage = pix->bytesperline * pix->height;
 860	pix->field = V4L2_FIELD_NONE;
 861
 862	return 0;
 863}
 864
 865static int cobalt_g_fmt_vid_out(struct file *file, void *priv,
 866		struct v4l2_format *f)
 867{
 868	struct cobalt_stream *s = video_drvdata(file);
 869	struct v4l2_pix_format *pix = &f->fmt.pix;
 870
 871	pix->width = s->width;
 872	pix->height = s->height;
 873	pix->bytesperline = s->stride;
 874	pix->field = V4L2_FIELD_NONE;
 875	pix->pixelformat = s->pixfmt;
 876	pix->colorspace = s->colorspace;
 877	pix->xfer_func = s->xfer_func;
 878	pix->ycbcr_enc = s->ycbcr_enc;
 879	pix->quantization = s->quantization;
 880	pix->sizeimage = pix->bytesperline * pix->height;
 881
 882	return 0;
 883}
 884
 885static int cobalt_enum_fmt_vid_out(struct file *file, void *priv,
 886		struct v4l2_fmtdesc *f)
 887{
 888	switch (f->index) {
 889	case 0:
 890		f->pixelformat = V4L2_PIX_FMT_YUYV;
 891		break;
 892	case 1:
 893		f->pixelformat = V4L2_PIX_FMT_BGR32;
 894		break;
 895	default:
 896		return -EINVAL;
 897	}
 898
 899	return 0;
 900}
 901
 902static int cobalt_s_fmt_vid_out(struct file *file, void *priv,
 903		struct v4l2_format *f)
 904{
 905	struct cobalt_stream *s = video_drvdata(file);
 906	struct v4l2_pix_format *pix = &f->fmt.pix;
 907	struct v4l2_subdev_format sd_fmt = {
 908		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
 909	};
 910	u32 code;
 911
 912	if (cobalt_try_fmt_vid_out(file, priv, f))
 913		return -EINVAL;
 914
 915	if (vb2_is_busy(&s->q) && (pix->pixelformat != s->pixfmt ||
 916	    pix->width != s->width || pix->height != s->height ||
 917	    pix->bytesperline != s->stride))
 918		return -EBUSY;
 919
 920	switch (pix->pixelformat) {
 921	case V4L2_PIX_FMT_YUYV:
 922		s->bpp = COBALT_BYTES_PER_PIXEL_YUYV;
 923		code = MEDIA_BUS_FMT_UYVY8_1X16;
 924		break;
 925	case V4L2_PIX_FMT_BGR32:
 926		s->bpp = COBALT_BYTES_PER_PIXEL_RGB32;
 927		code = MEDIA_BUS_FMT_RGB888_1X24;
 928		break;
 929	default:
 930		return -EINVAL;
 931	}
 932	s->width = pix->width;
 933	s->height = pix->height;
 934	s->stride = pix->bytesperline;
 935	s->pixfmt = pix->pixelformat;
 936	s->colorspace = pix->colorspace;
 937	s->xfer_func = pix->xfer_func;
 938	s->ycbcr_enc = pix->ycbcr_enc;
 939	s->quantization = pix->quantization;
 940	v4l2_fill_mbus_format(&sd_fmt.format, pix, code);
 941	v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt);
 942	return 0;
 943}
 944
 945static int cobalt_enum_input(struct file *file, void *priv,
 946				 struct v4l2_input *inp)
 947{
 948	struct cobalt_stream *s = video_drvdata(file);
 949
 950	if (inp->index > 1)
 951		return -EINVAL;
 952	if (inp->index == 0)
 953		snprintf(inp->name, sizeof(inp->name),
 954				"HDMI-%d", s->video_channel);
 955	else
 956		snprintf(inp->name, sizeof(inp->name),
 957				"Generator-%d", s->video_channel);
 958	inp->type = V4L2_INPUT_TYPE_CAMERA;
 959	inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
 960	if (inp->index == 1)
 961		return 0;
 962	return v4l2_subdev_call(s->sd,
 963			video, g_input_status, &inp->status);
 964}
 965
 966static int cobalt_g_input(struct file *file, void *priv, unsigned int *i)
 967{
 968	struct cobalt_stream *s = video_drvdata(file);
 969
 970	*i = s->input;
 971	return 0;
 972}
 973
 974static int cobalt_s_input(struct file *file, void *priv, unsigned int i)
 975{
 976	struct cobalt_stream *s = video_drvdata(file);
 977
 978	if (i >= 2)
 979		return -EINVAL;
 980	if (vb2_is_busy(&s->q))
 981		return -EBUSY;
 982	s->input = i;
 983
 984	cobalt_enable_input(s);
 985
 986	if (s->input == 1) /* Test Pattern Generator */
 987		return 0;
 988
 989	return v4l2_subdev_call(s->sd, video, s_routing,
 990			ADV76XX_PAD_HDMI_PORT_A, 0, 0);
 991}
 992
 993static int cobalt_enum_output(struct file *file, void *priv,
 994				 struct v4l2_output *out)
 995{
 996	if (out->index)
 997		return -EINVAL;
 998	snprintf(out->name, sizeof(out->name), "HDMI-%d", out->index);
 999	out->type = V4L2_OUTPUT_TYPE_ANALOG;
1000	out->capabilities = V4L2_OUT_CAP_DV_TIMINGS;
1001	return 0;
1002}
1003
1004static int cobalt_g_output(struct file *file, void *priv, unsigned int *i)
1005{
1006	*i = 0;
1007	return 0;
1008}
1009
1010static int cobalt_s_output(struct file *file, void *priv, unsigned int i)
1011{
1012	return i ? -EINVAL : 0;
1013}
1014
1015static int cobalt_g_edid(struct file *file, void *priv, struct v4l2_edid *edid)
1016{
1017	struct cobalt_stream *s = video_drvdata(file);
1018	u32 pad = edid->pad;
1019	int ret;
1020
1021	if (edid->pad >= (s->is_output ? 1 : 2))
1022		return -EINVAL;
1023	edid->pad = 0;
1024	ret = v4l2_subdev_call(s->sd, pad, get_edid, edid);
1025	edid->pad = pad;
1026	return ret;
1027}
1028
1029static int cobalt_s_edid(struct file *file, void *priv, struct v4l2_edid *edid)
1030{
1031	struct cobalt_stream *s = video_drvdata(file);
1032	u32 pad = edid->pad;
1033	int ret;
1034
1035	if (edid->pad >= 2)
1036		return -EINVAL;
1037	edid->pad = 0;
1038	ret = v4l2_subdev_call(s->sd, pad, set_edid, edid);
1039	edid->pad = pad;
1040	return ret;
1041}
1042
1043static int cobalt_subscribe_event(struct v4l2_fh *fh,
1044				  const struct v4l2_event_subscription *sub)
1045{
1046	switch (sub->type) {
1047	case V4L2_EVENT_SOURCE_CHANGE:
1048		return v4l2_event_subscribe(fh, sub, 4, NULL);
1049	}
1050	return v4l2_ctrl_subscribe_event(fh, sub);
1051}
1052
1053static int cobalt_g_parm(struct file *file, void *priv, struct v4l2_streamparm *a)
1054{
1055	struct cobalt_stream *s = video_drvdata(file);
1056	struct v4l2_fract fps;
1057
1058	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1059		return -EINVAL;
1060
1061	fps = v4l2_calc_timeperframe(&s->timings);
1062	a->parm.capture.timeperframe.numerator = fps.numerator;
1063	a->parm.capture.timeperframe.denominator = fps.denominator;
1064	a->parm.capture.readbuffers = 3;
1065	return 0;
1066}
1067
1068static int cobalt_g_pixelaspect(struct file *file, void *priv,
1069				int type, struct v4l2_fract *f)
1070{
1071	struct cobalt_stream *s = video_drvdata(file);
1072	struct v4l2_dv_timings timings;
1073	int err = 0;
1074
1075	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1076		return -EINVAL;
1077
1078	if (s->input == 1)
1079		timings = cea1080p60;
1080	else
1081		err = v4l2_subdev_call(s->sd, pad, g_dv_timings, 0, &timings);
1082	if (!err)
1083		*f = v4l2_dv_timings_aspect_ratio(&timings);
1084	return err;
1085}
1086
1087static int cobalt_g_selection(struct file *file, void *priv,
1088			      struct v4l2_selection *sel)
1089{
1090	struct cobalt_stream *s = video_drvdata(file);
1091	struct v4l2_dv_timings timings;
1092	int err = 0;
1093
1094	if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1095		return -EINVAL;
1096
1097	if (s->input == 1)
1098		timings = cea1080p60;
1099	else
1100		err = v4l2_subdev_call(s->sd, pad, g_dv_timings, 0, &timings);
1101
1102	if (err)
1103		return err;
1104
1105	switch (sel->target) {
1106	case V4L2_SEL_TGT_CROP_BOUNDS:
1107	case V4L2_SEL_TGT_CROP_DEFAULT:
1108		sel->r.top = 0;
1109		sel->r.left = 0;
1110		sel->r.width = timings.bt.width;
1111		sel->r.height = timings.bt.height;
1112		break;
1113	default:
1114		return -EINVAL;
1115	}
1116	return 0;
1117}
1118
1119static const struct v4l2_ioctl_ops cobalt_ioctl_ops = {
1120	.vidioc_querycap		= cobalt_querycap,
1121	.vidioc_g_parm			= cobalt_g_parm,
1122	.vidioc_log_status		= cobalt_log_status,
1123	.vidioc_streamon		= vb2_ioctl_streamon,
1124	.vidioc_streamoff		= vb2_ioctl_streamoff,
1125	.vidioc_g_pixelaspect		= cobalt_g_pixelaspect,
1126	.vidioc_g_selection		= cobalt_g_selection,
1127	.vidioc_enum_input		= cobalt_enum_input,
1128	.vidioc_g_input			= cobalt_g_input,
1129	.vidioc_s_input			= cobalt_s_input,
1130	.vidioc_enum_fmt_vid_cap	= cobalt_enum_fmt_vid_cap,
1131	.vidioc_g_fmt_vid_cap		= cobalt_g_fmt_vid_cap,
1132	.vidioc_s_fmt_vid_cap		= cobalt_s_fmt_vid_cap,
1133	.vidioc_try_fmt_vid_cap		= cobalt_try_fmt_vid_cap,
1134	.vidioc_enum_output		= cobalt_enum_output,
1135	.vidioc_g_output		= cobalt_g_output,
1136	.vidioc_s_output		= cobalt_s_output,
1137	.vidioc_enum_fmt_vid_out	= cobalt_enum_fmt_vid_out,
1138	.vidioc_g_fmt_vid_out		= cobalt_g_fmt_vid_out,
1139	.vidioc_s_fmt_vid_out		= cobalt_s_fmt_vid_out,
1140	.vidioc_try_fmt_vid_out		= cobalt_try_fmt_vid_out,
1141	.vidioc_s_dv_timings		= cobalt_s_dv_timings,
1142	.vidioc_g_dv_timings		= cobalt_g_dv_timings,
1143	.vidioc_query_dv_timings	= cobalt_query_dv_timings,
1144	.vidioc_enum_dv_timings		= cobalt_enum_dv_timings,
1145	.vidioc_dv_timings_cap		= cobalt_dv_timings_cap,
1146	.vidioc_g_edid			= cobalt_g_edid,
1147	.vidioc_s_edid			= cobalt_s_edid,
1148	.vidioc_subscribe_event		= cobalt_subscribe_event,
1149	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
1150	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
1151	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
1152	.vidioc_querybuf		= vb2_ioctl_querybuf,
1153	.vidioc_qbuf			= vb2_ioctl_qbuf,
1154	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
1155	.vidioc_expbuf			= vb2_ioctl_expbuf,
1156#ifdef CONFIG_VIDEO_ADV_DEBUG
1157	.vidioc_g_register              = cobalt_g_register,
1158	.vidioc_s_register              = cobalt_s_register,
1159#endif
1160};
1161
1162static const struct v4l2_ioctl_ops cobalt_ioctl_empty_ops = {
1163#ifdef CONFIG_VIDEO_ADV_DEBUG
1164	.vidioc_g_register              = cobalt_g_register,
1165	.vidioc_s_register              = cobalt_s_register,
1166#endif
1167};
1168
1169/* Register device nodes */
1170
1171static const struct v4l2_file_operations cobalt_fops = {
1172	.owner = THIS_MODULE,
1173	.open = v4l2_fh_open,
1174	.unlocked_ioctl = video_ioctl2,
1175	.release = vb2_fop_release,
1176	.poll = vb2_fop_poll,
1177	.mmap = vb2_fop_mmap,
1178	.read = vb2_fop_read,
1179};
1180
1181static const struct v4l2_file_operations cobalt_out_fops = {
1182	.owner = THIS_MODULE,
1183	.open = v4l2_fh_open,
1184	.unlocked_ioctl = video_ioctl2,
1185	.release = vb2_fop_release,
1186	.poll = vb2_fop_poll,
1187	.mmap = vb2_fop_mmap,
1188	.write = vb2_fop_write,
1189};
1190
1191static const struct v4l2_file_operations cobalt_empty_fops = {
1192	.owner = THIS_MODULE,
1193	.open = v4l2_fh_open,
1194	.unlocked_ioctl = video_ioctl2,
1195	.release = v4l2_fh_release,
1196};
1197
1198static int cobalt_node_register(struct cobalt *cobalt, int node)
1199{
1200	static const struct v4l2_dv_timings dv1080p60 =
1201		V4L2_DV_BT_CEA_1920X1080P60;
1202	struct cobalt_stream *s = cobalt->streams + node;
1203	struct video_device *vdev = &s->vdev;
1204	struct vb2_queue *q = &s->q;
1205	int ret;
1206
1207	mutex_init(&s->lock);
1208	spin_lock_init(&s->irqlock);
1209
1210	snprintf(vdev->name, sizeof(vdev->name),
1211			"%s-%d", cobalt->v4l2_dev.name, node);
1212	s->width = 1920;
1213	/* Audio frames are just 4 lines of 1920 bytes */
1214	s->height = s->is_audio ? 4 : 1080;
1215
1216	if (s->is_audio) {
1217		s->bpp = 1;
1218		s->pixfmt = V4L2_PIX_FMT_GREY;
1219	} else if (s->is_output) {
1220		s->bpp = COBALT_BYTES_PER_PIXEL_RGB32;
1221		s->pixfmt = V4L2_PIX_FMT_BGR32;
1222	} else {
1223		s->bpp = COBALT_BYTES_PER_PIXEL_YUYV;
1224		s->pixfmt = V4L2_PIX_FMT_YUYV;
1225	}
1226	s->colorspace = V4L2_COLORSPACE_SRGB;
1227	s->stride = s->width * s->bpp;
1228
1229	if (!s->is_audio) {
1230		if (s->is_dummy)
1231			cobalt_warn("Setting up dummy video node %d\n", node);
1232		vdev->v4l2_dev = &cobalt->v4l2_dev;
1233		if (s->is_dummy)
1234			vdev->fops = &cobalt_empty_fops;
1235		else
1236			vdev->fops = s->is_output ? &cobalt_out_fops :
1237						    &cobalt_fops;
1238		vdev->release = video_device_release_empty;
1239		vdev->vfl_dir = s->is_output ? VFL_DIR_TX : VFL_DIR_RX;
1240		vdev->lock = &s->lock;
1241		if (s->sd)
1242			vdev->ctrl_handler = s->sd->ctrl_handler;
1243		s->timings = dv1080p60;
1244		v4l2_subdev_call(s->sd, pad, s_dv_timings, 0, &s->timings);
1245		if (!s->is_output && s->sd)
1246			cobalt_enable_input(s);
1247		vdev->ioctl_ops = s->is_dummy ? &cobalt_ioctl_empty_ops :
1248				  &cobalt_ioctl_ops;
1249	}
1250
1251	INIT_LIST_HEAD(&s->bufs);
1252	q->type = s->is_output ? V4L2_BUF_TYPE_VIDEO_OUTPUT :
1253				 V4L2_BUF_TYPE_VIDEO_CAPTURE;
1254	q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1255	q->io_modes |= s->is_output ? VB2_WRITE : VB2_READ;
1256	q->drv_priv = s;
1257	q->buf_struct_size = sizeof(struct cobalt_buffer);
1258	q->ops = &cobalt_qops;
1259	q->mem_ops = &vb2_dma_sg_memops;
1260	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1261	q->min_queued_buffers = 2;
1262	q->lock = &s->lock;
1263	q->dev = &cobalt->pci_dev->dev;
1264	vdev->queue = q;
1265	vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
1266	if (s->is_output)
1267		vdev->device_caps |= V4L2_CAP_VIDEO_OUTPUT;
1268	else
1269		vdev->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
1270
1271	video_set_drvdata(vdev, s);
1272	ret = vb2_queue_init(q);
1273	if (!s->is_audio && ret == 0)
1274		ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
1275	else if (!s->is_dummy)
1276		ret = cobalt_alsa_init(s);
1277
1278	if (ret < 0) {
1279		if (!s->is_audio)
1280			cobalt_err("couldn't register v4l2 device node %d\n",
1281					node);
1282		return ret;
1283	}
1284	cobalt_info("registered node %d\n", node);
1285	return 0;
1286}
1287
1288/* Initialize v4l2 variables and register v4l2 devices */
1289int cobalt_nodes_register(struct cobalt *cobalt)
1290{
1291	int node, ret;
1292
1293	/* Setup V4L2 Devices */
1294	for (node = 0; node < COBALT_NUM_STREAMS; node++) {
1295		ret = cobalt_node_register(cobalt, node);
1296		if (ret)
1297			return ret;
1298	}
1299	return 0;
1300}
1301
1302/* Unregister v4l2 devices */
1303void cobalt_nodes_unregister(struct cobalt *cobalt)
1304{
1305	int node;
1306
1307	/* Teardown all streams */
1308	for (node = 0; node < COBALT_NUM_STREAMS; node++) {
1309		struct cobalt_stream *s = cobalt->streams + node;
1310		struct video_device *vdev = &s->vdev;
1311
1312		if (!s->is_audio)
1313			video_unregister_device(vdev);
1314		else if (!s->is_dummy)
1315			cobalt_alsa_exit(s);
1316	}
1317}
~/ Read-only file preview.