linux/drivers/media/platform/rcar-vin/rcar-dma.c
<<
>>
Prefs
   1/*
   2 * Driver for Renesas R-Car VIN
   3 *
   4 * Copyright (C) 2016 Renesas Electronics Corp.
   5 * Copyright (C) 2011-2013 Renesas Solutions Corp.
   6 * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
   7 * Copyright (C) 2008 Magnus Damm
   8 *
   9 * Based on the soc-camera rcar_vin driver
  10 *
  11 * This program is free software; you can redistribute  it and/or modify it
  12 * under  the terms of  the GNU General  Public License as published by the
  13 * Free Software Foundation;  either version 2 of the  License, or (at your
  14 * option) any later version.
  15 */
  16
  17#include <linux/delay.h>
  18#include <linux/interrupt.h>
  19
  20#include <media/videobuf2-dma-contig.h>
  21
  22#include "rcar-vin.h"
  23
  24/* -----------------------------------------------------------------------------
  25 * HW Functions
  26 */
  27
  28/* Register offsets for R-Car VIN */
  29#define VNMC_REG        0x00    /* Video n Main Control Register */
  30#define VNMS_REG        0x04    /* Video n Module Status Register */
  31#define VNFC_REG        0x08    /* Video n Frame Capture Register */
  32#define VNSLPRC_REG     0x0C    /* Video n Start Line Pre-Clip Register */
  33#define VNELPRC_REG     0x10    /* Video n End Line Pre-Clip Register */
  34#define VNSPPRC_REG     0x14    /* Video n Start Pixel Pre-Clip Register */
  35#define VNEPPRC_REG     0x18    /* Video n End Pixel Pre-Clip Register */
  36#define VNSLPOC_REG     0x1C    /* Video n Start Line Post-Clip Register */
  37#define VNELPOC_REG     0x20    /* Video n End Line Post-Clip Register */
  38#define VNSPPOC_REG     0x24    /* Video n Start Pixel Post-Clip Register */
  39#define VNEPPOC_REG     0x28    /* Video n End Pixel Post-Clip Register */
  40#define VNIS_REG        0x2C    /* Video n Image Stride Register */
  41#define VNMB_REG(m)     (0x30 + ((m) << 2)) /* Video n Memory Base m Register */
  42#define VNIE_REG        0x40    /* Video n Interrupt Enable Register */
  43#define VNINTS_REG      0x44    /* Video n Interrupt Status Register */
  44#define VNSI_REG        0x48    /* Video n Scanline Interrupt Register */
  45#define VNMTC_REG       0x4C    /* Video n Memory Transfer Control Register */
  46#define VNYS_REG        0x50    /* Video n Y Scale Register */
  47#define VNXS_REG        0x54    /* Video n X Scale Register */
  48#define VNDMR_REG       0x58    /* Video n Data Mode Register */
  49#define VNDMR2_REG      0x5C    /* Video n Data Mode Register 2 */
  50#define VNUVAOF_REG     0x60    /* Video n UV Address Offset Register */
  51#define VNC1A_REG       0x80    /* Video n Coefficient Set C1A Register */
  52#define VNC1B_REG       0x84    /* Video n Coefficient Set C1B Register */
  53#define VNC1C_REG       0x88    /* Video n Coefficient Set C1C Register */
  54#define VNC2A_REG       0x90    /* Video n Coefficient Set C2A Register */
  55#define VNC2B_REG       0x94    /* Video n Coefficient Set C2B Register */
  56#define VNC2C_REG       0x98    /* Video n Coefficient Set C2C Register */
  57#define VNC3A_REG       0xA0    /* Video n Coefficient Set C3A Register */
  58#define VNC3B_REG       0xA4    /* Video n Coefficient Set C3B Register */
  59#define VNC3C_REG       0xA8    /* Video n Coefficient Set C3C Register */
  60#define VNC4A_REG       0xB0    /* Video n Coefficient Set C4A Register */
  61#define VNC4B_REG       0xB4    /* Video n Coefficient Set C4B Register */
  62#define VNC4C_REG       0xB8    /* Video n Coefficient Set C4C Register */
  63#define VNC5A_REG       0xC0    /* Video n Coefficient Set C5A Register */
  64#define VNC5B_REG       0xC4    /* Video n Coefficient Set C5B Register */
  65#define VNC5C_REG       0xC8    /* Video n Coefficient Set C5C Register */
  66#define VNC6A_REG       0xD0    /* Video n Coefficient Set C6A Register */
  67#define VNC6B_REG       0xD4    /* Video n Coefficient Set C6B Register */
  68#define VNC6C_REG       0xD8    /* Video n Coefficient Set C6C Register */
  69#define VNC7A_REG       0xE0    /* Video n Coefficient Set C7A Register */
  70#define VNC7B_REG       0xE4    /* Video n Coefficient Set C7B Register */
  71#define VNC7C_REG       0xE8    /* Video n Coefficient Set C7C Register */
  72#define VNC8A_REG       0xF0    /* Video n Coefficient Set C8A Register */
  73#define VNC8B_REG       0xF4    /* Video n Coefficient Set C8B Register */
  74#define VNC8C_REG       0xF8    /* Video n Coefficient Set C8C Register */
  75
  76
  77/* Register bit fields for R-Car VIN */
  78/* Video n Main Control Register bits */
  79#define VNMC_FOC                (1 << 21)
  80#define VNMC_YCAL               (1 << 19)
  81#define VNMC_INF_YUV8_BT656     (0 << 16)
  82#define VNMC_INF_YUV8_BT601     (1 << 16)
  83#define VNMC_INF_YUV10_BT656    (2 << 16)
  84#define VNMC_INF_YUV10_BT601    (3 << 16)
  85#define VNMC_INF_YUV16          (5 << 16)
  86#define VNMC_INF_RGB888         (6 << 16)
  87#define VNMC_VUP                (1 << 10)
  88#define VNMC_IM_ODD             (0 << 3)
  89#define VNMC_IM_ODD_EVEN        (1 << 3)
  90#define VNMC_IM_EVEN            (2 << 3)
  91#define VNMC_IM_FULL            (3 << 3)
  92#define VNMC_BPS                (1 << 1)
  93#define VNMC_ME                 (1 << 0)
  94
  95/* Video n Module Status Register bits */
  96#define VNMS_FBS_MASK           (3 << 3)
  97#define VNMS_FBS_SHIFT          3
  98#define VNMS_FS                 (1 << 2)
  99#define VNMS_AV                 (1 << 1)
 100#define VNMS_CA                 (1 << 0)
 101
 102/* Video n Frame Capture Register bits */
 103#define VNFC_C_FRAME            (1 << 1)
 104#define VNFC_S_FRAME            (1 << 0)
 105
 106/* Video n Interrupt Enable Register bits */
 107#define VNIE_FIE                (1 << 4)
 108#define VNIE_EFE                (1 << 1)
 109
 110/* Video n Data Mode Register bits */
 111#define VNDMR_EXRGB             (1 << 8)
 112#define VNDMR_BPSM              (1 << 4)
 113#define VNDMR_DTMD_YCSEP        (1 << 1)
 114#define VNDMR_DTMD_ARGB1555     (1 << 0)
 115
 116/* Video n Data Mode Register 2 bits */
 117#define VNDMR2_VPS              (1 << 30)
 118#define VNDMR2_HPS              (1 << 29)
 119#define VNDMR2_FTEV             (1 << 17)
 120#define VNDMR2_VLV(n)           ((n & 0xf) << 12)
 121
 122static void rvin_write(struct rvin_dev *vin, u32 value, u32 offset)
 123{
 124        iowrite32(value, vin->base + offset);
 125}
 126
 127static u32 rvin_read(struct rvin_dev *vin, u32 offset)
 128{
 129        return ioread32(vin->base + offset);
 130}
 131
 132static int rvin_setup(struct rvin_dev *vin)
 133{
 134        u32 vnmc, dmr, dmr2, interrupts;
 135        v4l2_std_id std;
 136        bool progressive = false, output_is_yuv = false, input_is_yuv = false;
 137
 138        switch (vin->format.field) {
 139        case V4L2_FIELD_TOP:
 140                vnmc = VNMC_IM_ODD;
 141                break;
 142        case V4L2_FIELD_BOTTOM:
 143                vnmc = VNMC_IM_EVEN;
 144                break;
 145        case V4L2_FIELD_INTERLACED:
 146                /* Default to TB */
 147                vnmc = VNMC_IM_FULL;
 148                /* Use BT if video standard can be read and is 60 Hz format */
 149                if (!v4l2_subdev_call(vin_to_source(vin), video, g_std, &std)) {
 150                        if (std & V4L2_STD_525_60)
 151                                vnmc = VNMC_IM_FULL | VNMC_FOC;
 152                }
 153                break;
 154        case V4L2_FIELD_INTERLACED_TB:
 155                vnmc = VNMC_IM_FULL;
 156                break;
 157        case V4L2_FIELD_INTERLACED_BT:
 158                vnmc = VNMC_IM_FULL | VNMC_FOC;
 159                break;
 160        case V4L2_FIELD_ALTERNATE:
 161        case V4L2_FIELD_NONE:
 162                if (vin->continuous) {
 163                        vnmc = VNMC_IM_ODD_EVEN;
 164                        progressive = true;
 165                } else {
 166                        vnmc = VNMC_IM_ODD;
 167                }
 168                break;
 169        default:
 170                vnmc = VNMC_IM_ODD;
 171                break;
 172        }
 173
 174        /*
 175         * Input interface
 176         */
 177        switch (vin->digital.code) {
 178        case MEDIA_BUS_FMT_YUYV8_1X16:
 179                /* BT.601/BT.1358 16bit YCbCr422 */
 180                vnmc |= VNMC_INF_YUV16;
 181                input_is_yuv = true;
 182                break;
 183        case MEDIA_BUS_FMT_UYVY8_2X8:
 184                /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */
 185                vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ?
 186                        VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601;
 187                input_is_yuv = true;
 188                break;
 189        case MEDIA_BUS_FMT_RGB888_1X24:
 190                vnmc |= VNMC_INF_RGB888;
 191                break;
 192        case MEDIA_BUS_FMT_UYVY10_2X10:
 193                /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */
 194                vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ?
 195                        VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601;
 196                input_is_yuv = true;
 197                break;
 198        default:
 199                break;
 200        }
 201
 202        /* Enable VSYNC Field Toogle mode after one VSYNC input */
 203        dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1);
 204
 205        /* Hsync Signal Polarity Select */
 206        if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
 207                dmr2 |= VNDMR2_HPS;
 208
 209        /* Vsync Signal Polarity Select */
 210        if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
 211                dmr2 |= VNDMR2_VPS;
 212
 213        /*
 214         * Output format
 215         */
 216        switch (vin->format.pixelformat) {
 217        case V4L2_PIX_FMT_NV16:
 218                rvin_write(vin,
 219                           ALIGN(vin->format.width * vin->format.height, 0x80),
 220                           VNUVAOF_REG);
 221                dmr = VNDMR_DTMD_YCSEP;
 222                output_is_yuv = true;
 223                break;
 224        case V4L2_PIX_FMT_YUYV:
 225                dmr = VNDMR_BPSM;
 226                output_is_yuv = true;
 227                break;
 228        case V4L2_PIX_FMT_UYVY:
 229                dmr = 0;
 230                output_is_yuv = true;
 231                break;
 232        case V4L2_PIX_FMT_XRGB555:
 233                dmr = VNDMR_DTMD_ARGB1555;
 234                break;
 235        case V4L2_PIX_FMT_RGB565:
 236                dmr = 0;
 237                break;
 238        case V4L2_PIX_FMT_XBGR32:
 239                /* Note: not supported on M1 */
 240                dmr = VNDMR_EXRGB;
 241                break;
 242        default:
 243                vin_err(vin, "Invalid pixelformat (0x%x)\n",
 244                        vin->format.pixelformat);
 245                return -EINVAL;
 246        }
 247
 248        /* Always update on field change */
 249        vnmc |= VNMC_VUP;
 250
 251        /* If input and output use the same colorspace, use bypass mode */
 252        if (input_is_yuv == output_is_yuv)
 253                vnmc |= VNMC_BPS;
 254
 255        /* Progressive or interlaced mode */
 256        interrupts = progressive ? VNIE_FIE : VNIE_EFE;
 257
 258        /* Ack interrupts */
 259        rvin_write(vin, interrupts, VNINTS_REG);
 260        /* Enable interrupts */
 261        rvin_write(vin, interrupts, VNIE_REG);
 262        /* Start capturing */
 263        rvin_write(vin, dmr, VNDMR_REG);
 264        rvin_write(vin, dmr2, VNDMR2_REG);
 265
 266        /* Enable module */
 267        rvin_write(vin, vnmc | VNMC_ME, VNMC_REG);
 268
 269        return 0;
 270}
 271
 272static void rvin_capture_on(struct rvin_dev *vin)
 273{
 274        vin_dbg(vin, "Capture on in %s mode\n",
 275                vin->continuous ? "continuous" : "single");
 276
 277        if (vin->continuous)
 278                /* Continuous Frame Capture Mode */
 279                rvin_write(vin, VNFC_C_FRAME, VNFC_REG);
 280        else
 281                /* Single Frame Capture Mode */
 282                rvin_write(vin, VNFC_S_FRAME, VNFC_REG);
 283}
 284
 285static void rvin_capture_off(struct rvin_dev *vin)
 286{
 287        /* Set continuous & single transfer off */
 288        rvin_write(vin, 0, VNFC_REG);
 289}
 290
 291static int rvin_capture_start(struct rvin_dev *vin)
 292{
 293        int ret;
 294
 295        rvin_crop_scale_comp(vin);
 296
 297        ret = rvin_setup(vin);
 298        if (ret)
 299                return ret;
 300
 301        rvin_capture_on(vin);
 302
 303        return 0;
 304}
 305
 306static void rvin_capture_stop(struct rvin_dev *vin)
 307{
 308        rvin_capture_off(vin);
 309
 310        /* Disable module */
 311        rvin_write(vin, rvin_read(vin, VNMC_REG) & ~VNMC_ME, VNMC_REG);
 312}
 313
 314static void rvin_disable_interrupts(struct rvin_dev *vin)
 315{
 316        rvin_write(vin, 0, VNIE_REG);
 317}
 318
 319static u32 rvin_get_interrupt_status(struct rvin_dev *vin)
 320{
 321        return rvin_read(vin, VNINTS_REG);
 322}
 323
 324static void rvin_ack_interrupt(struct rvin_dev *vin)
 325{
 326        rvin_write(vin, rvin_read(vin, VNINTS_REG), VNINTS_REG);
 327}
 328
 329static bool rvin_capture_active(struct rvin_dev *vin)
 330{
 331        return rvin_read(vin, VNMS_REG) & VNMS_CA;
 332}
 333
 334static int rvin_get_active_slot(struct rvin_dev *vin, u32 vnms)
 335{
 336        if (vin->continuous)
 337                return (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT;
 338
 339        return 0;
 340}
 341
 342static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms)
 343{
 344        if (vin->format.field == V4L2_FIELD_ALTERNATE) {
 345                /* If FS is set it's a Even field */
 346                if (vnms & VNMS_FS)
 347                        return V4L2_FIELD_BOTTOM;
 348                return V4L2_FIELD_TOP;
 349        }
 350
 351        return vin->format.field;
 352}
 353
 354static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr)
 355{
 356        const struct rvin_video_format *fmt;
 357        int offsetx, offsety;
 358        dma_addr_t offset;
 359
 360        fmt = rvin_format_from_pixel(vin->format.pixelformat);
 361
 362        /*
 363         * There is no HW support for composition do the beast we can
 364         * by modifying the buffer offset
 365         */
 366        offsetx = vin->compose.left * fmt->bpp;
 367        offsety = vin->compose.top * vin->format.bytesperline;
 368        offset = addr + offsetx + offsety;
 369
 370        /*
 371         * The address needs to be 128 bytes aligned. Driver should never accept
 372         * settings that do not satisfy this in the first place...
 373         */
 374        if (WARN_ON((offsetx | offsety | offset) & HW_BUFFER_MASK))
 375                return;
 376
 377        rvin_write(vin, offset, VNMB_REG(slot));
 378}
 379
 380/* -----------------------------------------------------------------------------
 381 * Crop and Scaling Gen2
 382 */
 383
 384struct vin_coeff {
 385        unsigned short xs_value;
 386        u32 coeff_set[24];
 387};
 388
 389static const struct vin_coeff vin_coeff_set[] = {
 390        { 0x0000, {
 391                          0x00000000, 0x00000000, 0x00000000,
 392                          0x00000000, 0x00000000, 0x00000000,
 393                          0x00000000, 0x00000000, 0x00000000,
 394                          0x00000000, 0x00000000, 0x00000000,
 395                          0x00000000, 0x00000000, 0x00000000,
 396                          0x00000000, 0x00000000, 0x00000000,
 397                          0x00000000, 0x00000000, 0x00000000,
 398                          0x00000000, 0x00000000, 0x00000000 },
 399        },
 400        { 0x1000, {
 401                          0x000fa400, 0x000fa400, 0x09625902,
 402                          0x000003f8, 0x00000403, 0x3de0d9f0,
 403                          0x001fffed, 0x00000804, 0x3cc1f9c3,
 404                          0x001003de, 0x00000c01, 0x3cb34d7f,
 405                          0x002003d2, 0x00000c00, 0x3d24a92d,
 406                          0x00200bca, 0x00000bff, 0x3df600d2,
 407                          0x002013cc, 0x000007ff, 0x3ed70c7e,
 408                          0x00100fde, 0x00000000, 0x3f87c036 },
 409        },
 410        { 0x1200, {
 411                          0x002ffff1, 0x002ffff1, 0x02a0a9c8,
 412                          0x002003e7, 0x001ffffa, 0x000185bc,
 413                          0x002007dc, 0x000003ff, 0x3e52859c,
 414                          0x00200bd4, 0x00000002, 0x3d53996b,
 415                          0x00100fd0, 0x00000403, 0x3d04ad2d,
 416                          0x00000bd5, 0x00000403, 0x3d35ace7,
 417                          0x3ff003e4, 0x00000801, 0x3dc674a1,
 418                          0x3fffe800, 0x00000800, 0x3e76f461 },
 419        },
 420        { 0x1400, {
 421                          0x00100be3, 0x00100be3, 0x04d1359a,
 422                          0x00000fdb, 0x002003ed, 0x0211fd93,
 423                          0x00000fd6, 0x002003f4, 0x0002d97b,
 424                          0x000007d6, 0x002ffffb, 0x3e93b956,
 425                          0x3ff003da, 0x001003ff, 0x3db49926,
 426                          0x3fffefe9, 0x00100001, 0x3d655cee,
 427                          0x3fffd400, 0x00000003, 0x3d65f4b6,
 428                          0x000fb421, 0x00000402, 0x3dc6547e },
 429        },
 430        { 0x1600, {
 431                          0x00000bdd, 0x00000bdd, 0x06519578,
 432                          0x3ff007da, 0x00000be3, 0x03c24973,
 433                          0x3ff003d9, 0x00000be9, 0x01b30d5f,
 434                          0x3ffff7df, 0x001003f1, 0x0003c542,
 435                          0x000fdfec, 0x001003f7, 0x3ec4711d,
 436                          0x000fc400, 0x002ffffd, 0x3df504f1,
 437                          0x001fa81a, 0x002ffc00, 0x3d957cc2,
 438                          0x002f8c3c, 0x00100000, 0x3db5c891 },
 439        },
 440        { 0x1800, {
 441                          0x3ff003dc, 0x3ff003dc, 0x0791e558,
 442                          0x000ff7dd, 0x3ff007de, 0x05328554,
 443                          0x000fe7e3, 0x3ff00be2, 0x03232546,
 444                          0x000fd7ee, 0x000007e9, 0x0143bd30,
 445                          0x001fb800, 0x000007ee, 0x00044511,
 446                          0x002fa015, 0x000007f4, 0x3ef4bcee,
 447                          0x002f8832, 0x001003f9, 0x3e4514c7,
 448                          0x001f7853, 0x001003fd, 0x3de54c9f },
 449        },
 450        { 0x1a00, {
 451                          0x000fefe0, 0x000fefe0, 0x08721d3c,
 452                          0x001fdbe7, 0x000ffbde, 0x0652a139,
 453                          0x001fcbf0, 0x000003df, 0x0463292e,
 454                          0x002fb3ff, 0x3ff007e3, 0x0293a91d,
 455                          0x002f9c12, 0x3ff00be7, 0x01241905,
 456                          0x001f8c29, 0x000007ed, 0x3fe470eb,
 457                          0x000f7c46, 0x000007f2, 0x3f04b8ca,
 458                          0x3fef7865, 0x000007f6, 0x3e74e4a8 },
 459        },
 460        { 0x1c00, {
 461                          0x001fd3e9, 0x001fd3e9, 0x08f23d26,
 462                          0x002fbff3, 0x001fe3e4, 0x0712ad23,
 463                          0x002fa800, 0x000ff3e0, 0x05631d1b,
 464                          0x001f9810, 0x000ffbe1, 0x03b3890d,
 465                          0x000f8c23, 0x000003e3, 0x0233e8fa,
 466                          0x3fef843b, 0x000003e7, 0x00f430e4,
 467                          0x3fbf8456, 0x3ff00bea, 0x00046cc8,
 468                          0x3f8f8c72, 0x3ff00bef, 0x3f3490ac },
 469        },
 470        { 0x1e00, {
 471                          0x001fbbf4, 0x001fbbf4, 0x09425112,
 472                          0x001fa800, 0x002fc7ed, 0x0792b110,
 473                          0x000f980e, 0x001fdbe6, 0x0613110a,
 474                          0x3fff8c20, 0x001fe7e3, 0x04a368fd,
 475                          0x3fcf8c33, 0x000ff7e2, 0x0343b8ed,
 476                          0x3f9f8c4a, 0x000fffe3, 0x0203f8da,
 477                          0x3f5f9c61, 0x000003e6, 0x00e428c5,
 478                          0x3f1fb07b, 0x000003eb, 0x3fe440af },
 479        },
 480        { 0x2000, {
 481                          0x000fa400, 0x000fa400, 0x09625902,
 482                          0x3fff980c, 0x001fb7f5, 0x0812b0ff,
 483                          0x3fdf901c, 0x001fc7ed, 0x06b2fcfa,
 484                          0x3faf902d, 0x001fd3e8, 0x055348f1,
 485                          0x3f7f983f, 0x001fe3e5, 0x04038ce3,
 486                          0x3f3fa454, 0x001fefe3, 0x02e3c8d1,
 487                          0x3f0fb86a, 0x001ff7e4, 0x01c3e8c0,
 488                          0x3ecfd880, 0x000fffe6, 0x00c404ac },
 489        },
 490        { 0x2200, {
 491                          0x3fdf9c0b, 0x3fdf9c0b, 0x09725cf4,
 492                          0x3fbf9818, 0x3fffa400, 0x0842a8f1,
 493                          0x3f8f9827, 0x000fb3f7, 0x0702f0ec,
 494                          0x3f5fa037, 0x000fc3ef, 0x05d330e4,
 495                          0x3f2fac49, 0x001fcfea, 0x04a364d9,
 496                          0x3effc05c, 0x001fdbe7, 0x038394ca,
 497                          0x3ecfdc6f, 0x001fe7e6, 0x0273b0bb,
 498                          0x3ea00083, 0x001fefe6, 0x0183c0a9 },
 499        },
 500        { 0x2400, {
 501                          0x3f9fa014, 0x3f9fa014, 0x098260e6,
 502                          0x3f7f9c23, 0x3fcf9c0a, 0x08629ce5,
 503                          0x3f4fa431, 0x3fefa400, 0x0742d8e1,
 504                          0x3f1fb440, 0x3fffb3f8, 0x062310d9,
 505                          0x3eefc850, 0x000fbbf2, 0x050340d0,
 506                          0x3ecfe062, 0x000fcbec, 0x041364c2,
 507                          0x3ea00073, 0x001fd3ea, 0x03037cb5,
 508                          0x3e902086, 0x001fdfe8, 0x022388a5 },
 509        },
 510        { 0x2600, {
 511                          0x3f5fa81e, 0x3f5fa81e, 0x096258da,
 512                          0x3f3fac2b, 0x3f8fa412, 0x088290d8,
 513                          0x3f0fbc38, 0x3fafa408, 0x0772c8d5,
 514                          0x3eefcc47, 0x3fcfa800, 0x0672f4ce,
 515                          0x3ecfe456, 0x3fefaffa, 0x05531cc6,
 516                          0x3eb00066, 0x3fffbbf3, 0x047334bb,
 517                          0x3ea01c77, 0x000fc7ee, 0x039348ae,
 518                          0x3ea04486, 0x000fd3eb, 0x02b350a1 },
 519        },
 520        { 0x2800, {
 521                          0x3f2fb426, 0x3f2fb426, 0x094250ce,
 522                          0x3f0fc032, 0x3f4fac1b, 0x086284cd,
 523                          0x3eefd040, 0x3f7fa811, 0x0782acc9,
 524                          0x3ecfe84c, 0x3f9fa807, 0x06a2d8c4,
 525                          0x3eb0005b, 0x3fbfac00, 0x05b2f4bc,
 526                          0x3eb0186a, 0x3fdfb3fa, 0x04c308b4,
 527                          0x3eb04077, 0x3fefbbf4, 0x03f31ca8,
 528                          0x3ec06884, 0x000fbff2, 0x03031c9e },
 529        },
 530        { 0x2a00, {
 531                          0x3f0fc42d, 0x3f0fc42d, 0x090240c4,
 532                          0x3eefd439, 0x3f2fb822, 0x08526cc2,
 533                          0x3edfe845, 0x3f4fb018, 0x078294bf,
 534                          0x3ec00051, 0x3f6fac0f, 0x06b2b4bb,
 535                          0x3ec0185f, 0x3f8fac07, 0x05e2ccb4,
 536                          0x3ec0386b, 0x3fafac00, 0x0502e8ac,
 537                          0x3ed05c77, 0x3fcfb3fb, 0x0432f0a3,
 538                          0x3ef08482, 0x3fdfbbf6, 0x0372f898 },
 539        },
 540        { 0x2c00, {
 541                          0x3eefdc31, 0x3eefdc31, 0x08e238b8,
 542                          0x3edfec3d, 0x3f0fc828, 0x082258b9,
 543                          0x3ed00049, 0x3f1fc01e, 0x077278b6,
 544                          0x3ed01455, 0x3f3fb815, 0x06c294b2,
 545                          0x3ed03460, 0x3f5fb40d, 0x0602acac,
 546                          0x3ef0506c, 0x3f7fb006, 0x0542c0a4,
 547                          0x3f107476, 0x3f9fb400, 0x0472c89d,
 548                          0x3f309c80, 0x3fbfb7fc, 0x03b2cc94 },
 549        },
 550        { 0x2e00, {
 551                          0x3eefec37, 0x3eefec37, 0x088220b0,
 552                          0x3ee00041, 0x3effdc2d, 0x07f244ae,
 553                          0x3ee0144c, 0x3f0fd023, 0x07625cad,
 554                          0x3ef02c57, 0x3f1fc81a, 0x06c274a9,
 555                          0x3f004861, 0x3f3fbc13, 0x060288a6,
 556                          0x3f20686b, 0x3f5fb80c, 0x05529c9e,
 557                          0x3f408c74, 0x3f6fb805, 0x04b2ac96,
 558                          0x3f80ac7e, 0x3f8fb800, 0x0402ac8e },
 559        },
 560        { 0x3000, {
 561                          0x3ef0003a, 0x3ef0003a, 0x084210a6,
 562                          0x3ef01045, 0x3effec32, 0x07b228a7,
 563                          0x3f00284e, 0x3f0fdc29, 0x073244a4,
 564                          0x3f104058, 0x3f0fd420, 0x06a258a2,
 565                          0x3f305c62, 0x3f2fc818, 0x0612689d,
 566                          0x3f508069, 0x3f3fc011, 0x05728496,
 567                          0x3f80a072, 0x3f4fc00a, 0x04d28c90,
 568                          0x3fc0c07b, 0x3f6fbc04, 0x04429088 },
 569        },
 570        { 0x3200, {
 571                          0x3f00103e, 0x3f00103e, 0x07f1fc9e,
 572                          0x3f102447, 0x3f000035, 0x0782149d,
 573                          0x3f203c4f, 0x3f0ff02c, 0x07122c9c,
 574                          0x3f405458, 0x3f0fe424, 0x06924099,
 575                          0x3f607061, 0x3f1fd41d, 0x06024c97,
 576                          0x3f909068, 0x3f2fcc16, 0x05726490,
 577                          0x3fc0b070, 0x3f3fc80f, 0x04f26c8a,
 578                          0x0000d077, 0x3f4fc409, 0x04627484 },
 579        },
 580        { 0x3400, {
 581                          0x3f202040, 0x3f202040, 0x07a1e898,
 582                          0x3f303449, 0x3f100c38, 0x0741fc98,
 583                          0x3f504c50, 0x3f10002f, 0x06e21495,
 584                          0x3f706459, 0x3f1ff028, 0x06722492,
 585                          0x3fa08060, 0x3f1fe421, 0x05f2348f,
 586                          0x3fd09c67, 0x3f1fdc19, 0x05824c89,
 587                          0x0000bc6e, 0x3f2fd014, 0x04f25086,
 588                          0x0040dc74, 0x3f3fcc0d, 0x04825c7f },
 589        },
 590        { 0x3600, {
 591                          0x3f403042, 0x3f403042, 0x0761d890,
 592                          0x3f504848, 0x3f301c3b, 0x0701f090,
 593                          0x3f805c50, 0x3f200c33, 0x06a2008f,
 594                          0x3fa07458, 0x3f10002b, 0x06520c8d,
 595                          0x3fd0905e, 0x3f1ff424, 0x05e22089,
 596                          0x0000ac65, 0x3f1fe81d, 0x05823483,
 597                          0x0030cc6a, 0x3f2fdc18, 0x04f23c81,
 598                          0x0080e871, 0x3f2fd412, 0x0482407c },
 599        },
 600        { 0x3800, {
 601                          0x3f604043, 0x3f604043, 0x0721c88a,
 602                          0x3f80544a, 0x3f502c3c, 0x06d1d88a,
 603                          0x3fb06851, 0x3f301c35, 0x0681e889,
 604                          0x3fd08456, 0x3f30082f, 0x0611fc88,
 605                          0x00009c5d, 0x3f200027, 0x05d20884,
 606                          0x0030b863, 0x3f2ff421, 0x05621880,
 607                          0x0070d468, 0x3f2fe81b, 0x0502247c,
 608                          0x00c0ec6f, 0x3f2fe015, 0x04a22877 },
 609        },
 610        { 0x3a00, {
 611                          0x3f904c44, 0x3f904c44, 0x06e1b884,
 612                          0x3fb0604a, 0x3f70383e, 0x0691c885,
 613                          0x3fe07451, 0x3f502c36, 0x0661d483,
 614                          0x00009055, 0x3f401831, 0x0601ec81,
 615                          0x0030a85b, 0x3f300c2a, 0x05b1f480,
 616                          0x0070c061, 0x3f300024, 0x0562047a,
 617                          0x00b0d867, 0x3f3ff41e, 0x05020c77,
 618                          0x00f0f46b, 0x3f2fec19, 0x04a21474 },
 619        },
 620        { 0x3c00, {
 621                          0x3fb05c43, 0x3fb05c43, 0x06c1b07e,
 622                          0x3fe06c4b, 0x3f902c3f, 0x0681c081,
 623                          0x0000844f, 0x3f703838, 0x0631cc7d,
 624                          0x00309855, 0x3f602433, 0x05d1d47e,
 625                          0x0060b459, 0x3f50142e, 0x0581e47b,
 626                          0x00a0c85f, 0x3f400828, 0x0531f078,
 627                          0x00e0e064, 0x3f300021, 0x0501fc73,
 628                          0x00b0fc6a, 0x3f3ff41d, 0x04a20873 },
 629        },
 630        { 0x3e00, {
 631                          0x3fe06444, 0x3fe06444, 0x0681a07a,
 632                          0x00007849, 0x3fc0503f, 0x0641b07a,
 633                          0x0020904d, 0x3fa0403a, 0x05f1c07a,
 634                          0x0060a453, 0x3f803034, 0x05c1c878,
 635                          0x0090b858, 0x3f70202f, 0x0571d477,
 636                          0x00d0d05d, 0x3f501829, 0x0531e073,
 637                          0x0110e462, 0x3f500825, 0x04e1e471,
 638                          0x01510065, 0x3f40001f, 0x04a1f06d },
 639        },
 640        { 0x4000, {
 641                          0x00007044, 0x00007044, 0x06519476,
 642                          0x00208448, 0x3fe05c3f, 0x0621a476,
 643                          0x0050984d, 0x3fc04c3a, 0x05e1b075,
 644                          0x0080ac52, 0x3fa03c35, 0x05a1b875,
 645                          0x00c0c056, 0x3f803030, 0x0561c473,
 646                          0x0100d45b, 0x3f70202b, 0x0521d46f,
 647                          0x0140e860, 0x3f601427, 0x04d1d46e,
 648                          0x01810064, 0x3f500822, 0x0491dc6b },
 649        },
 650        { 0x5000, {
 651                          0x0110a442, 0x0110a442, 0x0551545e,
 652                          0x0140b045, 0x00e0983f, 0x0531585f,
 653                          0x0160c047, 0x00c08c3c, 0x0511645e,
 654                          0x0190cc4a, 0x00908039, 0x04f1685f,
 655                          0x01c0dc4c, 0x00707436, 0x04d1705e,
 656                          0x0200e850, 0x00506833, 0x04b1785b,
 657                          0x0230f453, 0x00305c30, 0x0491805a,
 658                          0x02710056, 0x0010542d, 0x04718059 },
 659        },
 660        { 0x6000, {
 661                          0x01c0bc40, 0x01c0bc40, 0x04c13052,
 662                          0x01e0c841, 0x01a0b43d, 0x04c13851,
 663                          0x0210cc44, 0x0180a83c, 0x04a13453,
 664                          0x0230d845, 0x0160a03a, 0x04913c52,
 665                          0x0260e047, 0x01409838, 0x04714052,
 666                          0x0280ec49, 0x01208c37, 0x04514c50,
 667                          0x02b0f44b, 0x01008435, 0x04414c50,
 668                          0x02d1004c, 0x00e07c33, 0x0431544f },
 669        },
 670        { 0x7000, {
 671                          0x0230c83e, 0x0230c83e, 0x04711c4c,
 672                          0x0250d03f, 0x0210c43c, 0x0471204b,
 673                          0x0270d840, 0x0200b83c, 0x0451244b,
 674                          0x0290dc42, 0x01e0b43a, 0x0441244c,
 675                          0x02b0e443, 0x01c0b038, 0x0441284b,
 676                          0x02d0ec44, 0x01b0a438, 0x0421304a,
 677                          0x02f0f445, 0x0190a036, 0x04213449,
 678                          0x0310f847, 0x01709c34, 0x04213848 },
 679        },
 680        { 0x8000, {
 681                          0x0280d03d, 0x0280d03d, 0x04310c48,
 682                          0x02a0d43e, 0x0270c83c, 0x04311047,
 683                          0x02b0dc3e, 0x0250c83a, 0x04311447,
 684                          0x02d0e040, 0x0240c03a, 0x04211446,
 685                          0x02e0e840, 0x0220bc39, 0x04111847,
 686                          0x0300e842, 0x0210b438, 0x04012445,
 687                          0x0310f043, 0x0200b037, 0x04012045,
 688                          0x0330f444, 0x01e0ac36, 0x03f12445 },
 689        },
 690        { 0xefff, {
 691                          0x0340dc3a, 0x0340dc3a, 0x03b0ec40,
 692                          0x0340e03a, 0x0330e039, 0x03c0f03e,
 693                          0x0350e03b, 0x0330dc39, 0x03c0ec3e,
 694                          0x0350e43a, 0x0320dc38, 0x03c0f43e,
 695                          0x0360e43b, 0x0320d839, 0x03b0f03e,
 696                          0x0360e83b, 0x0310d838, 0x03c0fc3b,
 697                          0x0370e83b, 0x0310d439, 0x03a0f83d,
 698                          0x0370e83c, 0x0300d438, 0x03b0fc3c },
 699        }
 700};
 701
 702static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs)
 703{
 704        int i;
 705        const struct vin_coeff *p_prev_set = NULL;
 706        const struct vin_coeff *p_set = NULL;
 707
 708        /* Look for suitable coefficient values */
 709        for (i = 0; i < ARRAY_SIZE(vin_coeff_set); i++) {
 710                p_prev_set = p_set;
 711                p_set = &vin_coeff_set[i];
 712
 713                if (xs < p_set->xs_value)
 714                        break;
 715        }
 716
 717        /* Use previous value if its XS value is closer */
 718        if (p_prev_set && p_set &&
 719            xs - p_prev_set->xs_value < p_set->xs_value - xs)
 720                p_set = p_prev_set;
 721
 722        /* Set coefficient registers */
 723        rvin_write(vin, p_set->coeff_set[0], VNC1A_REG);
 724        rvin_write(vin, p_set->coeff_set[1], VNC1B_REG);
 725        rvin_write(vin, p_set->coeff_set[2], VNC1C_REG);
 726
 727        rvin_write(vin, p_set->coeff_set[3], VNC2A_REG);
 728        rvin_write(vin, p_set->coeff_set[4], VNC2B_REG);
 729        rvin_write(vin, p_set->coeff_set[5], VNC2C_REG);
 730
 731        rvin_write(vin, p_set->coeff_set[6], VNC3A_REG);
 732        rvin_write(vin, p_set->coeff_set[7], VNC3B_REG);
 733        rvin_write(vin, p_set->coeff_set[8], VNC3C_REG);
 734
 735        rvin_write(vin, p_set->coeff_set[9], VNC4A_REG);
 736        rvin_write(vin, p_set->coeff_set[10], VNC4B_REG);
 737        rvin_write(vin, p_set->coeff_set[11], VNC4C_REG);
 738
 739        rvin_write(vin, p_set->coeff_set[12], VNC5A_REG);
 740        rvin_write(vin, p_set->coeff_set[13], VNC5B_REG);
 741        rvin_write(vin, p_set->coeff_set[14], VNC5C_REG);
 742
 743        rvin_write(vin, p_set->coeff_set[15], VNC6A_REG);
 744        rvin_write(vin, p_set->coeff_set[16], VNC6B_REG);
 745        rvin_write(vin, p_set->coeff_set[17], VNC6C_REG);
 746
 747        rvin_write(vin, p_set->coeff_set[18], VNC7A_REG);
 748        rvin_write(vin, p_set->coeff_set[19], VNC7B_REG);
 749        rvin_write(vin, p_set->coeff_set[20], VNC7C_REG);
 750
 751        rvin_write(vin, p_set->coeff_set[21], VNC8A_REG);
 752        rvin_write(vin, p_set->coeff_set[22], VNC8B_REG);
 753        rvin_write(vin, p_set->coeff_set[23], VNC8C_REG);
 754}
 755
 756void rvin_crop_scale_comp(struct rvin_dev *vin)
 757{
 758        u32 xs, ys;
 759
 760        /* Set Start/End Pixel/Line Pre-Clip */
 761        rvin_write(vin, vin->crop.left, VNSPPRC_REG);
 762        rvin_write(vin, vin->crop.left + vin->crop.width - 1, VNEPPRC_REG);
 763        switch (vin->format.field) {
 764        case V4L2_FIELD_INTERLACED:
 765        case V4L2_FIELD_INTERLACED_TB:
 766        case V4L2_FIELD_INTERLACED_BT:
 767                rvin_write(vin, vin->crop.top / 2, VNSLPRC_REG);
 768                rvin_write(vin, (vin->crop.top + vin->crop.height) / 2 - 1,
 769                           VNELPRC_REG);
 770                break;
 771        default:
 772                rvin_write(vin, vin->crop.top, VNSLPRC_REG);
 773                rvin_write(vin, vin->crop.top + vin->crop.height - 1,
 774                           VNELPRC_REG);
 775                break;
 776        }
 777
 778        /* Set scaling coefficient */
 779        ys = 0;
 780        if (vin->crop.height != vin->compose.height)
 781                ys = (4096 * vin->crop.height) / vin->compose.height;
 782        rvin_write(vin, ys, VNYS_REG);
 783
 784        xs = 0;
 785        if (vin->crop.width != vin->compose.width)
 786                xs = (4096 * vin->crop.width) / vin->compose.width;
 787
 788        /* Horizontal upscaling is up to double size */
 789        if (xs > 0 && xs < 2048)
 790                xs = 2048;
 791
 792        rvin_write(vin, xs, VNXS_REG);
 793
 794        /* Horizontal upscaling is done out by scaling down from double size */
 795        if (xs < 4096)
 796                xs *= 2;
 797
 798        rvin_set_coeff(vin, xs);
 799
 800        /* Set Start/End Pixel/Line Post-Clip */
 801        rvin_write(vin, 0, VNSPPOC_REG);
 802        rvin_write(vin, 0, VNSLPOC_REG);
 803        rvin_write(vin, vin->format.width - 1, VNEPPOC_REG);
 804        switch (vin->format.field) {
 805        case V4L2_FIELD_INTERLACED:
 806        case V4L2_FIELD_INTERLACED_TB:
 807        case V4L2_FIELD_INTERLACED_BT:
 808                rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG);
 809                break;
 810        default:
 811                rvin_write(vin, vin->format.height - 1, VNELPOC_REG);
 812                break;
 813        }
 814
 815        if (vin->format.pixelformat == V4L2_PIX_FMT_NV16)
 816                rvin_write(vin, ALIGN(vin->format.width, 0x20), VNIS_REG);
 817        else
 818                rvin_write(vin, ALIGN(vin->format.width, 0x10), VNIS_REG);
 819
 820        vin_dbg(vin,
 821                "Pre-Clip: %ux%u@%u:%u YS: %d XS: %d Post-Clip: %ux%u@%u:%u\n",
 822                vin->crop.width, vin->crop.height, vin->crop.left,
 823                vin->crop.top, ys, xs, vin->format.width, vin->format.height,
 824                0, 0);
 825}
 826
 827void rvin_scale_try(struct rvin_dev *vin, struct v4l2_pix_format *pix,
 828                    u32 width, u32 height)
 829{
 830        /* All VIN channels on Gen2 have scalers */
 831        pix->width = width;
 832        pix->height = height;
 833}
 834
 835/* -----------------------------------------------------------------------------
 836 * DMA Functions
 837 */
 838
 839#define RVIN_TIMEOUT_MS 100
 840#define RVIN_RETRIES 10
 841
 842struct rvin_buffer {
 843        struct vb2_v4l2_buffer vb;
 844        struct list_head list;
 845};
 846
 847#define to_buf_list(vb2_buffer) (&container_of(vb2_buffer, \
 848                                               struct rvin_buffer, \
 849                                               vb)->list)
 850
 851/* Moves a buffer from the queue to the HW slots */
 852static bool rvin_fill_hw_slot(struct rvin_dev *vin, int slot)
 853{
 854        struct rvin_buffer *buf;
 855        struct vb2_v4l2_buffer *vbuf;
 856        dma_addr_t phys_addr_top;
 857
 858        if (vin->queue_buf[slot] != NULL)
 859                return true;
 860
 861        if (list_empty(&vin->buf_list))
 862                return false;
 863
 864        vin_dbg(vin, "Filling HW slot: %d\n", slot);
 865
 866        /* Keep track of buffer we give to HW */
 867        buf = list_entry(vin->buf_list.next, struct rvin_buffer, list);
 868        vbuf = &buf->vb;
 869        list_del_init(to_buf_list(vbuf));
 870        vin->queue_buf[slot] = vbuf;
 871
 872        /* Setup DMA */
 873        phys_addr_top = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
 874        rvin_set_slot_addr(vin, slot, phys_addr_top);
 875
 876        return true;
 877}
 878
 879static bool rvin_fill_hw(struct rvin_dev *vin)
 880{
 881        int slot, limit;
 882
 883        limit = vin->continuous ? HW_BUFFER_NUM : 1;
 884
 885        for (slot = 0; slot < limit; slot++)
 886                if (!rvin_fill_hw_slot(vin, slot))
 887                        return false;
 888        return true;
 889}
 890
 891static irqreturn_t rvin_irq(int irq, void *data)
 892{
 893        struct rvin_dev *vin = data;
 894        u32 int_status, vnms;
 895        int slot;
 896        unsigned int sequence, handled = 0;
 897        unsigned long flags;
 898
 899        spin_lock_irqsave(&vin->qlock, flags);
 900
 901        int_status = rvin_get_interrupt_status(vin);
 902        if (!int_status)
 903                goto done;
 904
 905        rvin_ack_interrupt(vin);
 906        handled = 1;
 907
 908        /* Nothing to do if capture status is 'STOPPED' */
 909        if (vin->state == STOPPED) {
 910                vin_dbg(vin, "IRQ while state stopped\n");
 911                goto done;
 912        }
 913
 914        /* Nothing to do if capture status is 'STOPPING' */
 915        if (vin->state == STOPPING) {
 916                vin_dbg(vin, "IRQ while state stopping\n");
 917                goto done;
 918        }
 919
 920        /* Prepare for capture and update state */
 921        vnms = rvin_read(vin, VNMS_REG);
 922        slot = rvin_get_active_slot(vin, vnms);
 923        sequence = vin->sequence++;
 924
 925        vin_dbg(vin, "IRQ %02d: %d\tbuf0: %c buf1: %c buf2: %c\tmore: %d\n",
 926                sequence, slot,
 927                slot == 0 ? 'x' : vin->queue_buf[0] != NULL ? '1' : '0',
 928                slot == 1 ? 'x' : vin->queue_buf[1] != NULL ? '1' : '0',
 929                slot == 2 ? 'x' : vin->queue_buf[2] != NULL ? '1' : '0',
 930                !list_empty(&vin->buf_list));
 931
 932        /* HW have written to a slot that is not prepared we are in trouble */
 933        if (WARN_ON((vin->queue_buf[slot] == NULL)))
 934                goto done;
 935
 936        /* Capture frame */
 937        vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms);
 938        vin->queue_buf[slot]->sequence = sequence;
 939        vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
 940        vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, VB2_BUF_STATE_DONE);
 941        vin->queue_buf[slot] = NULL;
 942
 943        /* Prepare for next frame */
 944        if (!rvin_fill_hw(vin)) {
 945
 946                /*
 947                 * Can't supply HW with new buffers fast enough. Halt
 948                 * capture until more buffers are available.
 949                 */
 950                vin->state = STALLED;
 951
 952                /*
 953                 * The continuous capturing requires an explicit stop
 954                 * operation when there is no buffer to be set into
 955                 * the VnMBm registers.
 956                 */
 957                if (vin->continuous) {
 958                        rvin_capture_off(vin);
 959                        vin_dbg(vin, "IRQ %02d: hw not ready stop\n", sequence);
 960                }
 961        } else {
 962                /*
 963                 * The single capturing requires an explicit capture
 964                 * operation to fetch the next frame.
 965                 */
 966                if (!vin->continuous)
 967                        rvin_capture_on(vin);
 968        }
 969done:
 970        spin_unlock_irqrestore(&vin->qlock, flags);
 971
 972        return IRQ_RETVAL(handled);
 973}
 974
 975/* Need to hold qlock before calling */
 976static void return_all_buffers(struct rvin_dev *vin,
 977                               enum vb2_buffer_state state)
 978{
 979        struct rvin_buffer *buf, *node;
 980        int i;
 981
 982        for (i = 0; i < HW_BUFFER_NUM; i++) {
 983                if (vin->queue_buf[i]) {
 984                        vb2_buffer_done(&vin->queue_buf[i]->vb2_buf,
 985                                        state);
 986                        vin->queue_buf[i] = NULL;
 987                }
 988        }
 989
 990        list_for_each_entry_safe(buf, node, &vin->buf_list, list) {
 991                vb2_buffer_done(&buf->vb.vb2_buf, state);
 992                list_del(&buf->list);
 993        }
 994}
 995
 996static int rvin_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
 997                            unsigned int *nplanes, unsigned int sizes[],
 998                            struct device *alloc_devs[])
 999
1000{
1001        struct rvin_dev *vin = vb2_get_drv_priv(vq);
1002
1003        /* Make sure the image size is large enough. */
1004        if (*nplanes)
1005                return sizes[0] < vin->format.sizeimage ? -EINVAL : 0;
1006
1007        *nplanes = 1;
1008        sizes[0] = vin->format.sizeimage;
1009
1010        return 0;
1011};
1012
1013static int rvin_buffer_prepare(struct vb2_buffer *vb)
1014{
1015        struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue);
1016        unsigned long size = vin->format.sizeimage;
1017
1018        if (vb2_plane_size(vb, 0) < size) {
1019                vin_err(vin, "buffer too small (%lu < %lu)\n",
1020                        vb2_plane_size(vb, 0), size);
1021                return -EINVAL;
1022        }
1023
1024        vb2_set_plane_payload(vb, 0, size);
1025
1026        return 0;
1027}
1028
1029static void rvin_buffer_queue(struct vb2_buffer *vb)
1030{
1031        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1032        struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue);
1033        unsigned long flags;
1034
1035        spin_lock_irqsave(&vin->qlock, flags);
1036
1037        list_add_tail(to_buf_list(vbuf), &vin->buf_list);
1038
1039        /*
1040         * If capture is stalled add buffer to HW and restart
1041         * capturing if HW is ready to continue.
1042         */
1043        if (vin->state == STALLED)
1044                if (rvin_fill_hw(vin))
1045                        rvin_capture_on(vin);
1046
1047        spin_unlock_irqrestore(&vin->qlock, flags);
1048}
1049
1050static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count)
1051{
1052        struct rvin_dev *vin = vb2_get_drv_priv(vq);
1053        struct v4l2_subdev *sd;
1054        unsigned long flags;
1055        int ret;
1056
1057        sd = vin_to_source(vin);
1058        v4l2_subdev_call(sd, video, s_stream, 1);
1059
1060        spin_lock_irqsave(&vin->qlock, flags);
1061
1062        vin->state = RUNNING;
1063        vin->sequence = 0;
1064
1065        /* Continuous capture requires more buffers then there are HW slots */
1066        vin->continuous = count > HW_BUFFER_NUM;
1067
1068        /*
1069         * This should never happen but if we don't have enough
1070         * buffers for HW bail out
1071         */
1072        if (!rvin_fill_hw(vin)) {
1073                vin_err(vin, "HW not ready to start, not enough buffers available\n");
1074                ret = -EINVAL;
1075                goto out;
1076        }
1077
1078        ret = rvin_capture_start(vin);
1079out:
1080        /* Return all buffers if something went wrong */
1081        if (ret) {
1082                return_all_buffers(vin, VB2_BUF_STATE_QUEUED);
1083                v4l2_subdev_call(sd, video, s_stream, 0);
1084        }
1085
1086        spin_unlock_irqrestore(&vin->qlock, flags);
1087
1088        return ret;
1089}
1090
1091static void rvin_stop_streaming(struct vb2_queue *vq)
1092{
1093        struct rvin_dev *vin = vb2_get_drv_priv(vq);
1094        struct v4l2_subdev *sd;
1095        unsigned long flags;
1096        int retries = 0;
1097
1098        spin_lock_irqsave(&vin->qlock, flags);
1099
1100        vin->state = STOPPING;
1101
1102        /* Wait for streaming to stop */
1103        while (retries++ < RVIN_RETRIES) {
1104
1105                rvin_capture_stop(vin);
1106
1107                /* Check if HW is stopped */
1108                if (!rvin_capture_active(vin)) {
1109                        vin->state = STOPPED;
1110                        break;
1111                }
1112
1113                spin_unlock_irqrestore(&vin->qlock, flags);
1114                msleep(RVIN_TIMEOUT_MS);
1115                spin_lock_irqsave(&vin->qlock, flags);
1116        }
1117
1118        if (vin->state != STOPPED) {
1119                /*
1120                 * If this happens something have gone horribly wrong.
1121                 * Set state to stopped to prevent the interrupt handler
1122                 * to make things worse...
1123                 */
1124                vin_err(vin, "Failed stop HW, something is seriously broken\n");
1125                vin->state = STOPPED;
1126        }
1127
1128        /* Release all active buffers */
1129        return_all_buffers(vin, VB2_BUF_STATE_ERROR);
1130
1131        spin_unlock_irqrestore(&vin->qlock, flags);
1132
1133        sd = vin_to_source(vin);
1134        v4l2_subdev_call(sd, video, s_stream, 0);
1135
1136        /* disable interrupts */
1137        rvin_disable_interrupts(vin);
1138}
1139
1140static const struct vb2_ops rvin_qops = {
1141        .queue_setup            = rvin_queue_setup,
1142        .buf_prepare            = rvin_buffer_prepare,
1143        .buf_queue              = rvin_buffer_queue,
1144        .start_streaming        = rvin_start_streaming,
1145        .stop_streaming         = rvin_stop_streaming,
1146        .wait_prepare           = vb2_ops_wait_prepare,
1147        .wait_finish            = vb2_ops_wait_finish,
1148};
1149
1150void rvin_dma_remove(struct rvin_dev *vin)
1151{
1152        mutex_destroy(&vin->lock);
1153
1154        v4l2_device_unregister(&vin->v4l2_dev);
1155}
1156
1157int rvin_dma_probe(struct rvin_dev *vin, int irq)
1158{
1159        struct vb2_queue *q = &vin->queue;
1160        int i, ret;
1161
1162        /* Initialize the top-level structure */
1163        ret = v4l2_device_register(vin->dev, &vin->v4l2_dev);
1164        if (ret)
1165                return ret;
1166
1167        mutex_init(&vin->lock);
1168        INIT_LIST_HEAD(&vin->buf_list);
1169
1170        spin_lock_init(&vin->qlock);
1171
1172        vin->state = STOPPED;
1173
1174        for (i = 0; i < HW_BUFFER_NUM; i++)
1175                vin->queue_buf[i] = NULL;
1176
1177        /* buffer queue */
1178        q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1179        q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
1180        q->lock = &vin->lock;
1181        q->drv_priv = vin;
1182        q->buf_struct_size = sizeof(struct rvin_buffer);
1183        q->ops = &rvin_qops;
1184        q->mem_ops = &vb2_dma_contig_memops;
1185        q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1186        q->min_buffers_needed = 2;
1187        q->dev = vin->dev;
1188
1189        ret = vb2_queue_init(q);
1190        if (ret < 0) {
1191                vin_err(vin, "failed to initialize VB2 queue\n");
1192                goto error;
1193        }
1194
1195        /* irq */
1196        ret = devm_request_irq(vin->dev, irq, rvin_irq, IRQF_SHARED,
1197                               KBUILD_MODNAME, vin);
1198        if (ret) {
1199                vin_err(vin, "failed to request irq\n");
1200                goto error;
1201        }
1202
1203        return 0;
1204error:
1205        rvin_dma_remove(vin);
1206
1207        return ret;
1208}
1209