Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  cobalt V4L2 API
0004  *
0005  *  Derived from ivtv-ioctl.c and cx18-fileops.c
0006  *
0007  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
0008  *  All rights reserved.
0009  */
0010 
0011 #include <linux/dma-mapping.h>
0012 #include <linux/delay.h>
0013 #include <linux/math64.h>
0014 #include <linux/pci.h>
0015 #include <linux/v4l2-dv-timings.h>
0016 
0017 #include <media/v4l2-ctrls.h>
0018 #include <media/v4l2-event.h>
0019 #include <media/v4l2-dv-timings.h>
0020 #include <media/i2c/adv7604.h>
0021 #include <media/i2c/adv7842.h>
0022 
0023 #include "cobalt-alsa.h"
0024 #include "cobalt-cpld.h"
0025 #include "cobalt-driver.h"
0026 #include "cobalt-v4l2.h"
0027 #include "cobalt-irq.h"
0028 #include "cobalt-omnitek.h"
0029 
0030 static const struct v4l2_dv_timings cea1080p60 = V4L2_DV_BT_CEA_1920X1080P60;
0031 
0032 /* vb2 DMA streaming ops */
0033 
0034 static int cobalt_queue_setup(struct vb2_queue *q,
0035             unsigned int *num_buffers, unsigned int *num_planes,
0036             unsigned int sizes[], struct device *alloc_devs[])
0037 {
0038     struct cobalt_stream *s = q->drv_priv;
0039     unsigned size = s->stride * s->height;
0040 
0041     if (*num_buffers < 3)
0042         *num_buffers = 3;
0043     if (*num_buffers > NR_BUFS)
0044         *num_buffers = NR_BUFS;
0045     if (*num_planes)
0046         return sizes[0] < size ? -EINVAL : 0;
0047     *num_planes = 1;
0048     sizes[0] = size;
0049     return 0;
0050 }
0051 
0052 static int cobalt_buf_init(struct vb2_buffer *vb)
0053 {
0054     struct cobalt_stream *s = vb->vb2_queue->drv_priv;
0055     struct cobalt *cobalt = s->cobalt;
0056     const size_t max_pages_per_line =
0057         (COBALT_MAX_WIDTH * COBALT_MAX_BPP) / PAGE_SIZE + 2;
0058     const size_t bytes =
0059         COBALT_MAX_HEIGHT * max_pages_per_line * 0x20;
0060     const size_t audio_bytes = ((1920 * 4) / PAGE_SIZE + 1) * 0x20;
0061     struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->index];
0062     struct sg_table *sg_desc = vb2_dma_sg_plane_desc(vb, 0);
0063     unsigned size;
0064     int ret;
0065 
0066     size = s->stride * s->height;
0067     if (vb2_plane_size(vb, 0) < size) {
0068         cobalt_info("data will not fit into plane (%lu < %u)\n",
0069                     vb2_plane_size(vb, 0), size);
0070         return -EINVAL;
0071     }
0072 
0073     if (desc->virt == NULL) {
0074         desc->dev = &cobalt->pci_dev->dev;
0075         descriptor_list_allocate(desc,
0076             s->is_audio ? audio_bytes : bytes);
0077         if (desc->virt == NULL)
0078             return -ENOMEM;
0079     }
0080     ret = descriptor_list_create(cobalt, sg_desc->sgl,
0081             !s->is_output, sg_desc->nents, size,
0082             s->width * s->bpp, s->stride, desc);
0083     if (ret)
0084         descriptor_list_free(desc);
0085     return ret;
0086 }
0087 
0088 static void cobalt_buf_cleanup(struct vb2_buffer *vb)
0089 {
0090     struct cobalt_stream *s = vb->vb2_queue->drv_priv;
0091     struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->index];
0092 
0093     descriptor_list_free(desc);
0094 }
0095 
0096 static int cobalt_buf_prepare(struct vb2_buffer *vb)
0097 {
0098     struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
0099     struct cobalt_stream *s = vb->vb2_queue->drv_priv;
0100 
0101     vb2_set_plane_payload(vb, 0, s->stride * s->height);
0102     vbuf->field = V4L2_FIELD_NONE;
0103     return 0;
0104 }
0105 
0106 static void chain_all_buffers(struct cobalt_stream *s)
0107 {
0108     struct sg_dma_desc_info *desc[NR_BUFS];
0109     struct cobalt_buffer *cb;
0110     struct list_head *p;
0111     int i = 0;
0112 
0113     list_for_each(p, &s->bufs) {
0114         cb = list_entry(p, struct cobalt_buffer, list);
0115         desc[i] = &s->dma_desc_info[cb->vb.vb2_buf.index];
0116         if (i > 0)
0117             descriptor_list_chain(desc[i-1], desc[i]);
0118         i++;
0119     }
0120 }
0121 
0122 static void cobalt_buf_queue(struct vb2_buffer *vb)
0123 {
0124     struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
0125     struct vb2_queue *q = vb->vb2_queue;
0126     struct cobalt_stream *s = q->drv_priv;
0127     struct cobalt_buffer *cb = to_cobalt_buffer(vbuf);
0128     struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->index];
0129     unsigned long flags;
0130 
0131     /* Prepare new buffer */
0132     descriptor_list_loopback(desc);
0133     descriptor_list_interrupt_disable(desc);
0134 
0135     spin_lock_irqsave(&s->irqlock, flags);
0136     list_add_tail(&cb->list, &s->bufs);
0137     chain_all_buffers(s);
0138     spin_unlock_irqrestore(&s->irqlock, flags);
0139 }
0140 
0141 static void cobalt_enable_output(struct cobalt_stream *s)
0142 {
0143     struct cobalt *cobalt = s->cobalt;
0144     struct v4l2_bt_timings *bt = &s->timings.bt;
0145     struct m00514_syncgen_flow_evcnt_regmap __iomem *vo =
0146         COBALT_TX_BASE(cobalt);
0147     unsigned fmt = s->pixfmt != V4L2_PIX_FMT_BGR32 ?
0148             M00514_CONTROL_BITMAP_FORMAT_16_BPP_MSK : 0;
0149     struct v4l2_subdev_format sd_fmt = {
0150         .which = V4L2_SUBDEV_FORMAT_ACTIVE,
0151     };
0152     u64 clk = bt->pixelclock;
0153 
0154     if (bt->flags & V4L2_DV_FL_REDUCED_FPS)
0155         clk = div_u64(clk * 1000ULL, 1001);
0156     if (!cobalt_cpld_set_freq(cobalt, clk)) {
0157         cobalt_err("pixelclock out of range\n");
0158         return;
0159     }
0160 
0161     sd_fmt.format.colorspace = s->colorspace;
0162     sd_fmt.format.xfer_func = s->xfer_func;
0163     sd_fmt.format.ycbcr_enc = s->ycbcr_enc;
0164     sd_fmt.format.quantization = s->quantization;
0165     sd_fmt.format.width = bt->width;
0166     sd_fmt.format.height = bt->height;
0167 
0168     /* Set up FDMA packer */
0169     switch (s->pixfmt) {
0170     case V4L2_PIX_FMT_YUYV:
0171         sd_fmt.format.code = MEDIA_BUS_FMT_UYVY8_1X16;
0172         break;
0173     case V4L2_PIX_FMT_BGR32:
0174         sd_fmt.format.code = MEDIA_BUS_FMT_RGB888_1X24;
0175         break;
0176     }
0177     v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt);
0178 
0179     iowrite32(0, &vo->control);
0180     /* 1080p60 */
0181     iowrite32(bt->hsync, &vo->sync_generator_h_sync_length);
0182     iowrite32(bt->hbackporch, &vo->sync_generator_h_backporch_length);
0183     iowrite32(bt->width, &vo->sync_generator_h_active_length);
0184     iowrite32(bt->hfrontporch, &vo->sync_generator_h_frontporch_length);
0185     iowrite32(bt->vsync, &vo->sync_generator_v_sync_length);
0186     iowrite32(bt->vbackporch, &vo->sync_generator_v_backporch_length);
0187     iowrite32(bt->height, &vo->sync_generator_v_active_length);
0188     iowrite32(bt->vfrontporch, &vo->sync_generator_v_frontporch_length);
0189     iowrite32(0x9900c1, &vo->error_color);
0190 
0191     iowrite32(M00514_CONTROL_BITMAP_SYNC_GENERATOR_LOAD_PARAM_MSK | fmt,
0192           &vo->control);
0193     iowrite32(M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK | fmt, &vo->control);
0194     iowrite32(M00514_CONTROL_BITMAP_SYNC_GENERATOR_ENABLE_MSK |
0195           M00514_CONTROL_BITMAP_FLOW_CTRL_OUTPUT_ENABLE_MSK |
0196           fmt, &vo->control);
0197 }
0198 
0199 static void cobalt_enable_input(struct cobalt_stream *s)
0200 {
0201     struct cobalt *cobalt = s->cobalt;
0202     int ch = (int)s->video_channel;
0203     struct m00235_fdma_packer_regmap __iomem *packer;
0204     struct v4l2_subdev_format sd_fmt_yuyv = {
0205         .pad = s->pad_source,
0206         .which = V4L2_SUBDEV_FORMAT_ACTIVE,
0207         .format.code = MEDIA_BUS_FMT_YUYV8_1X16,
0208     };
0209     struct v4l2_subdev_format sd_fmt_rgb = {
0210         .pad = s->pad_source,
0211         .which = V4L2_SUBDEV_FORMAT_ACTIVE,
0212         .format.code = MEDIA_BUS_FMT_RGB888_1X24,
0213     };
0214 
0215     cobalt_dbg(1, "video_channel %d (%s, %s)\n",
0216            s->video_channel,
0217            s->input == 0 ? "hdmi" : "generator",
0218            "YUYV");
0219 
0220     packer = COBALT_CVI_PACKER(cobalt, ch);
0221 
0222     /* Set up FDMA packer */
0223     switch (s->pixfmt) {
0224     case V4L2_PIX_FMT_YUYV:
0225         iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK |
0226               (1 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST),
0227               &packer->control);
0228         v4l2_subdev_call(s->sd, pad, set_fmt, NULL,
0229                  &sd_fmt_yuyv);
0230         break;
0231     case V4L2_PIX_FMT_RGB24:
0232         iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK |
0233               (2 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST),
0234               &packer->control);
0235         v4l2_subdev_call(s->sd, pad, set_fmt, NULL,
0236                  &sd_fmt_rgb);
0237         break;
0238     case V4L2_PIX_FMT_BGR32:
0239         iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK |
0240               M00235_CONTROL_BITMAP_ENDIAN_FORMAT_MSK |
0241               (3 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST),
0242               &packer->control);
0243         v4l2_subdev_call(s->sd, pad, set_fmt, NULL,
0244                  &sd_fmt_rgb);
0245         break;
0246     }
0247 }
0248 
0249 static void cobalt_dma_start_streaming(struct cobalt_stream *s)
0250 {
0251     struct cobalt *cobalt = s->cobalt;
0252     int rx = s->video_channel;
0253     struct m00460_evcnt_regmap __iomem *evcnt =
0254         COBALT_CVI_EVCNT(cobalt, rx);
0255     struct cobalt_buffer *cb;
0256     unsigned long flags;
0257 
0258     spin_lock_irqsave(&s->irqlock, flags);
0259     if (!s->is_output) {
0260         iowrite32(M00460_CONTROL_BITMAP_CLEAR_MSK, &evcnt->control);
0261         iowrite32(M00460_CONTROL_BITMAP_ENABLE_MSK, &evcnt->control);
0262     } else {
0263         struct m00514_syncgen_flow_evcnt_regmap __iomem *vo =
0264             COBALT_TX_BASE(cobalt);
0265         u32 ctrl = ioread32(&vo->control);
0266 
0267         ctrl &= ~(M00514_CONTROL_BITMAP_EVCNT_ENABLE_MSK |
0268               M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK);
0269         iowrite32(ctrl | M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK,
0270               &vo->control);
0271         iowrite32(ctrl | M00514_CONTROL_BITMAP_EVCNT_ENABLE_MSK,
0272               &vo->control);
0273     }
0274     cb = list_first_entry(&s->bufs, struct cobalt_buffer, list);
0275     omni_sg_dma_start(s, &s->dma_desc_info[cb->vb.vb2_buf.index]);
0276     spin_unlock_irqrestore(&s->irqlock, flags);
0277 }
0278 
0279 static int cobalt_start_streaming(struct vb2_queue *q, unsigned int count)
0280 {
0281     struct cobalt_stream *s = q->drv_priv;
0282     struct cobalt *cobalt = s->cobalt;
0283     struct m00233_video_measure_regmap __iomem *vmr;
0284     struct m00473_freewheel_regmap __iomem *fw;
0285     struct m00479_clk_loss_detector_regmap __iomem *clkloss;
0286     int rx = s->video_channel;
0287     struct m00389_cvi_regmap __iomem *cvi = COBALT_CVI(cobalt, rx);
0288     struct m00460_evcnt_regmap __iomem *evcnt = COBALT_CVI_EVCNT(cobalt, rx);
0289     struct v4l2_bt_timings *bt = &s->timings.bt;
0290     u64 tot_size;
0291     u32 clk_freq;
0292 
0293     if (s->is_audio)
0294         goto done;
0295     if (s->is_output) {
0296         s->unstable_frame = false;
0297         cobalt_enable_output(s);
0298         goto done;
0299     }
0300 
0301     cobalt_enable_input(s);
0302 
0303     fw = COBALT_CVI_FREEWHEEL(cobalt, rx);
0304     vmr = COBALT_CVI_VMR(cobalt, rx);
0305     clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx);
0306 
0307     iowrite32(M00460_CONTROL_BITMAP_CLEAR_MSK, &evcnt->control);
0308     iowrite32(M00460_CONTROL_BITMAP_ENABLE_MSK, &evcnt->control);
0309     iowrite32(bt->width, &cvi->frame_width);
0310     iowrite32(bt->height, &cvi->frame_height);
0311     tot_size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
0312     iowrite32(div_u64((u64)V4L2_DV_BT_FRAME_WIDTH(bt) * COBALT_CLK * 4,
0313               bt->pixelclock), &vmr->hsync_timeout_val);
0314     iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control);
0315     clk_freq = ioread32(&fw->clk_freq);
0316     iowrite32(clk_freq / 1000000, &clkloss->ref_clk_cnt_val);
0317     /* The lower bound for the clock frequency is 0.5% lower as is
0318      * allowed by the spec */
0319     iowrite32(div_u64(bt->pixelclock * 995, 1000000000),
0320           &clkloss->test_clk_cnt_val);
0321     /* will be enabled after the first frame has been received */
0322     iowrite32(bt->width * bt->height, &fw->active_length);
0323     iowrite32(div_u64((u64)clk_freq * tot_size, bt->pixelclock),
0324           &fw->total_length);
0325     iowrite32(M00233_IRQ_TRIGGERS_BITMAP_VACTIVE_AREA_MSK |
0326           M00233_IRQ_TRIGGERS_BITMAP_HACTIVE_AREA_MSK,
0327           &vmr->irq_triggers);
0328     iowrite32(0, &cvi->control);
0329     iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control);
0330 
0331     iowrite32(0xff, &fw->output_color);
0332     iowrite32(M00479_CTRL_BITMAP_ENABLE_MSK, &clkloss->ctrl);
0333     iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK |
0334           M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK, &fw->ctrl);
0335     s->unstable_frame = true;
0336     s->enable_freewheel = false;
0337     s->enable_cvi = false;
0338     s->skip_first_frames = 0;
0339 
0340 done:
0341     s->sequence = 0;
0342     cobalt_dma_start_streaming(s);
0343     return 0;
0344 }
0345 
0346 static void cobalt_dma_stop_streaming(struct cobalt_stream *s)
0347 {
0348     struct cobalt *cobalt = s->cobalt;
0349     struct sg_dma_desc_info *desc;
0350     struct cobalt_buffer *cb;
0351     struct list_head *p;
0352     unsigned long flags;
0353     int timeout_msec = 100;
0354     int rx = s->video_channel;
0355     struct m00460_evcnt_regmap __iomem *evcnt =
0356         COBALT_CVI_EVCNT(cobalt, rx);
0357 
0358     if (!s->is_output) {
0359         iowrite32(0, &evcnt->control);
0360     } else if (!s->is_audio) {
0361         struct m00514_syncgen_flow_evcnt_regmap __iomem *vo =
0362             COBALT_TX_BASE(cobalt);
0363 
0364         iowrite32(M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK, &vo->control);
0365         iowrite32(0, &vo->control);
0366     }
0367 
0368     /* Try to stop the DMA engine gracefully */
0369     spin_lock_irqsave(&s->irqlock, flags);
0370     list_for_each(p, &s->bufs) {
0371         cb = list_entry(p, struct cobalt_buffer, list);
0372         desc = &s->dma_desc_info[cb->vb.vb2_buf.index];
0373         /* Stop DMA after this descriptor chain */
0374         descriptor_list_end_of_chain(desc);
0375     }
0376     spin_unlock_irqrestore(&s->irqlock, flags);
0377 
0378     /* Wait 100 millisecond for DMA to finish, abort on timeout. */
0379     if (!wait_event_timeout(s->q.done_wq, is_dma_done(s),
0380                 msecs_to_jiffies(timeout_msec))) {
0381         omni_sg_dma_abort_channel(s);
0382         pr_warn("aborted\n");
0383     }
0384     cobalt_write_bar0(cobalt, DMA_INTERRUPT_STATUS_REG,
0385             1 << s->dma_channel);
0386 }
0387 
0388 static void cobalt_stop_streaming(struct vb2_queue *q)
0389 {
0390     struct cobalt_stream *s = q->drv_priv;
0391     struct cobalt *cobalt = s->cobalt;
0392     int rx = s->video_channel;
0393     struct m00233_video_measure_regmap __iomem *vmr;
0394     struct m00473_freewheel_regmap __iomem *fw;
0395     struct m00479_clk_loss_detector_regmap __iomem *clkloss;
0396     struct cobalt_buffer *cb;
0397     struct list_head *p, *safe;
0398     unsigned long flags;
0399 
0400     cobalt_dma_stop_streaming(s);
0401 
0402     /* Return all buffers to user space */
0403     spin_lock_irqsave(&s->irqlock, flags);
0404     list_for_each_safe(p, safe, &s->bufs) {
0405         cb = list_entry(p, struct cobalt_buffer, list);
0406         list_del(&cb->list);
0407         vb2_buffer_done(&cb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
0408     }
0409     spin_unlock_irqrestore(&s->irqlock, flags);
0410 
0411     if (s->is_audio || s->is_output)
0412         return;
0413 
0414     fw = COBALT_CVI_FREEWHEEL(cobalt, rx);
0415     vmr = COBALT_CVI_VMR(cobalt, rx);
0416     clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx);
0417     iowrite32(0, &vmr->control);
0418     iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control);
0419     iowrite32(0, &fw->ctrl);
0420     iowrite32(0, &clkloss->ctrl);
0421 }
0422 
0423 static const struct vb2_ops cobalt_qops = {
0424     .queue_setup = cobalt_queue_setup,
0425     .buf_init = cobalt_buf_init,
0426     .buf_cleanup = cobalt_buf_cleanup,
0427     .buf_prepare = cobalt_buf_prepare,
0428     .buf_queue = cobalt_buf_queue,
0429     .start_streaming = cobalt_start_streaming,
0430     .stop_streaming = cobalt_stop_streaming,
0431     .wait_prepare = vb2_ops_wait_prepare,
0432     .wait_finish = vb2_ops_wait_finish,
0433 };
0434 
0435 /* V4L2 ioctls */
0436 
0437 #ifdef CONFIG_VIDEO_ADV_DEBUG
0438 static int cobalt_cobaltc(struct cobalt *cobalt, unsigned int cmd, void *arg)
0439 {
0440     struct v4l2_dbg_register *regs = arg;
0441     void __iomem *adrs = cobalt->bar1 + regs->reg;
0442 
0443     cobalt_info("cobalt_cobaltc: adrs = %p\n", adrs);
0444 
0445     if (!capable(CAP_SYS_ADMIN))
0446         return -EPERM;
0447 
0448     regs->size = 4;
0449     if (cmd == VIDIOC_DBG_S_REGISTER)
0450         iowrite32(regs->val, adrs);
0451     else
0452         regs->val = ioread32(adrs);
0453     return 0;
0454 }
0455 
0456 static int cobalt_g_register(struct file *file, void *priv_fh,
0457         struct v4l2_dbg_register *reg)
0458 {
0459     struct cobalt_stream *s = video_drvdata(file);
0460     struct cobalt *cobalt = s->cobalt;
0461 
0462     return cobalt_cobaltc(cobalt, VIDIOC_DBG_G_REGISTER, reg);
0463 }
0464 
0465 static int cobalt_s_register(struct file *file, void *priv_fh,
0466         const struct v4l2_dbg_register *reg)
0467 {
0468     struct cobalt_stream *s = video_drvdata(file);
0469     struct cobalt *cobalt = s->cobalt;
0470 
0471     return cobalt_cobaltc(cobalt, VIDIOC_DBG_S_REGISTER,
0472             (struct v4l2_dbg_register *)reg);
0473 }
0474 #endif
0475 
0476 static int cobalt_querycap(struct file *file, void *priv_fh,
0477                 struct v4l2_capability *vcap)
0478 {
0479     struct cobalt_stream *s = video_drvdata(file);
0480     struct cobalt *cobalt = s->cobalt;
0481 
0482     strscpy(vcap->driver, "cobalt", sizeof(vcap->driver));
0483     strscpy(vcap->card, "cobalt", sizeof(vcap->card));
0484     snprintf(vcap->bus_info, sizeof(vcap->bus_info),
0485          "PCIe:%s", pci_name(cobalt->pci_dev));
0486     vcap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE |
0487         V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS;
0488     if (cobalt->have_hsma_tx)
0489         vcap->capabilities |= V4L2_CAP_VIDEO_OUTPUT;
0490     return 0;
0491 }
0492 
0493 static void cobalt_video_input_status_show(struct cobalt_stream *s)
0494 {
0495     struct m00389_cvi_regmap __iomem *cvi;
0496     struct m00233_video_measure_regmap __iomem *vmr;
0497     struct m00473_freewheel_regmap __iomem *fw;
0498     struct m00479_clk_loss_detector_regmap __iomem *clkloss;
0499     struct m00235_fdma_packer_regmap __iomem *packer;
0500     int rx = s->video_channel;
0501     struct cobalt *cobalt = s->cobalt;
0502     u32 cvi_ctrl, cvi_stat;
0503     u32 vmr_ctrl, vmr_stat;
0504 
0505     cvi = COBALT_CVI(cobalt, rx);
0506     vmr = COBALT_CVI_VMR(cobalt, rx);
0507     fw = COBALT_CVI_FREEWHEEL(cobalt, rx);
0508     clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx);
0509     packer = COBALT_CVI_PACKER(cobalt, rx);
0510     cvi_ctrl = ioread32(&cvi->control);
0511     cvi_stat = ioread32(&cvi->status);
0512     vmr_ctrl = ioread32(&vmr->control);
0513     vmr_stat = ioread32(&vmr->status);
0514     cobalt_info("rx%d: cvi resolution: %dx%d\n", rx,
0515             ioread32(&cvi->frame_width), ioread32(&cvi->frame_height));
0516     cobalt_info("rx%d: cvi control: %s%s%s\n", rx,
0517         (cvi_ctrl & M00389_CONTROL_BITMAP_ENABLE_MSK) ?
0518             "enable " : "disable ",
0519         (cvi_ctrl & M00389_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK) ?
0520             "HSync- " : "HSync+ ",
0521         (cvi_ctrl & M00389_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK) ?
0522             "VSync- " : "VSync+ ");
0523     cobalt_info("rx%d: cvi status: %s%s\n", rx,
0524         (cvi_stat & M00389_STATUS_BITMAP_LOCK_MSK) ?
0525             "lock " : "no-lock ",
0526         (cvi_stat & M00389_STATUS_BITMAP_ERROR_MSK) ?
0527             "error " : "no-error ");
0528 
0529     cobalt_info("rx%d: Measurements: %s%s%s%s%s%s%s\n", rx,
0530         (vmr_ctrl & M00233_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK) ?
0531             "HSync- " : "HSync+ ",
0532         (vmr_ctrl & M00233_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK) ?
0533             "VSync- " : "VSync+ ",
0534         (vmr_ctrl & M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK) ?
0535             "enabled " : "disabled ",
0536         (vmr_ctrl & M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK) ?
0537             "irq-enabled " : "irq-disabled ",
0538         (vmr_ctrl & M00233_CONTROL_BITMAP_UPDATE_ON_HSYNC_MSK) ?
0539             "update-on-hsync " : "",
0540         (vmr_stat & M00233_STATUS_BITMAP_HSYNC_TIMEOUT_MSK) ?
0541             "hsync-timeout " : "",
0542         (vmr_stat & M00233_STATUS_BITMAP_INIT_DONE_MSK) ?
0543             "init-done" : "");
0544     cobalt_info("rx%d: irq_status: 0x%02x irq_triggers: 0x%02x\n", rx,
0545             ioread32(&vmr->irq_status) & 0xff,
0546             ioread32(&vmr->irq_triggers) & 0xff);
0547     cobalt_info("rx%d: vsync: %d\n", rx, ioread32(&vmr->vsync_time));
0548     cobalt_info("rx%d: vbp: %d\n", rx, ioread32(&vmr->vback_porch));
0549     cobalt_info("rx%d: vact: %d\n", rx, ioread32(&vmr->vactive_area));
0550     cobalt_info("rx%d: vfb: %d\n", rx, ioread32(&vmr->vfront_porch));
0551     cobalt_info("rx%d: hsync: %d\n", rx, ioread32(&vmr->hsync_time));
0552     cobalt_info("rx%d: hbp: %d\n", rx, ioread32(&vmr->hback_porch));
0553     cobalt_info("rx%d: hact: %d\n", rx, ioread32(&vmr->hactive_area));
0554     cobalt_info("rx%d: hfb: %d\n", rx, ioread32(&vmr->hfront_porch));
0555     cobalt_info("rx%d: Freewheeling: %s%s%s\n", rx,
0556         (ioread32(&fw->ctrl) & M00473_CTRL_BITMAP_ENABLE_MSK) ?
0557             "enabled " : "disabled ",
0558         (ioread32(&fw->ctrl) & M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK) ?
0559             "forced " : "",
0560         (ioread32(&fw->status) & M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK) ?
0561             "freewheeling " : "video-passthrough ");
0562     iowrite32(0xff, &vmr->irq_status);
0563     cobalt_info("rx%d: Clock Loss Detection: %s%s\n", rx,
0564         (ioread32(&clkloss->ctrl) & M00479_CTRL_BITMAP_ENABLE_MSK) ?
0565             "enabled " : "disabled ",
0566         (ioread32(&clkloss->status) & M00479_STATUS_BITMAP_CLOCK_MISSING_MSK) ?
0567             "clock-missing " : "found-clock ");
0568     cobalt_info("rx%d: Packer: %x\n", rx, ioread32(&packer->control));
0569 }
0570 
0571 static int cobalt_log_status(struct file *file, void *priv_fh)
0572 {
0573     struct cobalt_stream *s = video_drvdata(file);
0574     struct cobalt *cobalt = s->cobalt;
0575     struct m00514_syncgen_flow_evcnt_regmap __iomem *vo =
0576         COBALT_TX_BASE(cobalt);
0577     u8 stat;
0578 
0579     cobalt_info("%s", cobalt->hdl_info);
0580     cobalt_info("sysctrl: %08x, sysstat: %08x\n",
0581             cobalt_g_sysctrl(cobalt),
0582             cobalt_g_sysstat(cobalt));
0583     cobalt_info("dma channel: %d, video channel: %d\n",
0584             s->dma_channel, s->video_channel);
0585     cobalt_pcie_status_show(cobalt);
0586     cobalt_cpld_status(cobalt);
0587     cobalt_irq_log_status(cobalt);
0588     v4l2_subdev_call(s->sd, core, log_status);
0589     if (!s->is_output) {
0590         cobalt_video_input_status_show(s);
0591         return 0;
0592     }
0593 
0594     stat = ioread32(&vo->rd_status);
0595 
0596     cobalt_info("tx: status: %s%s\n",
0597         (stat & M00514_RD_STATUS_BITMAP_FLOW_CTRL_NO_DATA_ERROR_MSK) ?
0598             "no_data " : "",
0599         (stat & M00514_RD_STATUS_BITMAP_READY_BUFFER_FULL_MSK) ?
0600             "ready_buffer_full " : "");
0601     cobalt_info("tx: evcnt: %d\n", ioread32(&vo->rd_evcnt_count));
0602     return 0;
0603 }
0604 
0605 static int cobalt_enum_dv_timings(struct file *file, void *priv_fh,
0606                     struct v4l2_enum_dv_timings *timings)
0607 {
0608     struct cobalt_stream *s = video_drvdata(file);
0609 
0610     if (s->input == 1) {
0611         if (timings->index)
0612             return -EINVAL;
0613         memset(timings->reserved, 0, sizeof(timings->reserved));
0614         timings->timings = cea1080p60;
0615         return 0;
0616     }
0617     timings->pad = 0;
0618     return v4l2_subdev_call(s->sd,
0619             pad, enum_dv_timings, timings);
0620 }
0621 
0622 static int cobalt_s_dv_timings(struct file *file, void *priv_fh,
0623                     struct v4l2_dv_timings *timings)
0624 {
0625     struct cobalt_stream *s = video_drvdata(file);
0626     int err;
0627 
0628     if (s->input == 1) {
0629         *timings = cea1080p60;
0630         return 0;
0631     }
0632 
0633     if (v4l2_match_dv_timings(timings, &s->timings, 0, true))
0634         return 0;
0635 
0636     if (vb2_is_busy(&s->q))
0637         return -EBUSY;
0638 
0639     err = v4l2_subdev_call(s->sd,
0640             video, s_dv_timings, timings);
0641     if (!err) {
0642         s->timings = *timings;
0643         s->width = timings->bt.width;
0644         s->height = timings->bt.height;
0645         s->stride = timings->bt.width * s->bpp;
0646     }
0647     return err;
0648 }
0649 
0650 static int cobalt_g_dv_timings(struct file *file, void *priv_fh,
0651                     struct v4l2_dv_timings *timings)
0652 {
0653     struct cobalt_stream *s = video_drvdata(file);
0654 
0655     if (s->input == 1) {
0656         *timings = cea1080p60;
0657         return 0;
0658     }
0659     return v4l2_subdev_call(s->sd,
0660             video, g_dv_timings, timings);
0661 }
0662 
0663 static int cobalt_query_dv_timings(struct file *file, void *priv_fh,
0664                     struct v4l2_dv_timings *timings)
0665 {
0666     struct cobalt_stream *s = video_drvdata(file);
0667 
0668     if (s->input == 1) {
0669         *timings = cea1080p60;
0670         return 0;
0671     }
0672     return v4l2_subdev_call(s->sd,
0673             video, query_dv_timings, timings);
0674 }
0675 
0676 static int cobalt_dv_timings_cap(struct file *file, void *priv_fh,
0677                     struct v4l2_dv_timings_cap *cap)
0678 {
0679     struct cobalt_stream *s = video_drvdata(file);
0680 
0681     cap->pad = 0;
0682     return v4l2_subdev_call(s->sd,
0683             pad, dv_timings_cap, cap);
0684 }
0685 
0686 static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv_fh,
0687         struct v4l2_fmtdesc *f)
0688 {
0689     switch (f->index) {
0690     case 0:
0691         f->pixelformat = V4L2_PIX_FMT_YUYV;
0692         break;
0693     case 1:
0694         f->pixelformat = V4L2_PIX_FMT_RGB24;
0695         break;
0696     case 2:
0697         f->pixelformat = V4L2_PIX_FMT_BGR32;
0698         break;
0699     default:
0700         return -EINVAL;
0701     }
0702 
0703     return 0;
0704 }
0705 
0706 static int cobalt_g_fmt_vid_cap(struct file *file, void *priv_fh,
0707         struct v4l2_format *f)
0708 {
0709     struct cobalt_stream *s = video_drvdata(file);
0710     struct v4l2_pix_format *pix = &f->fmt.pix;
0711     struct v4l2_subdev_format sd_fmt;
0712 
0713     pix->width = s->width;
0714     pix->height = s->height;
0715     pix->bytesperline = s->stride;
0716     pix->field = V4L2_FIELD_NONE;
0717 
0718     if (s->input == 1) {
0719         pix->colorspace = V4L2_COLORSPACE_SRGB;
0720     } else {
0721         sd_fmt.pad = s->pad_source;
0722         sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
0723         v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt);
0724         v4l2_fill_pix_format(pix, &sd_fmt.format);
0725     }
0726 
0727     pix->pixelformat = s->pixfmt;
0728     pix->sizeimage = pix->bytesperline * pix->height;
0729 
0730     return 0;
0731 }
0732 
0733 static int cobalt_try_fmt_vid_cap(struct file *file, void *priv_fh,
0734         struct v4l2_format *f)
0735 {
0736     struct cobalt_stream *s = video_drvdata(file);
0737     struct v4l2_pix_format *pix = &f->fmt.pix;
0738     struct v4l2_subdev_format sd_fmt;
0739 
0740     /* Check for min (QCIF) and max (Full HD) size */
0741     if ((pix->width < 176) || (pix->height < 144)) {
0742         pix->width = 176;
0743         pix->height = 144;
0744     }
0745 
0746     if ((pix->width > 1920) || (pix->height > 1080)) {
0747         pix->width = 1920;
0748         pix->height = 1080;
0749     }
0750 
0751     /* Make width multiple of 4 */
0752     pix->width &= ~0x3;
0753 
0754     /* Make height multiple of 2 */
0755     pix->height &= ~0x1;
0756 
0757     if (s->input == 1) {
0758         /* Generator => fixed format only */
0759         pix->width = 1920;
0760         pix->height = 1080;
0761         pix->colorspace = V4L2_COLORSPACE_SRGB;
0762     } else {
0763         sd_fmt.pad = s->pad_source;
0764         sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
0765         v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt);
0766         v4l2_fill_pix_format(pix, &sd_fmt.format);
0767     }
0768 
0769     switch (pix->pixelformat) {
0770     case V4L2_PIX_FMT_YUYV:
0771     default:
0772         pix->bytesperline = max(pix->bytesperline & ~0x3,
0773                 pix->width * COBALT_BYTES_PER_PIXEL_YUYV);
0774         pix->pixelformat = V4L2_PIX_FMT_YUYV;
0775         break;
0776     case V4L2_PIX_FMT_RGB24:
0777         pix->bytesperline = max(pix->bytesperline & ~0x3,
0778                 pix->width * COBALT_BYTES_PER_PIXEL_RGB24);
0779         break;
0780     case V4L2_PIX_FMT_BGR32:
0781         pix->bytesperline = max(pix->bytesperline & ~0x3,
0782                 pix->width * COBALT_BYTES_PER_PIXEL_RGB32);
0783         break;
0784     }
0785 
0786     pix->sizeimage = pix->bytesperline * pix->height;
0787     pix->field = V4L2_FIELD_NONE;
0788 
0789     return 0;
0790 }
0791 
0792 static int cobalt_s_fmt_vid_cap(struct file *file, void *priv_fh,
0793         struct v4l2_format *f)
0794 {
0795     struct cobalt_stream *s = video_drvdata(file);
0796     struct v4l2_pix_format *pix = &f->fmt.pix;
0797 
0798     if (vb2_is_busy(&s->q))
0799         return -EBUSY;
0800 
0801     if (cobalt_try_fmt_vid_cap(file, priv_fh, f))
0802         return -EINVAL;
0803 
0804     s->width = pix->width;
0805     s->height = pix->height;
0806     s->stride = pix->bytesperline;
0807     switch (pix->pixelformat) {
0808     case V4L2_PIX_FMT_YUYV:
0809         s->bpp = COBALT_BYTES_PER_PIXEL_YUYV;
0810         break;
0811     case V4L2_PIX_FMT_RGB24:
0812         s->bpp = COBALT_BYTES_PER_PIXEL_RGB24;
0813         break;
0814     case V4L2_PIX_FMT_BGR32:
0815         s->bpp = COBALT_BYTES_PER_PIXEL_RGB32;
0816         break;
0817     default:
0818         return -EINVAL;
0819     }
0820     s->pixfmt = pix->pixelformat;
0821     cobalt_enable_input(s);
0822 
0823     return 0;
0824 }
0825 
0826 static int cobalt_try_fmt_vid_out(struct file *file, void *priv_fh,
0827         struct v4l2_format *f)
0828 {
0829     struct v4l2_pix_format *pix = &f->fmt.pix;
0830 
0831     /* Check for min (QCIF) and max (Full HD) size */
0832     if ((pix->width < 176) || (pix->height < 144)) {
0833         pix->width = 176;
0834         pix->height = 144;
0835     }
0836 
0837     if ((pix->width > 1920) || (pix->height > 1080)) {
0838         pix->width = 1920;
0839         pix->height = 1080;
0840     }
0841 
0842     /* Make width multiple of 4 */
0843     pix->width &= ~0x3;
0844 
0845     /* Make height multiple of 2 */
0846     pix->height &= ~0x1;
0847 
0848     switch (pix->pixelformat) {
0849     case V4L2_PIX_FMT_YUYV:
0850     default:
0851         pix->bytesperline = max(pix->bytesperline & ~0x3,
0852                 pix->width * COBALT_BYTES_PER_PIXEL_YUYV);
0853         pix->pixelformat = V4L2_PIX_FMT_YUYV;
0854         break;
0855     case V4L2_PIX_FMT_BGR32:
0856         pix->bytesperline = max(pix->bytesperline & ~0x3,
0857                 pix->width * COBALT_BYTES_PER_PIXEL_RGB32);
0858         break;
0859     }
0860 
0861     pix->sizeimage = pix->bytesperline * pix->height;
0862     pix->field = V4L2_FIELD_NONE;
0863 
0864     return 0;
0865 }
0866 
0867 static int cobalt_g_fmt_vid_out(struct file *file, void *priv_fh,
0868         struct v4l2_format *f)
0869 {
0870     struct cobalt_stream *s = video_drvdata(file);
0871     struct v4l2_pix_format *pix = &f->fmt.pix;
0872 
0873     pix->width = s->width;
0874     pix->height = s->height;
0875     pix->bytesperline = s->stride;
0876     pix->field = V4L2_FIELD_NONE;
0877     pix->pixelformat = s->pixfmt;
0878     pix->colorspace = s->colorspace;
0879     pix->xfer_func = s->xfer_func;
0880     pix->ycbcr_enc = s->ycbcr_enc;
0881     pix->quantization = s->quantization;
0882     pix->sizeimage = pix->bytesperline * pix->height;
0883 
0884     return 0;
0885 }
0886 
0887 static int cobalt_enum_fmt_vid_out(struct file *file, void *priv_fh,
0888         struct v4l2_fmtdesc *f)
0889 {
0890     switch (f->index) {
0891     case 0:
0892         f->pixelformat = V4L2_PIX_FMT_YUYV;
0893         break;
0894     case 1:
0895         f->pixelformat = V4L2_PIX_FMT_BGR32;
0896         break;
0897     default:
0898         return -EINVAL;
0899     }
0900 
0901     return 0;
0902 }
0903 
0904 static int cobalt_s_fmt_vid_out(struct file *file, void *priv_fh,
0905         struct v4l2_format *f)
0906 {
0907     struct cobalt_stream *s = video_drvdata(file);
0908     struct v4l2_pix_format *pix = &f->fmt.pix;
0909     struct v4l2_subdev_format sd_fmt = { 0 };
0910     u32 code;
0911 
0912     if (cobalt_try_fmt_vid_out(file, priv_fh, f))
0913         return -EINVAL;
0914 
0915     if (vb2_is_busy(&s->q) && (pix->pixelformat != s->pixfmt ||
0916         pix->width != s->width || pix->height != s->height ||
0917         pix->bytesperline != s->stride))
0918         return -EBUSY;
0919 
0920     switch (pix->pixelformat) {
0921     case V4L2_PIX_FMT_YUYV:
0922         s->bpp = COBALT_BYTES_PER_PIXEL_YUYV;
0923         code = MEDIA_BUS_FMT_UYVY8_1X16;
0924         break;
0925     case V4L2_PIX_FMT_BGR32:
0926         s->bpp = COBALT_BYTES_PER_PIXEL_RGB32;
0927         code = MEDIA_BUS_FMT_RGB888_1X24;
0928         break;
0929     default:
0930         return -EINVAL;
0931     }
0932     s->width = pix->width;
0933     s->height = pix->height;
0934     s->stride = pix->bytesperline;
0935     s->pixfmt = pix->pixelformat;
0936     s->colorspace = pix->colorspace;
0937     s->xfer_func = pix->xfer_func;
0938     s->ycbcr_enc = pix->ycbcr_enc;
0939     s->quantization = pix->quantization;
0940     sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
0941     v4l2_fill_mbus_format(&sd_fmt.format, pix, code);
0942     v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt);
0943     return 0;
0944 }
0945 
0946 static int cobalt_enum_input(struct file *file, void *priv_fh,
0947                  struct v4l2_input *inp)
0948 {
0949     struct cobalt_stream *s = video_drvdata(file);
0950 
0951     if (inp->index > 1)
0952         return -EINVAL;
0953     if (inp->index == 0)
0954         snprintf(inp->name, sizeof(inp->name),
0955                 "HDMI-%d", s->video_channel);
0956     else
0957         snprintf(inp->name, sizeof(inp->name),
0958                 "Generator-%d", s->video_channel);
0959     inp->type = V4L2_INPUT_TYPE_CAMERA;
0960     inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
0961     if (inp->index == 1)
0962         return 0;
0963     return v4l2_subdev_call(s->sd,
0964             video, g_input_status, &inp->status);
0965 }
0966 
0967 static int cobalt_g_input(struct file *file, void *priv_fh, unsigned int *i)
0968 {
0969     struct cobalt_stream *s = video_drvdata(file);
0970 
0971     *i = s->input;
0972     return 0;
0973 }
0974 
0975 static int cobalt_s_input(struct file *file, void *priv_fh, unsigned int i)
0976 {
0977     struct cobalt_stream *s = video_drvdata(file);
0978 
0979     if (i >= 2)
0980         return -EINVAL;
0981     if (vb2_is_busy(&s->q))
0982         return -EBUSY;
0983     s->input = i;
0984 
0985     cobalt_enable_input(s);
0986 
0987     if (s->input == 1) /* Test Pattern Generator */
0988         return 0;
0989 
0990     return v4l2_subdev_call(s->sd, video, s_routing,
0991             ADV76XX_PAD_HDMI_PORT_A, 0, 0);
0992 }
0993 
0994 static int cobalt_enum_output(struct file *file, void *priv_fh,
0995                  struct v4l2_output *out)
0996 {
0997     if (out->index)
0998         return -EINVAL;
0999     snprintf(out->name, sizeof(out->name), "HDMI-%d", out->index);
1000     out->type = V4L2_OUTPUT_TYPE_ANALOG;
1001     out->capabilities = V4L2_OUT_CAP_DV_TIMINGS;
1002     return 0;
1003 }
1004 
1005 static int cobalt_g_output(struct file *file, void *priv_fh, unsigned int *i)
1006 {
1007     *i = 0;
1008     return 0;
1009 }
1010 
1011 static int cobalt_s_output(struct file *file, void *priv_fh, unsigned int i)
1012 {
1013     return i ? -EINVAL : 0;
1014 }
1015 
1016 static int cobalt_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
1017 {
1018     struct cobalt_stream *s = video_drvdata(file);
1019     u32 pad = edid->pad;
1020     int ret;
1021 
1022     if (edid->pad >= (s->is_output ? 1 : 2))
1023         return -EINVAL;
1024     edid->pad = 0;
1025     ret = v4l2_subdev_call(s->sd, pad, get_edid, edid);
1026     edid->pad = pad;
1027     return ret;
1028 }
1029 
1030 static int cobalt_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
1031 {
1032     struct cobalt_stream *s = video_drvdata(file);
1033     u32 pad = edid->pad;
1034     int ret;
1035 
1036     if (edid->pad >= 2)
1037         return -EINVAL;
1038     edid->pad = 0;
1039     ret = v4l2_subdev_call(s->sd, pad, set_edid, edid);
1040     edid->pad = pad;
1041     return ret;
1042 }
1043 
1044 static int cobalt_subscribe_event(struct v4l2_fh *fh,
1045                   const struct v4l2_event_subscription *sub)
1046 {
1047     switch (sub->type) {
1048     case V4L2_EVENT_SOURCE_CHANGE:
1049         return v4l2_event_subscribe(fh, sub, 4, NULL);
1050     }
1051     return v4l2_ctrl_subscribe_event(fh, sub);
1052 }
1053 
1054 static int cobalt_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
1055 {
1056     struct cobalt_stream *s = video_drvdata(file);
1057     struct v4l2_fract fps;
1058 
1059     if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1060         return -EINVAL;
1061 
1062     fps = v4l2_calc_timeperframe(&s->timings);
1063     a->parm.capture.timeperframe.numerator = fps.numerator;
1064     a->parm.capture.timeperframe.denominator = fps.denominator;
1065     a->parm.capture.readbuffers = 3;
1066     return 0;
1067 }
1068 
1069 static int cobalt_g_pixelaspect(struct file *file, void *fh,
1070                 int type, struct v4l2_fract *f)
1071 {
1072     struct cobalt_stream *s = video_drvdata(file);
1073     struct v4l2_dv_timings timings;
1074     int err = 0;
1075 
1076     if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1077         return -EINVAL;
1078 
1079     if (s->input == 1)
1080         timings = cea1080p60;
1081     else
1082         err = v4l2_subdev_call(s->sd, video, g_dv_timings, &timings);
1083     if (!err)
1084         *f = v4l2_dv_timings_aspect_ratio(&timings);
1085     return err;
1086 }
1087 
1088 static int cobalt_g_selection(struct file *file, void *fh,
1089                   struct v4l2_selection *sel)
1090 {
1091     struct cobalt_stream *s = video_drvdata(file);
1092     struct v4l2_dv_timings timings;
1093     int err = 0;
1094 
1095     if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1096         return -EINVAL;
1097 
1098     if (s->input == 1)
1099         timings = cea1080p60;
1100     else
1101         err = v4l2_subdev_call(s->sd, video, g_dv_timings, &timings);
1102 
1103     if (err)
1104         return err;
1105 
1106     switch (sel->target) {
1107     case V4L2_SEL_TGT_CROP_BOUNDS:
1108     case V4L2_SEL_TGT_CROP_DEFAULT:
1109         sel->r.top = 0;
1110         sel->r.left = 0;
1111         sel->r.width = timings.bt.width;
1112         sel->r.height = timings.bt.height;
1113         break;
1114     default:
1115         return -EINVAL;
1116     }
1117     return 0;
1118 }
1119 
1120 static const struct v4l2_ioctl_ops cobalt_ioctl_ops = {
1121     .vidioc_querycap        = cobalt_querycap,
1122     .vidioc_g_parm          = cobalt_g_parm,
1123     .vidioc_log_status      = cobalt_log_status,
1124     .vidioc_streamon        = vb2_ioctl_streamon,
1125     .vidioc_streamoff       = vb2_ioctl_streamoff,
1126     .vidioc_g_pixelaspect       = cobalt_g_pixelaspect,
1127     .vidioc_g_selection     = cobalt_g_selection,
1128     .vidioc_enum_input      = cobalt_enum_input,
1129     .vidioc_g_input         = cobalt_g_input,
1130     .vidioc_s_input         = cobalt_s_input,
1131     .vidioc_enum_fmt_vid_cap    = cobalt_enum_fmt_vid_cap,
1132     .vidioc_g_fmt_vid_cap       = cobalt_g_fmt_vid_cap,
1133     .vidioc_s_fmt_vid_cap       = cobalt_s_fmt_vid_cap,
1134     .vidioc_try_fmt_vid_cap     = cobalt_try_fmt_vid_cap,
1135     .vidioc_enum_output     = cobalt_enum_output,
1136     .vidioc_g_output        = cobalt_g_output,
1137     .vidioc_s_output        = cobalt_s_output,
1138     .vidioc_enum_fmt_vid_out    = cobalt_enum_fmt_vid_out,
1139     .vidioc_g_fmt_vid_out       = cobalt_g_fmt_vid_out,
1140     .vidioc_s_fmt_vid_out       = cobalt_s_fmt_vid_out,
1141     .vidioc_try_fmt_vid_out     = cobalt_try_fmt_vid_out,
1142     .vidioc_s_dv_timings        = cobalt_s_dv_timings,
1143     .vidioc_g_dv_timings        = cobalt_g_dv_timings,
1144     .vidioc_query_dv_timings    = cobalt_query_dv_timings,
1145     .vidioc_enum_dv_timings     = cobalt_enum_dv_timings,
1146     .vidioc_dv_timings_cap      = cobalt_dv_timings_cap,
1147     .vidioc_g_edid          = cobalt_g_edid,
1148     .vidioc_s_edid          = cobalt_s_edid,
1149     .vidioc_subscribe_event     = cobalt_subscribe_event,
1150     .vidioc_unsubscribe_event   = v4l2_event_unsubscribe,
1151     .vidioc_reqbufs         = vb2_ioctl_reqbufs,
1152     .vidioc_create_bufs     = vb2_ioctl_create_bufs,
1153     .vidioc_querybuf        = vb2_ioctl_querybuf,
1154     .vidioc_qbuf            = vb2_ioctl_qbuf,
1155     .vidioc_dqbuf           = vb2_ioctl_dqbuf,
1156     .vidioc_expbuf          = vb2_ioctl_expbuf,
1157 #ifdef CONFIG_VIDEO_ADV_DEBUG
1158     .vidioc_g_register              = cobalt_g_register,
1159     .vidioc_s_register              = cobalt_s_register,
1160 #endif
1161 };
1162 
1163 static const struct v4l2_ioctl_ops cobalt_ioctl_empty_ops = {
1164 #ifdef CONFIG_VIDEO_ADV_DEBUG
1165     .vidioc_g_register              = cobalt_g_register,
1166     .vidioc_s_register              = cobalt_s_register,
1167 #endif
1168 };
1169 
1170 /* Register device nodes */
1171 
1172 static const struct v4l2_file_operations cobalt_fops = {
1173     .owner = THIS_MODULE,
1174     .open = v4l2_fh_open,
1175     .unlocked_ioctl = video_ioctl2,
1176     .release = vb2_fop_release,
1177     .poll = vb2_fop_poll,
1178     .mmap = vb2_fop_mmap,
1179     .read = vb2_fop_read,
1180 };
1181 
1182 static const struct v4l2_file_operations cobalt_out_fops = {
1183     .owner = THIS_MODULE,
1184     .open = v4l2_fh_open,
1185     .unlocked_ioctl = video_ioctl2,
1186     .release = vb2_fop_release,
1187     .poll = vb2_fop_poll,
1188     .mmap = vb2_fop_mmap,
1189     .write = vb2_fop_write,
1190 };
1191 
1192 static const struct v4l2_file_operations cobalt_empty_fops = {
1193     .owner = THIS_MODULE,
1194     .open = v4l2_fh_open,
1195     .unlocked_ioctl = video_ioctl2,
1196     .release = v4l2_fh_release,
1197 };
1198 
1199 static int cobalt_node_register(struct cobalt *cobalt, int node)
1200 {
1201     static const struct v4l2_dv_timings dv1080p60 =
1202         V4L2_DV_BT_CEA_1920X1080P60;
1203     struct cobalt_stream *s = cobalt->streams + node;
1204     struct video_device *vdev = &s->vdev;
1205     struct vb2_queue *q = &s->q;
1206     int ret;
1207 
1208     mutex_init(&s->lock);
1209     spin_lock_init(&s->irqlock);
1210 
1211     snprintf(vdev->name, sizeof(vdev->name),
1212             "%s-%d", cobalt->v4l2_dev.name, node);
1213     s->width = 1920;
1214     /* Audio frames are just 4 lines of 1920 bytes */
1215     s->height = s->is_audio ? 4 : 1080;
1216 
1217     if (s->is_audio) {
1218         s->bpp = 1;
1219         s->pixfmt = V4L2_PIX_FMT_GREY;
1220     } else if (s->is_output) {
1221         s->bpp = COBALT_BYTES_PER_PIXEL_RGB32;
1222         s->pixfmt = V4L2_PIX_FMT_BGR32;
1223     } else {
1224         s->bpp = COBALT_BYTES_PER_PIXEL_YUYV;
1225         s->pixfmt = V4L2_PIX_FMT_YUYV;
1226     }
1227     s->colorspace = V4L2_COLORSPACE_SRGB;
1228     s->stride = s->width * s->bpp;
1229 
1230     if (!s->is_audio) {
1231         if (s->is_dummy)
1232             cobalt_warn("Setting up dummy video node %d\n", node);
1233         vdev->v4l2_dev = &cobalt->v4l2_dev;
1234         if (s->is_dummy)
1235             vdev->fops = &cobalt_empty_fops;
1236         else
1237             vdev->fops = s->is_output ? &cobalt_out_fops :
1238                             &cobalt_fops;
1239         vdev->release = video_device_release_empty;
1240         vdev->vfl_dir = s->is_output ? VFL_DIR_TX : VFL_DIR_RX;
1241         vdev->lock = &s->lock;
1242         if (s->sd)
1243             vdev->ctrl_handler = s->sd->ctrl_handler;
1244         s->timings = dv1080p60;
1245         v4l2_subdev_call(s->sd, video, s_dv_timings, &s->timings);
1246         if (!s->is_output && s->sd)
1247             cobalt_enable_input(s);
1248         vdev->ioctl_ops = s->is_dummy ? &cobalt_ioctl_empty_ops :
1249                   &cobalt_ioctl_ops;
1250     }
1251 
1252     INIT_LIST_HEAD(&s->bufs);
1253     q->type = s->is_output ? V4L2_BUF_TYPE_VIDEO_OUTPUT :
1254                  V4L2_BUF_TYPE_VIDEO_CAPTURE;
1255     q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1256     q->io_modes |= s->is_output ? VB2_WRITE : VB2_READ;
1257     q->drv_priv = s;
1258     q->buf_struct_size = sizeof(struct cobalt_buffer);
1259     q->ops = &cobalt_qops;
1260     q->mem_ops = &vb2_dma_sg_memops;
1261     q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1262     q->min_buffers_needed = 2;
1263     q->lock = &s->lock;
1264     q->dev = &cobalt->pci_dev->dev;
1265     vdev->queue = q;
1266     vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
1267     if (s->is_output)
1268         vdev->device_caps |= V4L2_CAP_VIDEO_OUTPUT;
1269     else
1270         vdev->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
1271 
1272     video_set_drvdata(vdev, s);
1273     ret = vb2_queue_init(q);
1274     if (!s->is_audio && ret == 0)
1275         ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
1276     else if (!s->is_dummy)
1277         ret = cobalt_alsa_init(s);
1278 
1279     if (ret < 0) {
1280         if (!s->is_audio)
1281             cobalt_err("couldn't register v4l2 device node %d\n",
1282                     node);
1283         return ret;
1284     }
1285     cobalt_info("registered node %d\n", node);
1286     return 0;
1287 }
1288 
1289 /* Initialize v4l2 variables and register v4l2 devices */
1290 int cobalt_nodes_register(struct cobalt *cobalt)
1291 {
1292     int node, ret;
1293 
1294     /* Setup V4L2 Devices */
1295     for (node = 0; node < COBALT_NUM_STREAMS; node++) {
1296         ret = cobalt_node_register(cobalt, node);
1297         if (ret)
1298             return ret;
1299     }
1300     return 0;
1301 }
1302 
1303 /* Unregister v4l2 devices */
1304 void cobalt_nodes_unregister(struct cobalt *cobalt)
1305 {
1306     int node;
1307 
1308     /* Teardown all streams */
1309     for (node = 0; node < COBALT_NUM_STREAMS; node++) {
1310         struct cobalt_stream *s = cobalt->streams + node;
1311         struct video_device *vdev = &s->vdev;
1312 
1313         if (!s->is_audio)
1314             video_unregister_device(vdev);
1315         else if (!s->is_dummy)
1316             cobalt_alsa_exit(s);
1317     }
1318 }