0001
0002
0003
0004
0005
0006
0007
0008
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
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
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
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
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
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
0318
0319 iowrite32(div_u64(bt->pixelclock * 995, 1000000000),
0320 &clkloss->test_clk_cnt_val);
0321
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
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
0374 descriptor_list_end_of_chain(desc);
0375 }
0376 spin_unlock_irqrestore(&s->irqlock, flags);
0377
0378
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
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
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
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
0752 pix->width &= ~0x3;
0753
0754
0755 pix->height &= ~0x1;
0756
0757 if (s->input == 1) {
0758
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
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
0843 pix->width &= ~0x3;
0844
0845
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)
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
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
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
1290 int cobalt_nodes_register(struct cobalt *cobalt)
1291 {
1292 int node, ret;
1293
1294
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
1304 void cobalt_nodes_unregister(struct cobalt *cobalt)
1305 {
1306 int node;
1307
1308
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 }