brintos

brintos / linux-shallow public Read only

0
0
Text · 36.2 KiB · d4d7b26 Raw
1320 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  cobalt V4L2 API4 *5 *  Derived from ivtv-ioctl.c and cx18-fileops.c6 *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 is316	 * 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	.wait_prepare = vb2_ops_wait_prepare,428	.wait_finish = vb2_ops_wait_finish,429};430 431/* V4L2 ioctls */432 433#ifdef CONFIG_VIDEO_ADV_DEBUG434static int cobalt_cobaltc(struct cobalt *cobalt, unsigned int cmd, void *arg)435{436	struct v4l2_dbg_register *regs = arg;437	void __iomem *adrs = cobalt->bar1 + regs->reg;438 439	cobalt_info("cobalt_cobaltc: adrs = %p\n", adrs);440 441	if (!capable(CAP_SYS_ADMIN))442		return -EPERM;443 444	regs->size = 4;445	if (cmd == VIDIOC_DBG_S_REGISTER)446		iowrite32(regs->val, adrs);447	else448		regs->val = ioread32(adrs);449	return 0;450}451 452static int cobalt_g_register(struct file *file, void *priv_fh,453		struct v4l2_dbg_register *reg)454{455	struct cobalt_stream *s = video_drvdata(file);456	struct cobalt *cobalt = s->cobalt;457 458	return cobalt_cobaltc(cobalt, VIDIOC_DBG_G_REGISTER, reg);459}460 461static int cobalt_s_register(struct file *file, void *priv_fh,462		const struct v4l2_dbg_register *reg)463{464	struct cobalt_stream *s = video_drvdata(file);465	struct cobalt *cobalt = s->cobalt;466 467	return cobalt_cobaltc(cobalt, VIDIOC_DBG_S_REGISTER,468			(struct v4l2_dbg_register *)reg);469}470#endif471 472static int cobalt_querycap(struct file *file, void *priv_fh,473				struct v4l2_capability *vcap)474{475	struct cobalt_stream *s = video_drvdata(file);476	struct cobalt *cobalt = s->cobalt;477 478	strscpy(vcap->driver, "cobalt", sizeof(vcap->driver));479	strscpy(vcap->card, "cobalt", sizeof(vcap->card));480	snprintf(vcap->bus_info, sizeof(vcap->bus_info),481		 "PCIe:%s", pci_name(cobalt->pci_dev));482	vcap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE |483		V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS;484	if (cobalt->have_hsma_tx)485		vcap->capabilities |= V4L2_CAP_VIDEO_OUTPUT;486	return 0;487}488 489static void cobalt_video_input_status_show(struct cobalt_stream *s)490{491	struct m00389_cvi_regmap __iomem *cvi;492	struct m00233_video_measure_regmap __iomem *vmr;493	struct m00473_freewheel_regmap __iomem *fw;494	struct m00479_clk_loss_detector_regmap __iomem *clkloss;495	struct m00235_fdma_packer_regmap __iomem *packer;496	int rx = s->video_channel;497	struct cobalt *cobalt = s->cobalt;498	u32 cvi_ctrl, cvi_stat;499	u32 vmr_ctrl, vmr_stat;500 501	cvi = COBALT_CVI(cobalt, rx);502	vmr = COBALT_CVI_VMR(cobalt, rx);503	fw = COBALT_CVI_FREEWHEEL(cobalt, rx);504	clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx);505	packer = COBALT_CVI_PACKER(cobalt, rx);506	cvi_ctrl = ioread32(&cvi->control);507	cvi_stat = ioread32(&cvi->status);508	vmr_ctrl = ioread32(&vmr->control);509	vmr_stat = ioread32(&vmr->status);510	cobalt_info("rx%d: cvi resolution: %dx%d\n", rx,511		    ioread32(&cvi->frame_width), ioread32(&cvi->frame_height));512	cobalt_info("rx%d: cvi control: %s%s%s\n", rx,513		(cvi_ctrl & M00389_CONTROL_BITMAP_ENABLE_MSK) ?514			"enable " : "disable ",515		(cvi_ctrl & M00389_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK) ?516			"HSync- " : "HSync+ ",517		(cvi_ctrl & M00389_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK) ?518			"VSync- " : "VSync+ ");519	cobalt_info("rx%d: cvi status: %s%s\n", rx,520		(cvi_stat & M00389_STATUS_BITMAP_LOCK_MSK) ?521			"lock " : "no-lock ",522		(cvi_stat & M00389_STATUS_BITMAP_ERROR_MSK) ?523			"error " : "no-error ");524 525	cobalt_info("rx%d: Measurements: %s%s%s%s%s%s%s\n", rx,526		(vmr_ctrl & M00233_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK) ?527			"HSync- " : "HSync+ ",528		(vmr_ctrl & M00233_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK) ?529			"VSync- " : "VSync+ ",530		(vmr_ctrl & M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK) ?531			"enabled " : "disabled ",532		(vmr_ctrl & M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK) ?533			"irq-enabled " : "irq-disabled ",534		(vmr_ctrl & M00233_CONTROL_BITMAP_UPDATE_ON_HSYNC_MSK) ?535			"update-on-hsync " : "",536		(vmr_stat & M00233_STATUS_BITMAP_HSYNC_TIMEOUT_MSK) ?537			"hsync-timeout " : "",538		(vmr_stat & M00233_STATUS_BITMAP_INIT_DONE_MSK) ?539			"init-done" : "");540	cobalt_info("rx%d: irq_status: 0x%02x irq_triggers: 0x%02x\n", rx,541			ioread32(&vmr->irq_status) & 0xff,542			ioread32(&vmr->irq_triggers) & 0xff);543	cobalt_info("rx%d: vsync: %d\n", rx, ioread32(&vmr->vsync_time));544	cobalt_info("rx%d: vbp: %d\n", rx, ioread32(&vmr->vback_porch));545	cobalt_info("rx%d: vact: %d\n", rx, ioread32(&vmr->vactive_area));546	cobalt_info("rx%d: vfb: %d\n", rx, ioread32(&vmr->vfront_porch));547	cobalt_info("rx%d: hsync: %d\n", rx, ioread32(&vmr->hsync_time));548	cobalt_info("rx%d: hbp: %d\n", rx, ioread32(&vmr->hback_porch));549	cobalt_info("rx%d: hact: %d\n", rx, ioread32(&vmr->hactive_area));550	cobalt_info("rx%d: hfb: %d\n", rx, ioread32(&vmr->hfront_porch));551	cobalt_info("rx%d: Freewheeling: %s%s%s\n", rx,552		(ioread32(&fw->ctrl) & M00473_CTRL_BITMAP_ENABLE_MSK) ?553			"enabled " : "disabled ",554		(ioread32(&fw->ctrl) & M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK) ?555			"forced " : "",556		(ioread32(&fw->status) & M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK) ?557			"freewheeling " : "video-passthrough ");558	iowrite32(0xff, &vmr->irq_status);559	cobalt_info("rx%d: Clock Loss Detection: %s%s\n", rx,560		(ioread32(&clkloss->ctrl) & M00479_CTRL_BITMAP_ENABLE_MSK) ?561			"enabled " : "disabled ",562		(ioread32(&clkloss->status) & M00479_STATUS_BITMAP_CLOCK_MISSING_MSK) ?563			"clock-missing " : "found-clock ");564	cobalt_info("rx%d: Packer: %x\n", rx, ioread32(&packer->control));565}566 567static int cobalt_log_status(struct file *file, void *priv_fh)568{569	struct cobalt_stream *s = video_drvdata(file);570	struct cobalt *cobalt = s->cobalt;571	struct m00514_syncgen_flow_evcnt_regmap __iomem *vo =572		COBALT_TX_BASE(cobalt);573	u8 stat;574 575	cobalt_info("%s", cobalt->hdl_info);576	cobalt_info("sysctrl: %08x, sysstat: %08x\n",577			cobalt_g_sysctrl(cobalt),578			cobalt_g_sysstat(cobalt));579	cobalt_info("dma channel: %d, video channel: %d\n",580			s->dma_channel, s->video_channel);581	cobalt_pcie_status_show(cobalt);582	cobalt_cpld_status(cobalt);583	cobalt_irq_log_status(cobalt);584	v4l2_subdev_call(s->sd, core, log_status);585	if (!s->is_output) {586		cobalt_video_input_status_show(s);587		return 0;588	}589 590	stat = ioread32(&vo->rd_status);591 592	cobalt_info("tx: status: %s%s\n",593		(stat & M00514_RD_STATUS_BITMAP_FLOW_CTRL_NO_DATA_ERROR_MSK) ?594			"no_data " : "",595		(stat & M00514_RD_STATUS_BITMAP_READY_BUFFER_FULL_MSK) ?596			"ready_buffer_full " : "");597	cobalt_info("tx: evcnt: %d\n", ioread32(&vo->rd_evcnt_count));598	return 0;599}600 601static int cobalt_enum_dv_timings(struct file *file, void *priv_fh,602				    struct v4l2_enum_dv_timings *timings)603{604	struct cobalt_stream *s = video_drvdata(file);605 606	if (s->input == 1) {607		if (timings->index)608			return -EINVAL;609		memset(timings->reserved, 0, sizeof(timings->reserved));610		timings->timings = cea1080p60;611		return 0;612	}613	timings->pad = 0;614	return v4l2_subdev_call(s->sd,615			pad, enum_dv_timings, timings);616}617 618static int cobalt_s_dv_timings(struct file *file, void *priv_fh,619				    struct v4l2_dv_timings *timings)620{621	struct cobalt_stream *s = video_drvdata(file);622	int err;623 624	if (s->input == 1) {625		*timings = cea1080p60;626		return 0;627	}628 629	if (v4l2_match_dv_timings(timings, &s->timings, 0, true))630		return 0;631 632	if (vb2_is_busy(&s->q))633		return -EBUSY;634 635	err = v4l2_subdev_call(s->sd,636			pad, s_dv_timings, 0, timings);637	if (!err) {638		s->timings = *timings;639		s->width = timings->bt.width;640		s->height = timings->bt.height;641		s->stride = timings->bt.width * s->bpp;642	}643	return err;644}645 646static int cobalt_g_dv_timings(struct file *file, void *priv_fh,647				    struct v4l2_dv_timings *timings)648{649	struct cobalt_stream *s = video_drvdata(file);650 651	if (s->input == 1) {652		*timings = cea1080p60;653		return 0;654	}655	return v4l2_subdev_call(s->sd,656			pad, g_dv_timings, 0, timings);657}658 659static int cobalt_query_dv_timings(struct file *file, void *priv_fh,660				    struct v4l2_dv_timings *timings)661{662	struct cobalt_stream *s = video_drvdata(file);663 664	if (s->input == 1) {665		*timings = cea1080p60;666		return 0;667	}668	return v4l2_subdev_call(s->sd,669			pad, query_dv_timings, 0, timings);670}671 672static int cobalt_dv_timings_cap(struct file *file, void *priv_fh,673				    struct v4l2_dv_timings_cap *cap)674{675	struct cobalt_stream *s = video_drvdata(file);676 677	cap->pad = 0;678	return v4l2_subdev_call(s->sd,679			pad, dv_timings_cap, cap);680}681 682static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv_fh,683		struct v4l2_fmtdesc *f)684{685	switch (f->index) {686	case 0:687		f->pixelformat = V4L2_PIX_FMT_YUYV;688		break;689	case 1:690		f->pixelformat = V4L2_PIX_FMT_RGB24;691		break;692	case 2:693		f->pixelformat = V4L2_PIX_FMT_BGR32;694		break;695	default:696		return -EINVAL;697	}698 699	return 0;700}701 702static int cobalt_g_fmt_vid_cap(struct file *file, void *priv_fh,703		struct v4l2_format *f)704{705	struct cobalt_stream *s = video_drvdata(file);706	struct v4l2_pix_format *pix = &f->fmt.pix;707 708	pix->width = s->width;709	pix->height = s->height;710	pix->bytesperline = s->stride;711	pix->field = V4L2_FIELD_NONE;712 713	if (s->input == 1) {714		pix->colorspace = V4L2_COLORSPACE_SRGB;715	} else {716		struct v4l2_subdev_format sd_fmt = {717			.pad = s->pad_source,718			.which = V4L2_SUBDEV_FORMAT_ACTIVE,719		};720 721		v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt);722		v4l2_fill_pix_format(pix, &sd_fmt.format);723	}724 725	pix->pixelformat = s->pixfmt;726	pix->sizeimage = pix->bytesperline * pix->height;727 728	return 0;729}730 731static int cobalt_try_fmt_vid_cap(struct file *file, void *priv_fh,732		struct v4l2_format *f)733{734	struct cobalt_stream *s = video_drvdata(file);735	struct v4l2_pix_format *pix = &f->fmt.pix;736 737	/* Check for min (QCIF) and max (Full HD) size */738	if ((pix->width < 176) || (pix->height < 144)) {739		pix->width = 176;740		pix->height = 144;741	}742 743	if ((pix->width > 1920) || (pix->height > 1080)) {744		pix->width = 1920;745		pix->height = 1080;746	}747 748	/* Make width multiple of 4 */749	pix->width &= ~0x3;750 751	/* Make height multiple of 2 */752	pix->height &= ~0x1;753 754	if (s->input == 1) {755		/* Generator => fixed format only */756		pix->width = 1920;757		pix->height = 1080;758		pix->colorspace = V4L2_COLORSPACE_SRGB;759	} else {760		struct v4l2_subdev_format sd_fmt = {761			.pad = s->pad_source,762			.which = V4L2_SUBDEV_FORMAT_ACTIVE,763		};764 765		v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt);766		v4l2_fill_pix_format(pix, &sd_fmt.format);767	}768 769	switch (pix->pixelformat) {770	case V4L2_PIX_FMT_YUYV:771	default:772		pix->bytesperline = max(pix->bytesperline & ~0x3,773				pix->width * COBALT_BYTES_PER_PIXEL_YUYV);774		pix->pixelformat = V4L2_PIX_FMT_YUYV;775		break;776	case V4L2_PIX_FMT_RGB24:777		pix->bytesperline = max(pix->bytesperline & ~0x3,778				pix->width * COBALT_BYTES_PER_PIXEL_RGB24);779		break;780	case V4L2_PIX_FMT_BGR32:781		pix->bytesperline = max(pix->bytesperline & ~0x3,782				pix->width * COBALT_BYTES_PER_PIXEL_RGB32);783		break;784	}785 786	pix->sizeimage = pix->bytesperline * pix->height;787	pix->field = V4L2_FIELD_NONE;788 789	return 0;790}791 792static int cobalt_s_fmt_vid_cap(struct file *file, void *priv_fh,793		struct v4l2_format *f)794{795	struct cobalt_stream *s = video_drvdata(file);796	struct v4l2_pix_format *pix = &f->fmt.pix;797 798	if (vb2_is_busy(&s->q))799		return -EBUSY;800 801	if (cobalt_try_fmt_vid_cap(file, priv_fh, f))802		return -EINVAL;803 804	s->width = pix->width;805	s->height = pix->height;806	s->stride = pix->bytesperline;807	switch (pix->pixelformat) {808	case V4L2_PIX_FMT_YUYV:809		s->bpp = COBALT_BYTES_PER_PIXEL_YUYV;810		break;811	case V4L2_PIX_FMT_RGB24:812		s->bpp = COBALT_BYTES_PER_PIXEL_RGB24;813		break;814	case V4L2_PIX_FMT_BGR32:815		s->bpp = COBALT_BYTES_PER_PIXEL_RGB32;816		break;817	default:818		return -EINVAL;819	}820	s->pixfmt = pix->pixelformat;821	cobalt_enable_input(s);822 823	return 0;824}825 826static int cobalt_try_fmt_vid_out(struct file *file, void *priv_fh,827		struct v4l2_format *f)828{829	struct v4l2_pix_format *pix = &f->fmt.pix;830 831	/* Check for min (QCIF) and max (Full HD) size */832	if ((pix->width < 176) || (pix->height < 144)) {833		pix->width = 176;834		pix->height = 144;835	}836 837	if ((pix->width > 1920) || (pix->height > 1080)) {838		pix->width = 1920;839		pix->height = 1080;840	}841 842	/* Make width multiple of 4 */843	pix->width &= ~0x3;844 845	/* Make height multiple of 2 */846	pix->height &= ~0x1;847 848	switch (pix->pixelformat) {849	case V4L2_PIX_FMT_YUYV:850	default:851		pix->bytesperline = max(pix->bytesperline & ~0x3,852				pix->width * COBALT_BYTES_PER_PIXEL_YUYV);853		pix->pixelformat = V4L2_PIX_FMT_YUYV;854		break;855	case V4L2_PIX_FMT_BGR32:856		pix->bytesperline = max(pix->bytesperline & ~0x3,857				pix->width * COBALT_BYTES_PER_PIXEL_RGB32);858		break;859	}860 861	pix->sizeimage = pix->bytesperline * pix->height;862	pix->field = V4L2_FIELD_NONE;863 864	return 0;865}866 867static int cobalt_g_fmt_vid_out(struct file *file, void *priv_fh,868		struct v4l2_format *f)869{870	struct cobalt_stream *s = video_drvdata(file);871	struct v4l2_pix_format *pix = &f->fmt.pix;872 873	pix->width = s->width;874	pix->height = s->height;875	pix->bytesperline = s->stride;876	pix->field = V4L2_FIELD_NONE;877	pix->pixelformat = s->pixfmt;878	pix->colorspace = s->colorspace;879	pix->xfer_func = s->xfer_func;880	pix->ycbcr_enc = s->ycbcr_enc;881	pix->quantization = s->quantization;882	pix->sizeimage = pix->bytesperline * pix->height;883 884	return 0;885}886 887static int cobalt_enum_fmt_vid_out(struct file *file, void *priv_fh,888		struct v4l2_fmtdesc *f)889{890	switch (f->index) {891	case 0:892		f->pixelformat = V4L2_PIX_FMT_YUYV;893		break;894	case 1:895		f->pixelformat = V4L2_PIX_FMT_BGR32;896		break;897	default:898		return -EINVAL;899	}900 901	return 0;902}903 904static int cobalt_s_fmt_vid_out(struct file *file, void *priv_fh,905		struct v4l2_format *f)906{907	struct cobalt_stream *s = video_drvdata(file);908	struct v4l2_pix_format *pix = &f->fmt.pix;909	struct v4l2_subdev_format sd_fmt = {910		.which = V4L2_SUBDEV_FORMAT_ACTIVE,911	};912	u32 code;913 914	if (cobalt_try_fmt_vid_out(file, priv_fh, f))915		return -EINVAL;916 917	if (vb2_is_busy(&s->q) && (pix->pixelformat != s->pixfmt ||918	    pix->width != s->width || pix->height != s->height ||919	    pix->bytesperline != s->stride))920		return -EBUSY;921 922	switch (pix->pixelformat) {923	case V4L2_PIX_FMT_YUYV:924		s->bpp = COBALT_BYTES_PER_PIXEL_YUYV;925		code = MEDIA_BUS_FMT_UYVY8_1X16;926		break;927	case V4L2_PIX_FMT_BGR32:928		s->bpp = COBALT_BYTES_PER_PIXEL_RGB32;929		code = MEDIA_BUS_FMT_RGB888_1X24;930		break;931	default:932		return -EINVAL;933	}934	s->width = pix->width;935	s->height = pix->height;936	s->stride = pix->bytesperline;937	s->pixfmt = pix->pixelformat;938	s->colorspace = pix->colorspace;939	s->xfer_func = pix->xfer_func;940	s->ycbcr_enc = pix->ycbcr_enc;941	s->quantization = pix->quantization;942	v4l2_fill_mbus_format(&sd_fmt.format, pix, code);943	v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt);944	return 0;945}946 947static int cobalt_enum_input(struct file *file, void *priv_fh,948				 struct v4l2_input *inp)949{950	struct cobalt_stream *s = video_drvdata(file);951 952	if (inp->index > 1)953		return -EINVAL;954	if (inp->index == 0)955		snprintf(inp->name, sizeof(inp->name),956				"HDMI-%d", s->video_channel);957	else958		snprintf(inp->name, sizeof(inp->name),959				"Generator-%d", s->video_channel);960	inp->type = V4L2_INPUT_TYPE_CAMERA;961	inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;962	if (inp->index == 1)963		return 0;964	return v4l2_subdev_call(s->sd,965			video, g_input_status, &inp->status);966}967 968static int cobalt_g_input(struct file *file, void *priv_fh, unsigned int *i)969{970	struct cobalt_stream *s = video_drvdata(file);971 972	*i = s->input;973	return 0;974}975 976static int cobalt_s_input(struct file *file, void *priv_fh, unsigned int i)977{978	struct cobalt_stream *s = video_drvdata(file);979 980	if (i >= 2)981		return -EINVAL;982	if (vb2_is_busy(&s->q))983		return -EBUSY;984	s->input = i;985 986	cobalt_enable_input(s);987 988	if (s->input == 1) /* Test Pattern Generator */989		return 0;990 991	return v4l2_subdev_call(s->sd, video, s_routing,992			ADV76XX_PAD_HDMI_PORT_A, 0, 0);993}994 995static int cobalt_enum_output(struct file *file, void *priv_fh,996				 struct v4l2_output *out)997{998	if (out->index)999		return -EINVAL;1000	snprintf(out->name, sizeof(out->name), "HDMI-%d", out->index);1001	out->type = V4L2_OUTPUT_TYPE_ANALOG;1002	out->capabilities = V4L2_OUT_CAP_DV_TIMINGS;1003	return 0;1004}1005 1006static int cobalt_g_output(struct file *file, void *priv_fh, unsigned int *i)1007{1008	*i = 0;1009	return 0;1010}1011 1012static int cobalt_s_output(struct file *file, void *priv_fh, unsigned int i)1013{1014	return i ? -EINVAL : 0;1015}1016 1017static int cobalt_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)1018{1019	struct cobalt_stream *s = video_drvdata(file);1020	u32 pad = edid->pad;1021	int ret;1022 1023	if (edid->pad >= (s->is_output ? 1 : 2))1024		return -EINVAL;1025	edid->pad = 0;1026	ret = v4l2_subdev_call(s->sd, pad, get_edid, edid);1027	edid->pad = pad;1028	return ret;1029}1030 1031static int cobalt_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)1032{1033	struct cobalt_stream *s = video_drvdata(file);1034	u32 pad = edid->pad;1035	int ret;1036 1037	if (edid->pad >= 2)1038		return -EINVAL;1039	edid->pad = 0;1040	ret = v4l2_subdev_call(s->sd, pad, set_edid, edid);1041	edid->pad = pad;1042	return ret;1043}1044 1045static int cobalt_subscribe_event(struct v4l2_fh *fh,1046				  const struct v4l2_event_subscription *sub)1047{1048	switch (sub->type) {1049	case V4L2_EVENT_SOURCE_CHANGE:1050		return v4l2_event_subscribe(fh, sub, 4, NULL);1051	}1052	return v4l2_ctrl_subscribe_event(fh, sub);1053}1054 1055static int cobalt_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)1056{1057	struct cobalt_stream *s = video_drvdata(file);1058	struct v4l2_fract fps;1059 1060	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)1061		return -EINVAL;1062 1063	fps = v4l2_calc_timeperframe(&s->timings);1064	a->parm.capture.timeperframe.numerator = fps.numerator;1065	a->parm.capture.timeperframe.denominator = fps.denominator;1066	a->parm.capture.readbuffers = 3;1067	return 0;1068}1069 1070static int cobalt_g_pixelaspect(struct file *file, void *fh,1071				int type, struct v4l2_fract *f)1072{1073	struct cobalt_stream *s = video_drvdata(file);1074	struct v4l2_dv_timings timings;1075	int err = 0;1076 1077	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)1078		return -EINVAL;1079 1080	if (s->input == 1)1081		timings = cea1080p60;1082	else1083		err = v4l2_subdev_call(s->sd, pad, g_dv_timings, 0, &timings);1084	if (!err)1085		*f = v4l2_dv_timings_aspect_ratio(&timings);1086	return err;1087}1088 1089static int cobalt_g_selection(struct file *file, void *fh,1090			      struct v4l2_selection *sel)1091{1092	struct cobalt_stream *s = video_drvdata(file);1093	struct v4l2_dv_timings timings;1094	int err = 0;1095 1096	if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)1097		return -EINVAL;1098 1099	if (s->input == 1)1100		timings = cea1080p60;1101	else1102		err = v4l2_subdev_call(s->sd, pad, g_dv_timings, 0, &timings);1103 1104	if (err)1105		return err;1106 1107	switch (sel->target) {1108	case V4L2_SEL_TGT_CROP_BOUNDS:1109	case V4L2_SEL_TGT_CROP_DEFAULT:1110		sel->r.top = 0;1111		sel->r.left = 0;1112		sel->r.width = timings.bt.width;1113		sel->r.height = timings.bt.height;1114		break;1115	default:1116		return -EINVAL;1117	}1118	return 0;1119}1120 1121static const struct v4l2_ioctl_ops cobalt_ioctl_ops = {1122	.vidioc_querycap		= cobalt_querycap,1123	.vidioc_g_parm			= cobalt_g_parm,1124	.vidioc_log_status		= cobalt_log_status,1125	.vidioc_streamon		= vb2_ioctl_streamon,1126	.vidioc_streamoff		= vb2_ioctl_streamoff,1127	.vidioc_g_pixelaspect		= cobalt_g_pixelaspect,1128	.vidioc_g_selection		= cobalt_g_selection,1129	.vidioc_enum_input		= cobalt_enum_input,1130	.vidioc_g_input			= cobalt_g_input,1131	.vidioc_s_input			= cobalt_s_input,1132	.vidioc_enum_fmt_vid_cap	= cobalt_enum_fmt_vid_cap,1133	.vidioc_g_fmt_vid_cap		= cobalt_g_fmt_vid_cap,1134	.vidioc_s_fmt_vid_cap		= cobalt_s_fmt_vid_cap,1135	.vidioc_try_fmt_vid_cap		= cobalt_try_fmt_vid_cap,1136	.vidioc_enum_output		= cobalt_enum_output,1137	.vidioc_g_output		= cobalt_g_output,1138	.vidioc_s_output		= cobalt_s_output,1139	.vidioc_enum_fmt_vid_out	= cobalt_enum_fmt_vid_out,1140	.vidioc_g_fmt_vid_out		= cobalt_g_fmt_vid_out,1141	.vidioc_s_fmt_vid_out		= cobalt_s_fmt_vid_out,1142	.vidioc_try_fmt_vid_out		= cobalt_try_fmt_vid_out,1143	.vidioc_s_dv_timings		= cobalt_s_dv_timings,1144	.vidioc_g_dv_timings		= cobalt_g_dv_timings,1145	.vidioc_query_dv_timings	= cobalt_query_dv_timings,1146	.vidioc_enum_dv_timings		= cobalt_enum_dv_timings,1147	.vidioc_dv_timings_cap		= cobalt_dv_timings_cap,1148	.vidioc_g_edid			= cobalt_g_edid,1149	.vidioc_s_edid			= cobalt_s_edid,1150	.vidioc_subscribe_event		= cobalt_subscribe_event,1151	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,1152	.vidioc_reqbufs			= vb2_ioctl_reqbufs,1153	.vidioc_create_bufs		= vb2_ioctl_create_bufs,1154	.vidioc_querybuf		= vb2_ioctl_querybuf,1155	.vidioc_qbuf			= vb2_ioctl_qbuf,1156	.vidioc_dqbuf			= vb2_ioctl_dqbuf,1157	.vidioc_expbuf			= vb2_ioctl_expbuf,1158#ifdef CONFIG_VIDEO_ADV_DEBUG1159	.vidioc_g_register              = cobalt_g_register,1160	.vidioc_s_register              = cobalt_s_register,1161#endif1162};1163 1164static const struct v4l2_ioctl_ops cobalt_ioctl_empty_ops = {1165#ifdef CONFIG_VIDEO_ADV_DEBUG1166	.vidioc_g_register              = cobalt_g_register,1167	.vidioc_s_register              = cobalt_s_register,1168#endif1169};1170 1171/* Register device nodes */1172 1173static const struct v4l2_file_operations cobalt_fops = {1174	.owner = THIS_MODULE,1175	.open = v4l2_fh_open,1176	.unlocked_ioctl = video_ioctl2,1177	.release = vb2_fop_release,1178	.poll = vb2_fop_poll,1179	.mmap = vb2_fop_mmap,1180	.read = vb2_fop_read,1181};1182 1183static const struct v4l2_file_operations cobalt_out_fops = {1184	.owner = THIS_MODULE,1185	.open = v4l2_fh_open,1186	.unlocked_ioctl = video_ioctl2,1187	.release = vb2_fop_release,1188	.poll = vb2_fop_poll,1189	.mmap = vb2_fop_mmap,1190	.write = vb2_fop_write,1191};1192 1193static const struct v4l2_file_operations cobalt_empty_fops = {1194	.owner = THIS_MODULE,1195	.open = v4l2_fh_open,1196	.unlocked_ioctl = video_ioctl2,1197	.release = v4l2_fh_release,1198};1199 1200static int cobalt_node_register(struct cobalt *cobalt, int node)1201{1202	static const struct v4l2_dv_timings dv1080p60 =1203		V4L2_DV_BT_CEA_1920X1080P60;1204	struct cobalt_stream *s = cobalt->streams + node;1205	struct video_device *vdev = &s->vdev;1206	struct vb2_queue *q = &s->q;1207	int ret;1208 1209	mutex_init(&s->lock);1210	spin_lock_init(&s->irqlock);1211 1212	snprintf(vdev->name, sizeof(vdev->name),1213			"%s-%d", cobalt->v4l2_dev.name, node);1214	s->width = 1920;1215	/* Audio frames are just 4 lines of 1920 bytes */1216	s->height = s->is_audio ? 4 : 1080;1217 1218	if (s->is_audio) {1219		s->bpp = 1;1220		s->pixfmt = V4L2_PIX_FMT_GREY;1221	} else if (s->is_output) {1222		s->bpp = COBALT_BYTES_PER_PIXEL_RGB32;1223		s->pixfmt = V4L2_PIX_FMT_BGR32;1224	} else {1225		s->bpp = COBALT_BYTES_PER_PIXEL_YUYV;1226		s->pixfmt = V4L2_PIX_FMT_YUYV;1227	}1228	s->colorspace = V4L2_COLORSPACE_SRGB;1229	s->stride = s->width * s->bpp;1230 1231	if (!s->is_audio) {1232		if (s->is_dummy)1233			cobalt_warn("Setting up dummy video node %d\n", node);1234		vdev->v4l2_dev = &cobalt->v4l2_dev;1235		if (s->is_dummy)1236			vdev->fops = &cobalt_empty_fops;1237		else1238			vdev->fops = s->is_output ? &cobalt_out_fops :1239						    &cobalt_fops;1240		vdev->release = video_device_release_empty;1241		vdev->vfl_dir = s->is_output ? VFL_DIR_TX : VFL_DIR_RX;1242		vdev->lock = &s->lock;1243		if (s->sd)1244			vdev->ctrl_handler = s->sd->ctrl_handler;1245		s->timings = dv1080p60;1246		v4l2_subdev_call(s->sd, pad, s_dv_timings, 0, &s->timings);1247		if (!s->is_output && s->sd)1248			cobalt_enable_input(s);1249		vdev->ioctl_ops = s->is_dummy ? &cobalt_ioctl_empty_ops :1250				  &cobalt_ioctl_ops;1251	}1252 1253	INIT_LIST_HEAD(&s->bufs);1254	q->type = s->is_output ? V4L2_BUF_TYPE_VIDEO_OUTPUT :1255				 V4L2_BUF_TYPE_VIDEO_CAPTURE;1256	q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;1257	q->io_modes |= s->is_output ? VB2_WRITE : VB2_READ;1258	q->drv_priv = s;1259	q->buf_struct_size = sizeof(struct cobalt_buffer);1260	q->ops = &cobalt_qops;1261	q->mem_ops = &vb2_dma_sg_memops;1262	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;1263	q->min_queued_buffers = 2;1264	q->lock = &s->lock;1265	q->dev = &cobalt->pci_dev->dev;1266	vdev->queue = q;1267	vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;1268	if (s->is_output)1269		vdev->device_caps |= V4L2_CAP_VIDEO_OUTPUT;1270	else1271		vdev->device_caps |= V4L2_CAP_VIDEO_CAPTURE;1272 1273	video_set_drvdata(vdev, s);1274	ret = vb2_queue_init(q);1275	if (!s->is_audio && ret == 0)1276		ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);1277	else if (!s->is_dummy)1278		ret = cobalt_alsa_init(s);1279 1280	if (ret < 0) {1281		if (!s->is_audio)1282			cobalt_err("couldn't register v4l2 device node %d\n",1283					node);1284		return ret;1285	}1286	cobalt_info("registered node %d\n", node);1287	return 0;1288}1289 1290/* Initialize v4l2 variables and register v4l2 devices */1291int cobalt_nodes_register(struct cobalt *cobalt)1292{1293	int node, ret;1294 1295	/* Setup V4L2 Devices */1296	for (node = 0; node < COBALT_NUM_STREAMS; node++) {1297		ret = cobalt_node_register(cobalt, node);1298		if (ret)1299			return ret;1300	}1301	return 0;1302}1303 1304/* Unregister v4l2 devices */1305void cobalt_nodes_unregister(struct cobalt *cobalt)1306{1307	int node;1308 1309	/* Teardown all streams */1310	for (node = 0; node < COBALT_NUM_STREAMS; node++) {1311		struct cobalt_stream *s = cobalt->streams + node;1312		struct video_device *vdev = &s->vdev;1313 1314		if (!s->is_audio)1315			video_unregister_device(vdev);1316		else if (!s->is_dummy)1317			cobalt_alsa_exit(s);1318	}1319}1320