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