linux/drivers/media/platform/nxp/imx-pxp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * i.MX Pixel Pipeline (PXP) mem-to-mem scaler/CSC/rotator driver
   4 *
   5 * Copyright (c) 2018 Pengutronix, Philipp Zabel
   6 *
   7 * based on vim2m
   8 *
   9 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
  10 * Pawel Osciak, <pawel@osciak.com>
  11 * Marek Szyprowski, <m.szyprowski@samsung.com>
  12 */
  13#include <linux/clk.h>
  14#include <linux/delay.h>
  15#include <linux/dma-mapping.h>
  16#include <linux/interrupt.h>
  17#include <linux/io.h>
  18#include <linux/iopoll.h>
  19#include <linux/module.h>
  20#include <linux/of.h>
  21#include <linux/sched.h>
  22#include <linux/slab.h>
  23
  24#include <linux/platform_device.h>
  25#include <media/v4l2-mem2mem.h>
  26#include <media/v4l2-device.h>
  27#include <media/v4l2-ioctl.h>
  28#include <media/v4l2-ctrls.h>
  29#include <media/v4l2-event.h>
  30#include <media/videobuf2-dma-contig.h>
  31
  32#include "imx-pxp.h"
  33
  34static unsigned int debug;
  35module_param(debug, uint, 0644);
  36MODULE_PARM_DESC(debug, "activates debug info");
  37
  38#define MIN_W 8
  39#define MIN_H 8
  40#define MAX_W 4096
  41#define MAX_H 4096
  42#define ALIGN_W 3 /* 8x8 pixel blocks */
  43#define ALIGN_H 3
  44
  45/* Flags that indicate a format can be used for capture/output */
  46#define MEM2MEM_CAPTURE (1 << 0)
  47#define MEM2MEM_OUTPUT  (1 << 1)
  48
  49#define MEM2MEM_NAME            "pxp"
  50
  51/* Flags that indicate processing mode */
  52#define MEM2MEM_HFLIP   (1 << 0)
  53#define MEM2MEM_VFLIP   (1 << 1)
  54
  55#define dprintk(dev, fmt, arg...) \
  56        v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
  57
  58struct pxp_fmt {
  59        u32     fourcc;
  60        int     depth;
  61        /* Types the format can be used for */
  62        u32     types;
  63};
  64
  65static struct pxp_fmt formats[] = {
  66        {
  67                .fourcc = V4L2_PIX_FMT_XBGR32,
  68                .depth  = 32,
  69                /* Both capture and output format */
  70                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
  71        }, {
  72                .fourcc = V4L2_PIX_FMT_ABGR32,
  73                .depth  = 32,
  74                /* Capture-only format */
  75                .types  = MEM2MEM_CAPTURE,
  76        }, {
  77                .fourcc = V4L2_PIX_FMT_BGR24,
  78                .depth  = 24,
  79                .types  = MEM2MEM_CAPTURE,
  80        }, {
  81                .fourcc = V4L2_PIX_FMT_RGB565,
  82                .depth  = 16,
  83                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
  84        }, {
  85                .fourcc = V4L2_PIX_FMT_RGB555,
  86                .depth  = 16,
  87                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
  88        }, {
  89                .fourcc = V4L2_PIX_FMT_RGB444,
  90                .depth  = 16,
  91                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
  92        }, {
  93                .fourcc = V4L2_PIX_FMT_VUYA32,
  94                .depth  = 32,
  95                .types  = MEM2MEM_CAPTURE,
  96        }, {
  97                .fourcc = V4L2_PIX_FMT_VUYX32,
  98                .depth  = 32,
  99                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
 100        }, {
 101                .fourcc = V4L2_PIX_FMT_UYVY,
 102                .depth  = 16,
 103                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
 104        }, {
 105                .fourcc = V4L2_PIX_FMT_YUYV,
 106                .depth  = 16,
 107                /* Output-only format */
 108                .types  = MEM2MEM_OUTPUT,
 109        }, {
 110                .fourcc = V4L2_PIX_FMT_VYUY,
 111                .depth  = 16,
 112                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
 113        }, {
 114                .fourcc = V4L2_PIX_FMT_YVYU,
 115                .depth  = 16,
 116                .types  = MEM2MEM_OUTPUT,
 117        }, {
 118                .fourcc = V4L2_PIX_FMT_GREY,
 119                .depth  = 8,
 120                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
 121        }, {
 122                .fourcc = V4L2_PIX_FMT_Y4,
 123                .depth  = 4,
 124                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
 125        }, {
 126                .fourcc = V4L2_PIX_FMT_NV16,
 127                .depth  = 16,
 128                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
 129        }, {
 130                .fourcc = V4L2_PIX_FMT_NV12,
 131                .depth  = 12,
 132                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
 133        }, {
 134                .fourcc = V4L2_PIX_FMT_NV21,
 135                .depth  = 12,
 136                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
 137        }, {
 138                .fourcc = V4L2_PIX_FMT_NV61,
 139                .depth  = 16,
 140                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
 141        }, {
 142                .fourcc = V4L2_PIX_FMT_YUV422P,
 143                .depth  = 16,
 144                .types  = MEM2MEM_OUTPUT,
 145        }, {
 146                .fourcc = V4L2_PIX_FMT_YUV420,
 147                .depth  = 12,
 148                .types  = MEM2MEM_OUTPUT,
 149        },
 150};
 151
 152#define NUM_FORMATS ARRAY_SIZE(formats)
 153
 154/* Per-queue, driver-specific private data */
 155struct pxp_q_data {
 156        unsigned int            width;
 157        unsigned int            height;
 158        unsigned int            bytesperline;
 159        unsigned int            sizeimage;
 160        unsigned int            sequence;
 161        struct pxp_fmt          *fmt;
 162        enum v4l2_ycbcr_encoding ycbcr_enc;
 163        enum v4l2_quantization  quant;
 164};
 165
 166enum {
 167        V4L2_M2M_SRC = 0,
 168        V4L2_M2M_DST = 1,
 169};
 170
 171static struct pxp_fmt *find_format(struct v4l2_format *f)
 172{
 173        struct pxp_fmt *fmt;
 174        unsigned int k;
 175
 176        for (k = 0; k < NUM_FORMATS; k++) {
 177                fmt = &formats[k];
 178                if (fmt->fourcc == f->fmt.pix.pixelformat)
 179                        break;
 180        }
 181
 182        if (k == NUM_FORMATS)
 183                return NULL;
 184
 185        return &formats[k];
 186}
 187
 188struct pxp_dev {
 189        struct v4l2_device      v4l2_dev;
 190        struct video_device     vfd;
 191
 192        struct clk              *clk;
 193        void __iomem            *mmio;
 194
 195        atomic_t                num_inst;
 196        struct mutex            dev_mutex;
 197        spinlock_t              irqlock;
 198
 199        struct v4l2_m2m_dev     *m2m_dev;
 200};
 201
 202struct pxp_ctx {
 203        struct v4l2_fh          fh;
 204        struct pxp_dev  *dev;
 205
 206        struct v4l2_ctrl_handler hdl;
 207
 208        /* Abort requested by m2m */
 209        int                     aborting;
 210
 211        /* Processing mode */
 212        int                     mode;
 213        u8                      alpha_component;
 214        u8                      rotation;
 215
 216        enum v4l2_colorspace    colorspace;
 217        enum v4l2_xfer_func     xfer_func;
 218
 219        /* Source and destination queue data */
 220        struct pxp_q_data   q_data[2];
 221};
 222
 223static inline struct pxp_ctx *file2ctx(struct file *file)
 224{
 225        return container_of(file->private_data, struct pxp_ctx, fh);
 226}
 227
 228static struct pxp_q_data *get_q_data(struct pxp_ctx *ctx,
 229                                         enum v4l2_buf_type type)
 230{
 231        if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
 232                return &ctx->q_data[V4L2_M2M_SRC];
 233        else
 234                return &ctx->q_data[V4L2_M2M_DST];
 235}
 236
 237static u32 pxp_v4l2_pix_fmt_to_ps_format(u32 v4l2_pix_fmt)
 238{
 239        switch (v4l2_pix_fmt) {
 240        case V4L2_PIX_FMT_XBGR32:  return BV_PXP_PS_CTRL_FORMAT__RGB888;
 241        case V4L2_PIX_FMT_RGB555:  return BV_PXP_PS_CTRL_FORMAT__RGB555;
 242        case V4L2_PIX_FMT_RGB444:  return BV_PXP_PS_CTRL_FORMAT__RGB444;
 243        case V4L2_PIX_FMT_RGB565:  return BV_PXP_PS_CTRL_FORMAT__RGB565;
 244        case V4L2_PIX_FMT_VUYX32:  return BV_PXP_PS_CTRL_FORMAT__YUV1P444;
 245        case V4L2_PIX_FMT_UYVY:    return BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
 246        case V4L2_PIX_FMT_YUYV:    return BM_PXP_PS_CTRL_WB_SWAP |
 247                                          BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
 248        case V4L2_PIX_FMT_VYUY:    return BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
 249        case V4L2_PIX_FMT_YVYU:    return BM_PXP_PS_CTRL_WB_SWAP |
 250                                          BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
 251        case V4L2_PIX_FMT_GREY:    return BV_PXP_PS_CTRL_FORMAT__Y8;
 252        default:
 253        case V4L2_PIX_FMT_Y4:      return BV_PXP_PS_CTRL_FORMAT__Y4;
 254        case V4L2_PIX_FMT_NV16:    return BV_PXP_PS_CTRL_FORMAT__YUV2P422;
 255        case V4L2_PIX_FMT_NV12:    return BV_PXP_PS_CTRL_FORMAT__YUV2P420;
 256        case V4L2_PIX_FMT_NV21:    return BV_PXP_PS_CTRL_FORMAT__YVU2P420;
 257        case V4L2_PIX_FMT_NV61:    return BV_PXP_PS_CTRL_FORMAT__YVU2P422;
 258        case V4L2_PIX_FMT_YUV422P: return BV_PXP_PS_CTRL_FORMAT__YUV422;
 259        case V4L2_PIX_FMT_YUV420:  return BV_PXP_PS_CTRL_FORMAT__YUV420;
 260        }
 261}
 262
 263static u32 pxp_v4l2_pix_fmt_to_out_format(u32 v4l2_pix_fmt)
 264{
 265        switch (v4l2_pix_fmt) {
 266        case V4L2_PIX_FMT_XBGR32:   return BV_PXP_OUT_CTRL_FORMAT__RGB888;
 267        case V4L2_PIX_FMT_ABGR32:   return BV_PXP_OUT_CTRL_FORMAT__ARGB8888;
 268        case V4L2_PIX_FMT_BGR24:    return BV_PXP_OUT_CTRL_FORMAT__RGB888P;
 269        /* Missing V4L2 pixel formats for ARGB1555 and ARGB4444 */
 270        case V4L2_PIX_FMT_RGB555:   return BV_PXP_OUT_CTRL_FORMAT__RGB555;
 271        case V4L2_PIX_FMT_RGB444:   return BV_PXP_OUT_CTRL_FORMAT__RGB444;
 272        case V4L2_PIX_FMT_RGB565:   return BV_PXP_OUT_CTRL_FORMAT__RGB565;
 273        case V4L2_PIX_FMT_VUYA32:
 274        case V4L2_PIX_FMT_VUYX32:   return BV_PXP_OUT_CTRL_FORMAT__YUV1P444;
 275        case V4L2_PIX_FMT_UYVY:     return BV_PXP_OUT_CTRL_FORMAT__UYVY1P422;
 276        case V4L2_PIX_FMT_VYUY:     return BV_PXP_OUT_CTRL_FORMAT__VYUY1P422;
 277        case V4L2_PIX_FMT_GREY:     return BV_PXP_OUT_CTRL_FORMAT__Y8;
 278        default:
 279        case V4L2_PIX_FMT_Y4:       return BV_PXP_OUT_CTRL_FORMAT__Y4;
 280        case V4L2_PIX_FMT_NV16:     return BV_PXP_OUT_CTRL_FORMAT__YUV2P422;
 281        case V4L2_PIX_FMT_NV12:     return BV_PXP_OUT_CTRL_FORMAT__YUV2P420;
 282        case V4L2_PIX_FMT_NV61:     return BV_PXP_OUT_CTRL_FORMAT__YVU2P422;
 283        case V4L2_PIX_FMT_NV21:     return BV_PXP_OUT_CTRL_FORMAT__YVU2P420;
 284        }
 285}
 286
 287static bool pxp_v4l2_pix_fmt_is_yuv(u32 v4l2_pix_fmt)
 288{
 289        switch (v4l2_pix_fmt) {
 290        case V4L2_PIX_FMT_VUYA32:
 291        case V4L2_PIX_FMT_VUYX32:
 292        case V4L2_PIX_FMT_UYVY:
 293        case V4L2_PIX_FMT_YUYV:
 294        case V4L2_PIX_FMT_VYUY:
 295        case V4L2_PIX_FMT_YVYU:
 296        case V4L2_PIX_FMT_NV16:
 297        case V4L2_PIX_FMT_NV12:
 298        case V4L2_PIX_FMT_NV61:
 299        case V4L2_PIX_FMT_NV21:
 300        case V4L2_PIX_FMT_YUV420:
 301        case V4L2_PIX_FMT_YUV422P:
 302        case V4L2_PIX_FMT_GREY:
 303        case V4L2_PIX_FMT_Y4:
 304                return true;
 305        default:
 306                return false;
 307        }
 308}
 309
 310static void pxp_setup_csc(struct pxp_ctx *ctx)
 311{
 312        struct pxp_dev *dev = ctx->dev;
 313        enum v4l2_ycbcr_encoding ycbcr_enc;
 314        enum v4l2_quantization quantization;
 315
 316        if (pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) &&
 317            !pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_DST].fmt->fourcc)) {
 318                /*
 319                 * CSC1 YUV/YCbCr to RGB conversion is implemented as follows:
 320                 *
 321                 * |R|   |C0 0  C1|   |Y  + Yoffset |
 322                 * |G| = |C0 C3 C2| * |Cb + UVoffset|
 323                 * |B|   |C0 C4 0 |   |Cr + UVoffset|
 324                 *
 325                 * Results are clamped to 0..255.
 326                 *
 327                 * BT.601 limited range:
 328                 *
 329                 * |R|   |1.1644  0.0000  1.5960|   |Y  - 16 |
 330                 * |G| = |1.1644 -0.3917 -0.8129| * |Cb - 128|
 331                 * |B|   |1.1644  2.0172  0.0000|   |Cr - 128|
 332                 */
 333                static const u32 csc1_coef_bt601_lim[3] = {
 334                        BM_PXP_CSC1_COEF0_YCBCR_MODE |
 335                        BF_PXP_CSC1_COEF0_C0(0x12a) |   /*  1.1641 (-0.03 %) */
 336                        BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
 337                        BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
 338                        BF_PXP_CSC1_COEF1_C1(0x198) |   /*  1.5938 (-0.23 %) */
 339                        BF_PXP_CSC1_COEF1_C4(0x204),    /*  2.0156 (-0.16 %) */
 340                        BF_PXP_CSC1_COEF2_C2(0x730) |   /* -0.8125 (+0.04 %) */
 341                        BF_PXP_CSC1_COEF2_C3(0x79c),    /* -0.3906 (+0.11 %) */
 342                };
 343                /*
 344                 * BT.601 full range:
 345                 *
 346                 * |R|   |1.0000  0.0000  1.4020|   |Y  + 0  |
 347                 * |G| = |1.0000 -0.3441 -0.7141| * |Cb - 128|
 348                 * |B|   |1.0000  1.7720  0.0000|   |Cr - 128|
 349                 */
 350                static const u32 csc1_coef_bt601_full[3] = {
 351                        BM_PXP_CSC1_COEF0_YCBCR_MODE |
 352                        BF_PXP_CSC1_COEF0_C0(0x100) |   /*  1.0000 (+0.00 %) */
 353                        BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
 354                        BF_PXP_CSC1_COEF0_Y_OFFSET(0),
 355                        BF_PXP_CSC1_COEF1_C1(0x166) |   /*  1.3984 (-0.36 %) */
 356                        BF_PXP_CSC1_COEF1_C4(0x1c5),    /*  1.7695 (-0.25 %) */
 357                        BF_PXP_CSC1_COEF2_C2(0x74a) |   /* -0.7109 (+0.32 %) */
 358                        BF_PXP_CSC1_COEF2_C3(0x7a8),    /* -0.3438 (+0.04 %) */
 359                };
 360                /*
 361                 * Rec.709 limited range:
 362                 *
 363                 * |R|   |1.1644  0.0000  1.7927|   |Y  - 16 |
 364                 * |G| = |1.1644 -0.2132 -0.5329| * |Cb - 128|
 365                 * |B|   |1.1644  2.1124  0.0000|   |Cr - 128|
 366                 */
 367                static const u32 csc1_coef_rec709_lim[3] = {
 368                        BM_PXP_CSC1_COEF0_YCBCR_MODE |
 369                        BF_PXP_CSC1_COEF0_C0(0x12a) |   /*  1.1641 (-0.03 %) */
 370                        BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
 371                        BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
 372                        BF_PXP_CSC1_COEF1_C1(0x1ca) |   /*  1.7891 (-0.37 %) */
 373                        BF_PXP_CSC1_COEF1_C4(0x21c),    /*  2.1094 (-0.30 %) */
 374                        BF_PXP_CSC1_COEF2_C2(0x778) |   /* -0.5312 (+0.16 %) */
 375                        BF_PXP_CSC1_COEF2_C3(0x7ca),    /* -0.2109 (+0.23 %) */
 376                };
 377                /*
 378                 * Rec.709 full range:
 379                 *
 380                 * |R|   |1.0000  0.0000  1.5748|   |Y  + 0  |
 381                 * |G| = |1.0000 -0.1873 -0.4681| * |Cb - 128|
 382                 * |B|   |1.0000  1.8556  0.0000|   |Cr - 128|
 383                 */
 384                static const u32 csc1_coef_rec709_full[3] = {
 385                        BM_PXP_CSC1_COEF0_YCBCR_MODE |
 386                        BF_PXP_CSC1_COEF0_C0(0x100) |   /*  1.0000 (+0.00 %) */
 387                        BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
 388                        BF_PXP_CSC1_COEF0_Y_OFFSET(0),
 389                        BF_PXP_CSC1_COEF1_C1(0x193) |   /*  1.5742 (-0.06 %) */
 390                        BF_PXP_CSC1_COEF1_C4(0x1db),    /*  1.8555 (-0.01 %) */
 391                        BF_PXP_CSC1_COEF2_C2(0x789) |   /* -0.4648 (+0.33 %) */
 392                        BF_PXP_CSC1_COEF2_C3(0x7d1),    /* -0.1836 (+0.37 %) */
 393                };
 394                /*
 395                 * BT.2020 limited range:
 396                 *
 397                 * |R|   |1.1644  0.0000  1.6787|   |Y  - 16 |
 398                 * |G| = |1.1644 -0.1874 -0.6505| * |Cb - 128|
 399                 * |B|   |1.1644  2.1418  0.0000|   |Cr - 128|
 400                 */
 401                static const u32 csc1_coef_bt2020_lim[3] = {
 402                        BM_PXP_CSC1_COEF0_YCBCR_MODE |
 403                        BF_PXP_CSC1_COEF0_C0(0x12a) |   /*  1.1641 (-0.03 %) */
 404                        BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
 405                        BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
 406                        BF_PXP_CSC1_COEF1_C1(0x1ad) |   /*  1.6758 (-0.29 %) */
 407                        BF_PXP_CSC1_COEF1_C4(0x224),    /*  2.1406 (-0.11 %) */
 408                        BF_PXP_CSC1_COEF2_C2(0x75a) |   /* -0.6484 (+0.20 %) */
 409                        BF_PXP_CSC1_COEF2_C3(0x7d1),    /* -0.1836 (+0.38 %) */
 410                };
 411                /*
 412                 * BT.2020 full range:
 413                 *
 414                 * |R|   |1.0000  0.0000  1.4746|   |Y  + 0  |
 415                 * |G| = |1.0000 -0.1646 -0.5714| * |Cb - 128|
 416                 * |B|   |1.0000  1.8814  0.0000|   |Cr - 128|
 417                 */
 418                static const u32 csc1_coef_bt2020_full[3] = {
 419                        BM_PXP_CSC1_COEF0_YCBCR_MODE |
 420                        BF_PXP_CSC1_COEF0_C0(0x100) |   /*  1.0000 (+0.00 %) */
 421                        BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
 422                        BF_PXP_CSC1_COEF0_Y_OFFSET(0),
 423                        BF_PXP_CSC1_COEF1_C1(0x179) |   /*  1.4727 (-0.19 %) */
 424                        BF_PXP_CSC1_COEF1_C4(0x1e1),    /*  1.8789 (-0.25 %) */
 425                        BF_PXP_CSC1_COEF2_C2(0x76e) |   /* -0.5703 (+0.11 %) */
 426                        BF_PXP_CSC1_COEF2_C3(0x7d6),    /* -0.1641 (+0.05 %) */
 427                };
 428                /*
 429                 * SMPTE 240m limited range:
 430                 *
 431                 * |R|   |1.1644  0.0000  1.7937|   |Y  - 16 |
 432                 * |G| = |1.1644 -0.2565 -0.5427| * |Cb - 128|
 433                 * |B|   |1.1644  2.0798  0.0000|   |Cr - 128|
 434                 */
 435                static const u32 csc1_coef_smpte240m_lim[3] = {
 436                        BM_PXP_CSC1_COEF0_YCBCR_MODE |
 437                        BF_PXP_CSC1_COEF0_C0(0x12a) |   /*  1.1641 (-0.03 %) */
 438                        BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
 439                        BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
 440                        BF_PXP_CSC1_COEF1_C1(0x1cb) |   /*  1.7930 (-0.07 %) */
 441                        BF_PXP_CSC1_COEF1_C4(0x214),    /*  2.0781 (-0.17 %) */
 442                        BF_PXP_CSC1_COEF2_C2(0x776) |   /* -0.5391 (+0.36 %) */
 443                        BF_PXP_CSC1_COEF2_C3(0x7bf),    /* -0.2539 (+0.26 %) */
 444                };
 445                /*
 446                 * SMPTE 240m full range:
 447                 *
 448                 * |R|   |1.0000  0.0000  1.5756|   |Y  + 0  |
 449                 * |G| = |1.0000 -0.2253 -0.4767| * |Cb - 128|
 450                 * |B|   |1.0000  1.8270  0.0000|   |Cr - 128|
 451                 */
 452                static const u32 csc1_coef_smpte240m_full[3] = {
 453                        BM_PXP_CSC1_COEF0_YCBCR_MODE |
 454                        BF_PXP_CSC1_COEF0_C0(0x100) |   /*  1.0000 (+0.00 %) */
 455                        BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
 456                        BF_PXP_CSC1_COEF0_Y_OFFSET(0),
 457                        BF_PXP_CSC1_COEF1_C1(0x193) |   /*  1.5742 (-0.14 %) */
 458                        BF_PXP_CSC1_COEF1_C4(0x1d3),    /*  1.8242 (-0.28 %) */
 459                        BF_PXP_CSC1_COEF2_C2(0x786) |   /* -0.4766 (+0.01 %) */
 460                        BF_PXP_CSC1_COEF2_C3(0x7c7),    /* -0.2227 (+0.26 %) */
 461                };
 462                const u32 *csc1_coef;
 463
 464                ycbcr_enc = ctx->q_data[V4L2_M2M_SRC].ycbcr_enc;
 465                quantization = ctx->q_data[V4L2_M2M_SRC].quant;
 466
 467                if (ycbcr_enc == V4L2_YCBCR_ENC_601) {
 468                        if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
 469                                csc1_coef = csc1_coef_bt601_full;
 470                        else
 471                                csc1_coef = csc1_coef_bt601_lim;
 472                } else if (ycbcr_enc == V4L2_YCBCR_ENC_709) {
 473                        if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
 474                                csc1_coef = csc1_coef_rec709_full;
 475                        else
 476                                csc1_coef = csc1_coef_rec709_lim;
 477                } else if (ycbcr_enc == V4L2_YCBCR_ENC_BT2020) {
 478                        if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
 479                                csc1_coef = csc1_coef_bt2020_full;
 480                        else
 481                                csc1_coef = csc1_coef_bt2020_lim;
 482                } else {
 483                        if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
 484                                csc1_coef = csc1_coef_smpte240m_full;
 485                        else
 486                                csc1_coef = csc1_coef_smpte240m_lim;
 487                }
 488
 489                writel(csc1_coef[0], dev->mmio + HW_PXP_CSC1_COEF0);
 490                writel(csc1_coef[1], dev->mmio + HW_PXP_CSC1_COEF1);
 491                writel(csc1_coef[2], dev->mmio + HW_PXP_CSC1_COEF2);
 492        } else {
 493                writel(BM_PXP_CSC1_COEF0_BYPASS, dev->mmio + HW_PXP_CSC1_COEF0);
 494        }
 495
 496        if (!pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) &&
 497            pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_DST].fmt->fourcc)) {
 498                /*
 499                 * CSC2 RGB to YUV/YCbCr conversion is implemented as follows:
 500                 *
 501                 * |Y |   |A1 A2 A3|   |R|   |D1|
 502                 * |Cb| = |B1 B2 B3| * |G| + |D2|
 503                 * |Cr|   |C1 C2 C3|   |B|   |D3|
 504                 *
 505                 * Results are clamped to 0..255.
 506                 *
 507                 * BT.601 limited range:
 508                 *
 509                 * |Y |   | 0.2568  0.5041  0.0979|   |R|   |16 |
 510                 * |Cb| = |-0.1482 -0.2910  0.4392| * |G| + |128|
 511                 * |Cr|   | 0.4392  0.4392 -0.3678|   |B|   |128|
 512                 */
 513                static const u32 csc2_coef_bt601_lim[6] = {
 514                        BF_PXP_CSC2_COEF0_A2(0x081) |   /*  0.5039 (-0.02 %) */
 515                        BF_PXP_CSC2_COEF0_A1(0x041),    /*  0.2539 (-0.29 %) */
 516                        BF_PXP_CSC2_COEF1_B1(0x7db) |   /* -0.1445 (+0.37 %) */
 517                        BF_PXP_CSC2_COEF1_A3(0x019),    /*  0.0977 (-0.02 %) */
 518                        BF_PXP_CSC2_COEF2_B3(0x070) |   /*  0.4375 (-0.17 %) */
 519                        BF_PXP_CSC2_COEF2_B2(0x7b6),    /* -0.2891 (+0.20 %) */
 520                        BF_PXP_CSC2_COEF3_C2(0x7a2) |   /* -0.3672 (+0.06 %) */
 521                        BF_PXP_CSC2_COEF3_C1(0x070),    /*  0.4375 (-0.17 %) */
 522                        BF_PXP_CSC2_COEF4_D1(16) |
 523                        BF_PXP_CSC2_COEF4_C3(0x7ee),    /* -0.0703 (+0.11 %) */
 524                        BF_PXP_CSC2_COEF5_D3(128) |
 525                        BF_PXP_CSC2_COEF5_D2(128),
 526                };
 527                /*
 528                 * BT.601 full range:
 529                 *
 530                 * |Y |   | 0.2990  0.5870  0.1140|   |R|   |0  |
 531                 * |Cb| = |-0.1687 -0.3313  0.5000| * |G| + |128|
 532                 * |Cr|   | 0.5000  0.5000 -0.4187|   |B|   |128|
 533                 */
 534                static const u32 csc2_coef_bt601_full[6] = {
 535                        BF_PXP_CSC2_COEF0_A2(0x096) |   /*  0.5859 (-0.11 %) */
 536                        BF_PXP_CSC2_COEF0_A1(0x04c),    /*  0.2969 (-0.21 %) */
 537                        BF_PXP_CSC2_COEF1_B1(0x7d5) |   /* -0.1680 (+0.07 %) */
 538                        BF_PXP_CSC2_COEF1_A3(0x01d),    /*  0.1133 (-0.07 %) */
 539                        BF_PXP_CSC2_COEF2_B3(0x080) |   /*  0.5000 (+0.00 %) */
 540                        BF_PXP_CSC2_COEF2_B2(0x7ac),    /* -0.3281 (+0.32 %) */
 541                        BF_PXP_CSC2_COEF3_C2(0x795) |   /* -0.4180 (+0.07 %) */
 542                        BF_PXP_CSC2_COEF3_C1(0x080),    /*  0.5000 (+0.00 %) */
 543                        BF_PXP_CSC2_COEF4_D1(0) |
 544                        BF_PXP_CSC2_COEF4_C3(0x7ec),    /* -0.0781 (+0.32 %) */
 545                        BF_PXP_CSC2_COEF5_D3(128) |
 546                        BF_PXP_CSC2_COEF5_D2(128),
 547                };
 548                /*
 549                 * Rec.709 limited range:
 550                 *
 551                 * |Y |   | 0.1826  0.6142  0.0620|   |R|   |16 |
 552                 * |Cb| = |-0.1007 -0.3385  0.4392| * |G| + |128|
 553                 * |Cr|   | 0.4392  0.4392 -0.3990|   |B|   |128|
 554                 */
 555                static const u32 csc2_coef_rec709_lim[6] = {
 556                        BF_PXP_CSC2_COEF0_A2(0x09d) |   /*  0.6133 (-0.09 %) */
 557                        BF_PXP_CSC2_COEF0_A1(0x02e),    /*  0.1797 (-0.29 %) */
 558                        BF_PXP_CSC2_COEF1_B1(0x7e7) |   /* -0.0977 (+0.30 %) */
 559                        BF_PXP_CSC2_COEF1_A3(0x00f),    /*  0.0586 (-0.34 %) */
 560                        BF_PXP_CSC2_COEF2_B3(0x070) |   /*  0.4375 (-0.17 %) */
 561                        BF_PXP_CSC2_COEF2_B2(0x7aa),    /* -0.3359 (+0.26 %) */
 562                        BF_PXP_CSC2_COEF3_C2(0x79a) |   /* -0.3984 (+0.05 %) */
 563                        BF_PXP_CSC2_COEF3_C1(0x070),    /*  0.4375 (-0.17 %) */
 564                        BF_PXP_CSC2_COEF4_D1(16) |
 565                        BF_PXP_CSC2_COEF4_C3(0x7f6),    /* -0.0391 (+0.12 %) */
 566                        BF_PXP_CSC2_COEF5_D3(128) |
 567                        BF_PXP_CSC2_COEF5_D2(128),
 568                };
 569                /*
 570                 * Rec.709 full range:
 571                 *
 572                 * |Y |   | 0.2126  0.7152  0.0722|   |R|   |0  |
 573                 * |Cb| = |-0.1146 -0.3854  0.5000| * |G| + |128|
 574                 * |Cr|   | 0.5000  0.5000 -0.4542|   |B|   |128|
 575                 */
 576                static const u32 csc2_coef_rec709_full[6] = {
 577                        BF_PXP_CSC2_COEF0_A2(0x0b7) |   /*  0.7148 (-0.04 %) */
 578                        BF_PXP_CSC2_COEF0_A1(0x036),    /*  0.2109 (-0.17 %) */
 579                        BF_PXP_CSC2_COEF1_B1(0x7e3) |   /* -0.1133 (+0.13 %) */
 580                        BF_PXP_CSC2_COEF1_A3(0x012),    /*  0.0703 (-0.19 %) */
 581                        BF_PXP_CSC2_COEF2_B3(0x080) |   /*  0.5000 (+0.00 %) */
 582                        BF_PXP_CSC2_COEF2_B2(0x79e),    /* -0.3828 (+0.26 %) */
 583                        BF_PXP_CSC2_COEF3_C2(0x78c) |   /* -0.4531 (+0.11 %) */
 584                        BF_PXP_CSC2_COEF3_C1(0x080),    /*  0.5000 (+0.00 %) */
 585                        BF_PXP_CSC2_COEF4_D1(0) |
 586                        BF_PXP_CSC2_COEF4_C3(0x7f5),    /* -0.0430 (+0.28 %) */
 587                        BF_PXP_CSC2_COEF5_D3(128) |
 588                        BF_PXP_CSC2_COEF5_D2(128),
 589                };
 590                /*
 591                 * BT.2020 limited range:
 592                 *
 593                 * |Y |   | 0.2256  0.5823  0.0509|   |R|   |16 |
 594                 * |Cb| = |-0.1226 -0.3166  0.4392| * |G| + |128|
 595                 * |Cr|   | 0.4392  0.4392 -0.4039|   |B|   |128|
 596                 */
 597                static const u32 csc2_coef_bt2020_lim[6] = {
 598                        BF_PXP_CSC2_COEF0_A2(0x095) |   /*  0.5820 (-0.03 %) */
 599                        BF_PXP_CSC2_COEF0_A1(0x039),    /*  0.2227 (-0.30 %) */
 600                        BF_PXP_CSC2_COEF1_B1(0x7e1) |   /* -0.1211 (+0.15 %) */
 601                        BF_PXP_CSC2_COEF1_A3(0x00d),    /*  0.0508 (-0.01 %) */
 602                        BF_PXP_CSC2_COEF2_B3(0x070) |   /*  0.4375 (-0.17 %) */
 603                        BF_PXP_CSC2_COEF2_B2(0x7af),    /* -0.3164 (+0.02 %) */
 604                        BF_PXP_CSC2_COEF3_C2(0x799) |   /* -0.4023 (+0.16 %) */
 605                        BF_PXP_CSC2_COEF3_C1(0x070),    /*  0.4375 (-0.17 %) */
 606                        BF_PXP_CSC2_COEF4_D1(16) |
 607                        BF_PXP_CSC2_COEF4_C3(0x7f7),    /* -0.0352 (+0.02 %) */
 608                        BF_PXP_CSC2_COEF5_D3(128) |
 609                        BF_PXP_CSC2_COEF5_D2(128),
 610                };
 611                /*
 612                 * BT.2020 full range:
 613                 *
 614                 * |Y |   | 0.2627  0.6780  0.0593|   |R|   |0  |
 615                 * |Cb| = |-0.1396 -0.3604  0.5000| * |G| + |128|
 616                 * |Cr|   | 0.5000  0.5000 -0.4598|   |B|   |128|
 617                 */
 618                static const u32 csc2_coef_bt2020_full[6] = {
 619                        BF_PXP_CSC2_COEF0_A2(0x0ad) |   /*  0.6758 (-0.22 %) */
 620                        BF_PXP_CSC2_COEF0_A1(0x043),    /*  0.2617 (-0.10 %) */
 621                        BF_PXP_CSC2_COEF1_B1(0x7dd) |   /* -0.1367 (+0.29 %) */
 622                        BF_PXP_CSC2_COEF1_A3(0x00f),    /*  0.0586 (-0.07 %) */
 623                        BF_PXP_CSC2_COEF2_B3(0x080) |   /*  0.5000 (+0.00 %) */
 624                        BF_PXP_CSC2_COEF2_B2(0x7a4),    /* -0.3594 (+0.10 %) */
 625                        BF_PXP_CSC2_COEF3_C2(0x78b) |   /* -0.4570 (+0.28 %) */
 626                        BF_PXP_CSC2_COEF3_C1(0x080),    /*  0.5000 (+0.00 %) */
 627                        BF_PXP_CSC2_COEF4_D1(0) |
 628                        BF_PXP_CSC2_COEF4_C3(0x7f6),    /* -0.0391 (+0.11 %) */
 629                        BF_PXP_CSC2_COEF5_D3(128) |
 630                        BF_PXP_CSC2_COEF5_D2(128),
 631                };
 632                /*
 633                 * SMPTE 240m limited range:
 634                 *
 635                 * |Y |   | 0.1821  0.6020  0.0747|   |R|   |16 |
 636                 * |Cb| = |-0.1019 -0.3373  0.4392| * |G| + |128|
 637                 * |Cr|   | 0.4392  0.4392 -0.3909|   |B|   |128|
 638                 */
 639                static const u32 csc2_coef_smpte240m_lim[6] = {
 640                        BF_PXP_CSC2_COEF0_A2(0x09a) |   /*  0.6016 (-0.05 %) */
 641                        BF_PXP_CSC2_COEF0_A1(0x02e),    /*  0.1797 (-0.24 %) */
 642                        BF_PXP_CSC2_COEF1_B1(0x7e6) |   /* -0.1016 (+0.03 %) */
 643                        BF_PXP_CSC2_COEF1_A3(0x013),    /*  0.0742 (-0.05 %) */
 644                        BF_PXP_CSC2_COEF2_B3(0x070) |   /*  0.4375 (-0.17 %) */
 645                        BF_PXP_CSC2_COEF2_B2(0x7aa),    /* -0.3359 (+0.14 %) */
 646                        BF_PXP_CSC2_COEF3_C2(0x79c) |   /* -0.3906 (+0.03 %) */
 647                        BF_PXP_CSC2_COEF3_C1(0x070),    /*  0.4375 (-0.17 %) */
 648                        BF_PXP_CSC2_COEF4_D1(16) |
 649                        BF_PXP_CSC2_COEF4_C3(0x7f4),    /* -0.0469 (+0.14 %) */
 650                        BF_PXP_CSC2_COEF5_D3(128) |
 651                        BF_PXP_CSC2_COEF5_D2(128),
 652                };
 653                /*
 654                 * SMPTE 240m full range:
 655                 *
 656                 * |Y |   | 0.2120  0.7010  0.0870|   |R|   |0  |
 657                 * |Cb| = |-0.1160 -0.3840  0.5000| * |G| + |128|
 658                 * |Cr|   | 0.5000  0.5000 -0.4450|   |B|   |128|
 659                 */
 660                static const u32 csc2_coef_smpte240m_full[6] = {
 661                        BF_PXP_CSC2_COEF0_A2(0x0b3) |   /*  0.6992 (-0.18 %) */
 662                        BF_PXP_CSC2_COEF0_A1(0x036),    /*  0.2109 (-0.11 %) */
 663                        BF_PXP_CSC2_COEF1_B1(0x7e3) |   /* -0.1133 (+0.27 %) */
 664                        BF_PXP_CSC2_COEF1_A3(0x016),    /*  0.0859 (-0.11 %) */
 665                        BF_PXP_CSC2_COEF2_B3(0x080) |   /*  0.5000 (+0.00 %) */
 666                        BF_PXP_CSC2_COEF2_B2(0x79e),    /* -0.3828 (+0.12 %) */
 667                        BF_PXP_CSC2_COEF3_C2(0x78f) |   /* -0.4414 (+0.36 %) */
 668                        BF_PXP_CSC2_COEF3_C1(0x080),    /*  0.5000 (+0.00 %) */
 669                        BF_PXP_CSC2_COEF4_D1(0) |
 670                        BF_PXP_CSC2_COEF4_C3(0x7f2),    /* -0.0547 (+0.03 %) */
 671                        BF_PXP_CSC2_COEF5_D3(128) |
 672                        BF_PXP_CSC2_COEF5_D2(128),
 673                };
 674                const u32 *csc2_coef;
 675                u32 csc2_ctrl;
 676
 677                ycbcr_enc = ctx->q_data[V4L2_M2M_DST].ycbcr_enc;
 678                quantization = ctx->q_data[V4L2_M2M_DST].quant;
 679
 680                if (ycbcr_enc == V4L2_YCBCR_ENC_601) {
 681                        if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
 682                                csc2_coef = csc2_coef_bt601_full;
 683                        else
 684                                csc2_coef = csc2_coef_bt601_lim;
 685                } else if (ycbcr_enc == V4L2_YCBCR_ENC_709) {
 686                        if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
 687                                csc2_coef = csc2_coef_rec709_full;
 688                        else
 689                                csc2_coef = csc2_coef_rec709_lim;
 690                } else if (ycbcr_enc == V4L2_YCBCR_ENC_BT2020) {
 691                        if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
 692                                csc2_coef = csc2_coef_bt2020_full;
 693                        else
 694                                csc2_coef = csc2_coef_bt2020_lim;
 695                } else {
 696                        if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
 697                                csc2_coef = csc2_coef_smpte240m_full;
 698                        else
 699                                csc2_coef = csc2_coef_smpte240m_lim;
 700                }
 701                if (quantization == V4L2_QUANTIZATION_FULL_RANGE) {
 702                        csc2_ctrl = BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YUV <<
 703                                    BP_PXP_CSC2_CTRL_CSC_MODE;
 704                } else {
 705                        csc2_ctrl = BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YCbCr <<
 706                                    BP_PXP_CSC2_CTRL_CSC_MODE;
 707                }
 708
 709                writel(csc2_ctrl, dev->mmio + HW_PXP_CSC2_CTRL);
 710                writel(csc2_coef[0], dev->mmio + HW_PXP_CSC2_COEF0);
 711                writel(csc2_coef[1], dev->mmio + HW_PXP_CSC2_COEF1);
 712                writel(csc2_coef[2], dev->mmio + HW_PXP_CSC2_COEF2);
 713                writel(csc2_coef[3], dev->mmio + HW_PXP_CSC2_COEF3);
 714                writel(csc2_coef[4], dev->mmio + HW_PXP_CSC2_COEF4);
 715                writel(csc2_coef[5], dev->mmio + HW_PXP_CSC2_COEF5);
 716        } else {
 717                writel(BM_PXP_CSC2_CTRL_BYPASS, dev->mmio + HW_PXP_CSC2_CTRL);
 718        }
 719}
 720
 721static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb,
 722                     struct vb2_v4l2_buffer *out_vb)
 723{
 724        struct pxp_dev *dev = ctx->dev;
 725        struct pxp_q_data *q_data;
 726        u32 src_width, src_height, src_stride, src_fourcc;
 727        u32 dst_width, dst_height, dst_stride, dst_fourcc;
 728        dma_addr_t p_in, p_out;
 729        u32 ctrl, out_ctrl, out_buf, out_buf2, out_pitch, out_lrc, out_ps_ulc;
 730        u32 out_ps_lrc;
 731        u32 ps_ctrl, ps_buf, ps_ubuf, ps_vbuf, ps_pitch, ps_scale, ps_offset;
 732        u32 as_ulc, as_lrc;
 733        u32 y_size;
 734        u32 decx, decy, xscale, yscale;
 735
 736        q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
 737
 738        src_width = ctx->q_data[V4L2_M2M_SRC].width;
 739        dst_width = ctx->q_data[V4L2_M2M_DST].width;
 740        src_height = ctx->q_data[V4L2_M2M_SRC].height;
 741        dst_height = ctx->q_data[V4L2_M2M_DST].height;
 742        src_stride = ctx->q_data[V4L2_M2M_SRC].bytesperline;
 743        dst_stride = ctx->q_data[V4L2_M2M_DST].bytesperline;
 744        src_fourcc = ctx->q_data[V4L2_M2M_SRC].fmt->fourcc;
 745        dst_fourcc = ctx->q_data[V4L2_M2M_DST].fmt->fourcc;
 746
 747        p_in = vb2_dma_contig_plane_dma_addr(&in_vb->vb2_buf, 0);
 748        p_out = vb2_dma_contig_plane_dma_addr(&out_vb->vb2_buf, 0);
 749
 750        if (!p_in || !p_out) {
 751                v4l2_err(&dev->v4l2_dev,
 752                         "Acquiring DMA addresses of buffers failed\n");
 753                return -EFAULT;
 754        }
 755
 756        out_vb->sequence =
 757                get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++;
 758        in_vb->sequence = q_data->sequence++;
 759        out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp;
 760
 761        if (in_vb->flags & V4L2_BUF_FLAG_TIMECODE)
 762                out_vb->timecode = in_vb->timecode;
 763        out_vb->field = in_vb->field;
 764        out_vb->flags = in_vb->flags &
 765                (V4L2_BUF_FLAG_TIMECODE |
 766                 V4L2_BUF_FLAG_KEYFRAME |
 767                 V4L2_BUF_FLAG_PFRAME |
 768                 V4L2_BUF_FLAG_BFRAME |
 769                 V4L2_BUF_FLAG_TSTAMP_SRC_MASK);
 770
 771        /* 8x8 block size */
 772        ctrl = BF_PXP_CTRL_VFLIP0(!!(ctx->mode & MEM2MEM_VFLIP)) |
 773               BF_PXP_CTRL_HFLIP0(!!(ctx->mode & MEM2MEM_HFLIP)) |
 774               BF_PXP_CTRL_ROTATE0(ctx->rotation);
 775        /* Always write alpha value as V4L2_CID_ALPHA_COMPONENT */
 776        out_ctrl = BF_PXP_OUT_CTRL_ALPHA(ctx->alpha_component) |
 777                   BF_PXP_OUT_CTRL_ALPHA_OUTPUT(1) |
 778                   pxp_v4l2_pix_fmt_to_out_format(dst_fourcc);
 779        out_buf = p_out;
 780
 781        if (ctx->rotation == BV_PXP_CTRL_ROTATE0__ROT_90 ||
 782            ctx->rotation == BV_PXP_CTRL_ROTATE0__ROT_270)
 783                swap(dst_width, dst_height);
 784
 785        switch (dst_fourcc) {
 786        case V4L2_PIX_FMT_NV12:
 787        case V4L2_PIX_FMT_NV21:
 788        case V4L2_PIX_FMT_NV16:
 789        case V4L2_PIX_FMT_NV61:
 790                out_buf2 = out_buf + dst_stride * dst_height;
 791                break;
 792        default:
 793                out_buf2 = 0;
 794        }
 795
 796        out_pitch = BF_PXP_OUT_PITCH_PITCH(dst_stride);
 797        out_lrc = BF_PXP_OUT_LRC_X(dst_width - 1) |
 798                  BF_PXP_OUT_LRC_Y(dst_height - 1);
 799        /* PS covers whole output */
 800        out_ps_ulc = BF_PXP_OUT_PS_ULC_X(0) | BF_PXP_OUT_PS_ULC_Y(0);
 801        out_ps_lrc = BF_PXP_OUT_PS_LRC_X(dst_width - 1) |
 802                     BF_PXP_OUT_PS_LRC_Y(dst_height - 1);
 803        /* no AS */
 804        as_ulc = BF_PXP_OUT_AS_ULC_X(1) | BF_PXP_OUT_AS_ULC_Y(1);
 805        as_lrc = BF_PXP_OUT_AS_LRC_X(0) | BF_PXP_OUT_AS_LRC_Y(0);
 806
 807        decx = (src_width <= dst_width) ? 0 : ilog2(src_width / dst_width);
 808        decy = (src_height <= dst_height) ? 0 : ilog2(src_height / dst_height);
 809        ps_ctrl = BF_PXP_PS_CTRL_DECX(decx) | BF_PXP_PS_CTRL_DECY(decy) |
 810                  pxp_v4l2_pix_fmt_to_ps_format(src_fourcc);
 811        ps_buf = p_in;
 812        y_size = src_stride * src_height;
 813        switch (src_fourcc) {
 814        case V4L2_PIX_FMT_YUV420:
 815                ps_ubuf = ps_buf + y_size;
 816                ps_vbuf = ps_ubuf + y_size / 4;
 817                break;
 818        case V4L2_PIX_FMT_YUV422P:
 819                ps_ubuf = ps_buf + y_size;
 820                ps_vbuf = ps_ubuf + y_size / 2;
 821                break;
 822        case V4L2_PIX_FMT_NV12:
 823        case V4L2_PIX_FMT_NV21:
 824        case V4L2_PIX_FMT_NV16:
 825        case V4L2_PIX_FMT_NV61:
 826                ps_ubuf = ps_buf + y_size;
 827                ps_vbuf = 0;
 828                break;
 829        case V4L2_PIX_FMT_GREY:
 830        case V4L2_PIX_FMT_Y4:
 831                ps_ubuf = 0;
 832                /* In grayscale mode, ps_vbuf contents are reused as CbCr */
 833                ps_vbuf = 0x8080;
 834                break;
 835        default:
 836                ps_ubuf = 0;
 837                ps_vbuf = 0;
 838                break;
 839        }
 840        ps_pitch = BF_PXP_PS_PITCH_PITCH(src_stride);
 841        if (decx) {
 842                xscale = (src_width >> decx) * 0x1000 / dst_width;
 843        } else {
 844                switch (src_fourcc) {
 845                case V4L2_PIX_FMT_UYVY:
 846                case V4L2_PIX_FMT_YUYV:
 847                case V4L2_PIX_FMT_VYUY:
 848                case V4L2_PIX_FMT_YVYU:
 849                case V4L2_PIX_FMT_NV16:
 850                case V4L2_PIX_FMT_NV12:
 851                case V4L2_PIX_FMT_NV21:
 852                case V4L2_PIX_FMT_NV61:
 853                case V4L2_PIX_FMT_YUV422P:
 854                case V4L2_PIX_FMT_YUV420:
 855                        /*
 856                         * This avoids sampling past the right edge for
 857                         * horizontally chroma subsampled formats.
 858                         */
 859                        xscale = (src_width - 2) * 0x1000 / (dst_width - 1);
 860                        break;
 861                default:
 862                        xscale = (src_width - 1) * 0x1000 / (dst_width - 1);
 863                        break;
 864                }
 865        }
 866        if (decy)
 867                yscale = (src_height >> decy) * 0x1000 / dst_height;
 868        else
 869                yscale = (src_height - 1) * 0x1000 / (dst_height - 1);
 870        ps_scale = BF_PXP_PS_SCALE_YSCALE(yscale) |
 871                   BF_PXP_PS_SCALE_XSCALE(xscale);
 872        ps_offset = BF_PXP_PS_OFFSET_YOFFSET(0) | BF_PXP_PS_OFFSET_XOFFSET(0);
 873
 874        writel(ctrl, dev->mmio + HW_PXP_CTRL);
 875        /* skip STAT */
 876        writel(out_ctrl, dev->mmio + HW_PXP_OUT_CTRL);
 877        writel(out_buf, dev->mmio + HW_PXP_OUT_BUF);
 878        writel(out_buf2, dev->mmio + HW_PXP_OUT_BUF2);
 879        writel(out_pitch, dev->mmio + HW_PXP_OUT_PITCH);
 880        writel(out_lrc, dev->mmio + HW_PXP_OUT_LRC);
 881        writel(out_ps_ulc, dev->mmio + HW_PXP_OUT_PS_ULC);
 882        writel(out_ps_lrc, dev->mmio + HW_PXP_OUT_PS_LRC);
 883        writel(as_ulc, dev->mmio + HW_PXP_OUT_AS_ULC);
 884        writel(as_lrc, dev->mmio + HW_PXP_OUT_AS_LRC);
 885        writel(ps_ctrl, dev->mmio + HW_PXP_PS_CTRL);
 886        writel(ps_buf, dev->mmio + HW_PXP_PS_BUF);
 887        writel(ps_ubuf, dev->mmio + HW_PXP_PS_UBUF);
 888        writel(ps_vbuf, dev->mmio + HW_PXP_PS_VBUF);
 889        writel(ps_pitch, dev->mmio + HW_PXP_PS_PITCH);
 890        writel(0x00ffffff, dev->mmio + HW_PXP_PS_BACKGROUND_0);
 891        writel(ps_scale, dev->mmio + HW_PXP_PS_SCALE);
 892        writel(ps_offset, dev->mmio + HW_PXP_PS_OFFSET);
 893        /* disable processed surface color keying */
 894        writel(0x00ffffff, dev->mmio + HW_PXP_PS_CLRKEYLOW_0);
 895        writel(0x00000000, dev->mmio + HW_PXP_PS_CLRKEYHIGH_0);
 896
 897        /* disable alpha surface color keying */
 898        writel(0x00ffffff, dev->mmio + HW_PXP_AS_CLRKEYLOW_0);
 899        writel(0x00000000, dev->mmio + HW_PXP_AS_CLRKEYHIGH_0);
 900
 901        /* setup CSC */
 902        pxp_setup_csc(ctx);
 903
 904        /* bypass LUT */
 905        writel(BM_PXP_LUT_CTRL_BYPASS, dev->mmio + HW_PXP_LUT_CTRL);
 906
 907        writel(BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(0)|
 908               BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1)|
 909               BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(0)|
 910               BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0)|
 911               BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(0)|
 912               BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(0)|
 913               BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(1)|
 914               BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0)|
 915               BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(0)|
 916               BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(0)|
 917               BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(0)|
 918               BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(0)|
 919               BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0)|
 920               BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(0)|
 921               BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(0)|
 922               BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(0),
 923               dev->mmio + HW_PXP_DATA_PATH_CTRL0);
 924        writel(BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(1) |
 925               BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(1),
 926               dev->mmio + HW_PXP_DATA_PATH_CTRL1);
 927
 928        writel(0xffff, dev->mmio + HW_PXP_IRQ_MASK);
 929
 930        /* ungate, enable PS/AS/OUT and PXP operation */
 931        writel(BM_PXP_CTRL_IRQ_ENABLE, dev->mmio + HW_PXP_CTRL_SET);
 932        writel(BM_PXP_CTRL_ENABLE | BM_PXP_CTRL_ENABLE_CSC2 |
 933               BM_PXP_CTRL_ENABLE_LUT | BM_PXP_CTRL_ENABLE_ROTATE0 |
 934               BM_PXP_CTRL_ENABLE_PS_AS_OUT, dev->mmio + HW_PXP_CTRL_SET);
 935
 936        return 0;
 937}
 938
 939static void pxp_job_finish(struct pxp_dev *dev)
 940{
 941        struct pxp_ctx *curr_ctx;
 942        struct vb2_v4l2_buffer *src_vb, *dst_vb;
 943        unsigned long flags;
 944
 945        curr_ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
 946
 947        if (curr_ctx == NULL) {
 948                pr_err("Instance released before the end of transaction\n");
 949                return;
 950        }
 951
 952        src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
 953        dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
 954
 955        spin_lock_irqsave(&dev->irqlock, flags);
 956        v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
 957        v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
 958        spin_unlock_irqrestore(&dev->irqlock, flags);
 959
 960        dprintk(curr_ctx->dev, "Finishing transaction\n");
 961        v4l2_m2m_job_finish(dev->m2m_dev, curr_ctx->fh.m2m_ctx);
 962}
 963
 964/*
 965 * mem2mem callbacks
 966 */
 967static void pxp_device_run(void *priv)
 968{
 969        struct pxp_ctx *ctx = priv;
 970        struct vb2_v4l2_buffer *src_buf, *dst_buf;
 971
 972        src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 973        dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
 974
 975        pxp_start(ctx, src_buf, dst_buf);
 976}
 977
 978static int pxp_job_ready(void *priv)
 979{
 980        struct pxp_ctx *ctx = priv;
 981
 982        if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < 1 ||
 983            v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < 1) {
 984                dprintk(ctx->dev, "Not enough buffers available\n");
 985                return 0;
 986        }
 987
 988        return 1;
 989}
 990
 991static void pxp_job_abort(void *priv)
 992{
 993        struct pxp_ctx *ctx = priv;
 994
 995        /* Will cancel the transaction in the next interrupt handler */
 996        ctx->aborting = 1;
 997}
 998
 999/*
1000 * interrupt handler
1001 */
1002static irqreturn_t pxp_irq_handler(int irq, void *dev_id)
1003{
1004        struct pxp_dev *dev = dev_id;
1005        u32 stat;
1006
1007        stat = readl(dev->mmio + HW_PXP_STAT);
1008
1009        if (stat & BM_PXP_STAT_IRQ0) {
1010                /* we expect x = 0, y = height, irq0 = 1 */
1011                if (stat & ~(BM_PXP_STAT_BLOCKX | BM_PXP_STAT_BLOCKY |
1012                             BM_PXP_STAT_IRQ0))
1013                        dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat);
1014                writel(BM_PXP_STAT_IRQ0, dev->mmio + HW_PXP_STAT_CLR);
1015
1016                pxp_job_finish(dev);
1017        } else {
1018                u32 irq = readl(dev->mmio + HW_PXP_IRQ);
1019
1020                dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat);
1021                dprintk(dev, "%s: irq = 0x%08x\n", __func__, irq);
1022
1023                writel(irq, dev->mmio + HW_PXP_IRQ_CLR);
1024        }
1025
1026        return IRQ_HANDLED;
1027}
1028
1029/*
1030 * video ioctls
1031 */
1032static int pxp_querycap(struct file *file, void *priv,
1033                           struct v4l2_capability *cap)
1034{
1035        strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
1036        strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
1037        snprintf(cap->bus_info, sizeof(cap->bus_info),
1038                        "platform:%s", MEM2MEM_NAME);
1039        return 0;
1040}
1041
1042static int pxp_enum_fmt(struct v4l2_fmtdesc *f, u32 type)
1043{
1044        int i, num;
1045        struct pxp_fmt *fmt;
1046
1047        num = 0;
1048
1049        for (i = 0; i < NUM_FORMATS; ++i) {
1050                if (formats[i].types & type) {
1051                        /* index-th format of type type found ? */
1052                        if (num == f->index)
1053                                break;
1054                        /*
1055                         * Correct type but haven't reached our index yet,
1056                         * just increment per-type index
1057                         */
1058                        ++num;
1059                }
1060        }
1061
1062        if (i < NUM_FORMATS) {
1063                /* Format found */
1064                fmt = &formats[i];
1065                f->pixelformat = fmt->fourcc;
1066                return 0;
1067        }
1068
1069        /* Format not found */
1070        return -EINVAL;
1071}
1072
1073static int pxp_enum_fmt_vid_cap(struct file *file, void *priv,
1074                                struct v4l2_fmtdesc *f)
1075{
1076        return pxp_enum_fmt(f, MEM2MEM_CAPTURE);
1077}
1078
1079static int pxp_enum_fmt_vid_out(struct file *file, void *priv,
1080                                struct v4l2_fmtdesc *f)
1081{
1082        return pxp_enum_fmt(f, MEM2MEM_OUTPUT);
1083}
1084
1085static int pxp_g_fmt(struct pxp_ctx *ctx, struct v4l2_format *f)
1086{
1087        struct vb2_queue *vq;
1088        struct pxp_q_data *q_data;
1089
1090        vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
1091        if (!vq)
1092                return -EINVAL;
1093
1094        q_data = get_q_data(ctx, f->type);
1095
1096        f->fmt.pix.width        = q_data->width;
1097        f->fmt.pix.height       = q_data->height;
1098        f->fmt.pix.field        = V4L2_FIELD_NONE;
1099        f->fmt.pix.pixelformat  = q_data->fmt->fourcc;
1100        f->fmt.pix.bytesperline = q_data->bytesperline;
1101        f->fmt.pix.sizeimage    = q_data->sizeimage;
1102        f->fmt.pix.colorspace   = ctx->colorspace;
1103        f->fmt.pix.xfer_func    = ctx->xfer_func;
1104        f->fmt.pix.ycbcr_enc    = q_data->ycbcr_enc;
1105        f->fmt.pix.quantization = q_data->quant;
1106
1107        return 0;
1108}
1109
1110static int pxp_g_fmt_vid_out(struct file *file, void *priv,
1111                                struct v4l2_format *f)
1112{
1113        return pxp_g_fmt(file2ctx(file), f);
1114}
1115
1116static int pxp_g_fmt_vid_cap(struct file *file, void *priv,
1117                                struct v4l2_format *f)
1118{
1119        return pxp_g_fmt(file2ctx(file), f);
1120}
1121
1122static inline u32 pxp_bytesperline(struct pxp_fmt *fmt, u32 width)
1123{
1124        switch (fmt->fourcc) {
1125        case V4L2_PIX_FMT_YUV420:
1126        case V4L2_PIX_FMT_NV12:
1127        case V4L2_PIX_FMT_NV21:
1128        case V4L2_PIX_FMT_YUV422P:
1129        case V4L2_PIX_FMT_NV16:
1130        case V4L2_PIX_FMT_NV61:
1131                return width;
1132        default:
1133                return (width * fmt->depth) >> 3;
1134        }
1135}
1136
1137static inline u32 pxp_sizeimage(struct pxp_fmt *fmt, u32 width, u32 height)
1138{
1139        return (fmt->depth * width * height) >> 3;
1140}
1141
1142static int pxp_try_fmt(struct v4l2_format *f, struct pxp_fmt *fmt)
1143{
1144        v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W, ALIGN_W,
1145                              &f->fmt.pix.height, MIN_H, MAX_H, ALIGN_H, 0);
1146
1147        f->fmt.pix.bytesperline = pxp_bytesperline(fmt, f->fmt.pix.width);
1148        f->fmt.pix.sizeimage = pxp_sizeimage(fmt, f->fmt.pix.width,
1149                                             f->fmt.pix.height);
1150        f->fmt.pix.field = V4L2_FIELD_NONE;
1151
1152        return 0;
1153}
1154
1155static void
1156pxp_fixup_colorimetry_cap(struct pxp_ctx *ctx, u32 dst_fourcc,
1157                          enum v4l2_ycbcr_encoding *ycbcr_enc,
1158                          enum v4l2_quantization *quantization)
1159{
1160        bool dst_is_yuv = pxp_v4l2_pix_fmt_is_yuv(dst_fourcc);
1161
1162        if (pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) ==
1163            dst_is_yuv) {
1164                /*
1165                 * There is no support for conversion between different YCbCr
1166                 * encodings or between RGB limited and full range.
1167                 */
1168                *ycbcr_enc = ctx->q_data[V4L2_M2M_SRC].ycbcr_enc;
1169                *quantization = ctx->q_data[V4L2_M2M_SRC].quant;
1170        } else {
1171                *ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(ctx->colorspace);
1172                *quantization = V4L2_MAP_QUANTIZATION_DEFAULT(!dst_is_yuv,
1173                                                              ctx->colorspace,
1174                                                              *ycbcr_enc);
1175        }
1176}
1177
1178static int pxp_try_fmt_vid_cap(struct file *file, void *priv,
1179                               struct v4l2_format *f)
1180{
1181        struct pxp_fmt *fmt;
1182        struct pxp_ctx *ctx = file2ctx(file);
1183
1184        fmt = find_format(f);
1185        if (!fmt) {
1186                f->fmt.pix.pixelformat = formats[0].fourcc;
1187                fmt = find_format(f);
1188        }
1189        if (!(fmt->types & MEM2MEM_CAPTURE)) {
1190                v4l2_err(&ctx->dev->v4l2_dev,
1191                         "Fourcc format (0x%08x) invalid.\n",
1192                         f->fmt.pix.pixelformat);
1193                return -EINVAL;
1194        }
1195
1196        f->fmt.pix.colorspace = ctx->colorspace;
1197        f->fmt.pix.xfer_func = ctx->xfer_func;
1198
1199        pxp_fixup_colorimetry_cap(ctx, fmt->fourcc,
1200                                  &f->fmt.pix.ycbcr_enc,
1201                                  &f->fmt.pix.quantization);
1202
1203        return pxp_try_fmt(f, fmt);
1204}
1205
1206static int pxp_try_fmt_vid_out(struct file *file, void *priv,
1207                               struct v4l2_format *f)
1208{
1209        struct pxp_fmt *fmt;
1210        struct pxp_ctx *ctx = file2ctx(file);
1211
1212        fmt = find_format(f);
1213        if (!fmt) {
1214                f->fmt.pix.pixelformat = formats[0].fourcc;
1215                fmt = find_format(f);
1216        }
1217        if (!(fmt->types & MEM2MEM_OUTPUT)) {
1218                v4l2_err(&ctx->dev->v4l2_dev,
1219                         "Fourcc format (0x%08x) invalid.\n",
1220                         f->fmt.pix.pixelformat);
1221                return -EINVAL;
1222        }
1223
1224        if (!f->fmt.pix.colorspace)
1225                f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
1226
1227        return pxp_try_fmt(f, fmt);
1228}
1229
1230static int pxp_s_fmt(struct pxp_ctx *ctx, struct v4l2_format *f)
1231{
1232        struct pxp_q_data *q_data;
1233        struct vb2_queue *vq;
1234
1235        vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
1236        if (!vq)
1237                return -EINVAL;
1238
1239        q_data = get_q_data(ctx, f->type);
1240        if (!q_data)
1241                return -EINVAL;
1242
1243        if (vb2_is_busy(vq)) {
1244                v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
1245                return -EBUSY;
1246        }
1247
1248        q_data->fmt             = find_format(f);
1249        q_data->width           = f->fmt.pix.width;
1250        q_data->height          = f->fmt.pix.height;
1251        q_data->bytesperline    = f->fmt.pix.bytesperline;
1252        q_data->sizeimage       = f->fmt.pix.sizeimage;
1253
1254        dprintk(ctx->dev,
1255                "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
1256                f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
1257
1258        return 0;
1259}
1260
1261static int pxp_s_fmt_vid_cap(struct file *file, void *priv,
1262                             struct v4l2_format *f)
1263{
1264        struct pxp_ctx *ctx = file2ctx(file);
1265        int ret;
1266
1267        ret = pxp_try_fmt_vid_cap(file, priv, f);
1268        if (ret)
1269                return ret;
1270
1271        ret = pxp_s_fmt(file2ctx(file), f);
1272        if (ret)
1273                return ret;
1274
1275        ctx->q_data[V4L2_M2M_DST].ycbcr_enc = f->fmt.pix.ycbcr_enc;
1276        ctx->q_data[V4L2_M2M_DST].quant = f->fmt.pix.quantization;
1277
1278        return 0;
1279}
1280
1281static int pxp_s_fmt_vid_out(struct file *file, void *priv,
1282                             struct v4l2_format *f)
1283{
1284        struct pxp_ctx *ctx = file2ctx(file);
1285        int ret;
1286
1287        ret = pxp_try_fmt_vid_out(file, priv, f);
1288        if (ret)
1289                return ret;
1290
1291        ret = pxp_s_fmt(file2ctx(file), f);
1292        if (ret)
1293                return ret;
1294
1295        ctx->colorspace = f->fmt.pix.colorspace;
1296        ctx->xfer_func = f->fmt.pix.xfer_func;
1297        ctx->q_data[V4L2_M2M_SRC].ycbcr_enc = f->fmt.pix.ycbcr_enc;
1298        ctx->q_data[V4L2_M2M_SRC].quant = f->fmt.pix.quantization;
1299
1300        pxp_fixup_colorimetry_cap(ctx, ctx->q_data[V4L2_M2M_DST].fmt->fourcc,
1301                                  &ctx->q_data[V4L2_M2M_DST].ycbcr_enc,
1302                                  &ctx->q_data[V4L2_M2M_DST].quant);
1303
1304        return 0;
1305}
1306
1307static u8 pxp_degrees_to_rot_mode(u32 degrees)
1308{
1309        switch (degrees) {
1310        case 90:
1311                return BV_PXP_CTRL_ROTATE0__ROT_90;
1312        case 180:
1313                return BV_PXP_CTRL_ROTATE0__ROT_180;
1314        case 270:
1315                return BV_PXP_CTRL_ROTATE0__ROT_270;
1316        case 0:
1317        default:
1318                return BV_PXP_CTRL_ROTATE0__ROT_0;
1319        }
1320}
1321
1322static int pxp_s_ctrl(struct v4l2_ctrl *ctrl)
1323{
1324        struct pxp_ctx *ctx =
1325                container_of(ctrl->handler, struct pxp_ctx, hdl);
1326
1327        switch (ctrl->id) {
1328        case V4L2_CID_HFLIP:
1329                if (ctrl->val)
1330                        ctx->mode |= MEM2MEM_HFLIP;
1331                else
1332                        ctx->mode &= ~MEM2MEM_HFLIP;
1333                break;
1334
1335        case V4L2_CID_VFLIP:
1336                if (ctrl->val)
1337                        ctx->mode |= MEM2MEM_VFLIP;
1338                else
1339                        ctx->mode &= ~MEM2MEM_VFLIP;
1340                break;
1341
1342        case V4L2_CID_ROTATE:
1343                ctx->rotation = pxp_degrees_to_rot_mode(ctrl->val);
1344                break;
1345
1346        case V4L2_CID_ALPHA_COMPONENT:
1347                ctx->alpha_component = ctrl->val;
1348                break;
1349
1350        default:
1351                v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
1352                return -EINVAL;
1353        }
1354
1355        return 0;
1356}
1357
1358static const struct v4l2_ctrl_ops pxp_ctrl_ops = {
1359        .s_ctrl = pxp_s_ctrl,
1360};
1361
1362static const struct v4l2_ioctl_ops pxp_ioctl_ops = {
1363        .vidioc_querycap        = pxp_querycap,
1364
1365        .vidioc_enum_fmt_vid_cap = pxp_enum_fmt_vid_cap,
1366        .vidioc_g_fmt_vid_cap   = pxp_g_fmt_vid_cap,
1367        .vidioc_try_fmt_vid_cap = pxp_try_fmt_vid_cap,
1368        .vidioc_s_fmt_vid_cap   = pxp_s_fmt_vid_cap,
1369
1370        .vidioc_enum_fmt_vid_out = pxp_enum_fmt_vid_out,
1371        .vidioc_g_fmt_vid_out   = pxp_g_fmt_vid_out,
1372        .vidioc_try_fmt_vid_out = pxp_try_fmt_vid_out,
1373        .vidioc_s_fmt_vid_out   = pxp_s_fmt_vid_out,
1374
1375        .vidioc_reqbufs         = v4l2_m2m_ioctl_reqbufs,
1376        .vidioc_querybuf        = v4l2_m2m_ioctl_querybuf,
1377        .vidioc_qbuf            = v4l2_m2m_ioctl_qbuf,
1378        .vidioc_dqbuf           = v4l2_m2m_ioctl_dqbuf,
1379        .vidioc_prepare_buf     = v4l2_m2m_ioctl_prepare_buf,
1380        .vidioc_create_bufs     = v4l2_m2m_ioctl_create_bufs,
1381        .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
1382
1383        .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
1384        .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
1385
1386        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
1387        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1388};
1389
1390/*
1391 * Queue operations
1392 */
1393static int pxp_queue_setup(struct vb2_queue *vq,
1394                           unsigned int *nbuffers, unsigned int *nplanes,
1395                           unsigned int sizes[], struct device *alloc_devs[])
1396{
1397        struct pxp_ctx *ctx = vb2_get_drv_priv(vq);
1398        struct pxp_q_data *q_data;
1399        unsigned int size, count = *nbuffers;
1400
1401        q_data = get_q_data(ctx, vq->type);
1402
1403        size = q_data->sizeimage;
1404
1405        *nbuffers = count;
1406
1407        if (*nplanes)
1408                return sizes[0] < size ? -EINVAL : 0;
1409
1410        *nplanes = 1;
1411        sizes[0] = size;
1412
1413        dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
1414
1415        return 0;
1416}
1417
1418static int pxp_buf_prepare(struct vb2_buffer *vb)
1419{
1420        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1421        struct pxp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1422        struct pxp_dev *dev = ctx->dev;
1423        struct pxp_q_data *q_data;
1424
1425        dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
1426
1427        q_data = get_q_data(ctx, vb->vb2_queue->type);
1428        if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1429                if (vbuf->field == V4L2_FIELD_ANY)
1430                        vbuf->field = V4L2_FIELD_NONE;
1431                if (vbuf->field != V4L2_FIELD_NONE) {
1432                        dprintk(dev, "%s field isn't supported\n", __func__);
1433                        return -EINVAL;
1434                }
1435        }
1436
1437        if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
1438                dprintk(dev, "%s data will not fit into plane (%lu < %lu)\n",
1439                        __func__, vb2_plane_size(vb, 0),
1440                        (long)q_data->sizeimage);
1441                return -EINVAL;
1442        }
1443
1444        vb2_set_plane_payload(vb, 0, q_data->sizeimage);
1445
1446        return 0;
1447}
1448
1449static void pxp_buf_queue(struct vb2_buffer *vb)
1450{
1451        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1452        struct pxp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1453
1454        v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1455}
1456
1457static int pxp_start_streaming(struct vb2_queue *q, unsigned int count)
1458{
1459        struct pxp_ctx *ctx = vb2_get_drv_priv(q);
1460        struct pxp_q_data *q_data = get_q_data(ctx, q->type);
1461
1462        q_data->sequence = 0;
1463        return 0;
1464}
1465
1466static void pxp_stop_streaming(struct vb2_queue *q)
1467{
1468        struct pxp_ctx *ctx = vb2_get_drv_priv(q);
1469        struct vb2_v4l2_buffer *vbuf;
1470        unsigned long flags;
1471
1472        for (;;) {
1473                if (V4L2_TYPE_IS_OUTPUT(q->type))
1474                        vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
1475                else
1476                        vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
1477                if (vbuf == NULL)
1478                        return;
1479                spin_lock_irqsave(&ctx->dev->irqlock, flags);
1480                v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
1481                spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
1482        }
1483}
1484
1485static const struct vb2_ops pxp_qops = {
1486        .queue_setup     = pxp_queue_setup,
1487        .buf_prepare     = pxp_buf_prepare,
1488        .buf_queue       = pxp_buf_queue,
1489        .start_streaming = pxp_start_streaming,
1490        .stop_streaming  = pxp_stop_streaming,
1491        .wait_prepare    = vb2_ops_wait_prepare,
1492        .wait_finish     = vb2_ops_wait_finish,
1493};
1494
1495static int queue_init(void *priv, struct vb2_queue *src_vq,
1496                      struct vb2_queue *dst_vq)
1497{
1498        struct pxp_ctx *ctx = priv;
1499        int ret;
1500
1501        src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1502        src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
1503        src_vq->drv_priv = ctx;
1504        src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1505        src_vq->ops = &pxp_qops;
1506        src_vq->mem_ops = &vb2_dma_contig_memops;
1507        src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1508        src_vq->lock = &ctx->dev->dev_mutex;
1509        src_vq->dev = ctx->dev->v4l2_dev.dev;
1510
1511        ret = vb2_queue_init(src_vq);
1512        if (ret)
1513                return ret;
1514
1515        dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1516        dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
1517        dst_vq->drv_priv = ctx;
1518        dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1519        dst_vq->ops = &pxp_qops;
1520        dst_vq->mem_ops = &vb2_dma_contig_memops;
1521        dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1522        dst_vq->lock = &ctx->dev->dev_mutex;
1523        dst_vq->dev = ctx->dev->v4l2_dev.dev;
1524
1525        return vb2_queue_init(dst_vq);
1526}
1527
1528/*
1529 * File operations
1530 */
1531static int pxp_open(struct file *file)
1532{
1533        struct pxp_dev *dev = video_drvdata(file);
1534        struct pxp_ctx *ctx = NULL;
1535        struct v4l2_ctrl_handler *hdl;
1536        int rc = 0;
1537
1538        if (mutex_lock_interruptible(&dev->dev_mutex))
1539                return -ERESTARTSYS;
1540        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1541        if (!ctx) {
1542                rc = -ENOMEM;
1543                goto open_unlock;
1544        }
1545
1546        v4l2_fh_init(&ctx->fh, video_devdata(file));
1547        file->private_data = &ctx->fh;
1548        ctx->dev = dev;
1549        hdl = &ctx->hdl;
1550        v4l2_ctrl_handler_init(hdl, 4);
1551        v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
1552        v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
1553        v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
1554        v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
1555                          0, 255, 1, 255);
1556        if (hdl->error) {
1557                rc = hdl->error;
1558                v4l2_ctrl_handler_free(hdl);
1559                kfree(ctx);
1560                goto open_unlock;
1561        }
1562        ctx->fh.ctrl_handler = hdl;
1563        v4l2_ctrl_handler_setup(hdl);
1564
1565        ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
1566        ctx->q_data[V4L2_M2M_SRC].width = 640;
1567        ctx->q_data[V4L2_M2M_SRC].height = 480;
1568        ctx->q_data[V4L2_M2M_SRC].bytesperline =
1569                pxp_bytesperline(&formats[0], 640);
1570        ctx->q_data[V4L2_M2M_SRC].sizeimage =
1571                pxp_sizeimage(&formats[0], 640, 480);
1572        ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
1573        ctx->colorspace = V4L2_COLORSPACE_REC709;
1574
1575        ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
1576
1577        if (IS_ERR(ctx->fh.m2m_ctx)) {
1578                rc = PTR_ERR(ctx->fh.m2m_ctx);
1579
1580                v4l2_ctrl_handler_free(hdl);
1581                v4l2_fh_exit(&ctx->fh);
1582                kfree(ctx);
1583                goto open_unlock;
1584        }
1585
1586        v4l2_fh_add(&ctx->fh);
1587        atomic_inc(&dev->num_inst);
1588
1589        dprintk(dev, "Created instance: %p, m2m_ctx: %p\n",
1590                ctx, ctx->fh.m2m_ctx);
1591
1592open_unlock:
1593        mutex_unlock(&dev->dev_mutex);
1594        return rc;
1595}
1596
1597static int pxp_release(struct file *file)
1598{
1599        struct pxp_dev *dev = video_drvdata(file);
1600        struct pxp_ctx *ctx = file2ctx(file);
1601
1602        dprintk(dev, "Releasing instance %p\n", ctx);
1603
1604        v4l2_fh_del(&ctx->fh);
1605        v4l2_fh_exit(&ctx->fh);
1606        v4l2_ctrl_handler_free(&ctx->hdl);
1607        mutex_lock(&dev->dev_mutex);
1608        v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1609        mutex_unlock(&dev->dev_mutex);
1610        kfree(ctx);
1611
1612        atomic_dec(&dev->num_inst);
1613
1614        return 0;
1615}
1616
1617static const struct v4l2_file_operations pxp_fops = {
1618        .owner          = THIS_MODULE,
1619        .open           = pxp_open,
1620        .release        = pxp_release,
1621        .poll           = v4l2_m2m_fop_poll,
1622        .unlocked_ioctl = video_ioctl2,
1623        .mmap           = v4l2_m2m_fop_mmap,
1624};
1625
1626static const struct video_device pxp_videodev = {
1627        .name           = MEM2MEM_NAME,
1628        .vfl_dir        = VFL_DIR_M2M,
1629        .fops           = &pxp_fops,
1630        .device_caps    = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
1631        .ioctl_ops      = &pxp_ioctl_ops,
1632        .minor          = -1,
1633        .release        = video_device_release_empty,
1634};
1635
1636static const struct v4l2_m2m_ops m2m_ops = {
1637        .device_run     = pxp_device_run,
1638        .job_ready      = pxp_job_ready,
1639        .job_abort      = pxp_job_abort,
1640};
1641
1642static int pxp_soft_reset(struct pxp_dev *dev)
1643{
1644        int ret;
1645        u32 val;
1646
1647        writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR);
1648        writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR);
1649
1650        writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_SET);
1651
1652        ret = readl_poll_timeout(dev->mmio + HW_PXP_CTRL, val,
1653                                 val & BM_PXP_CTRL_CLKGATE, 0, 100);
1654        if (ret < 0)
1655                return ret;
1656
1657        writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR);
1658        writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR);
1659
1660        return 0;
1661}
1662
1663static int pxp_probe(struct platform_device *pdev)
1664{
1665        struct pxp_dev *dev;
1666        struct video_device *vfd;
1667        int irq;
1668        int ret;
1669
1670        dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
1671        if (!dev)
1672                return -ENOMEM;
1673
1674        dev->clk = devm_clk_get(&pdev->dev, "axi");
1675        if (IS_ERR(dev->clk)) {
1676                ret = PTR_ERR(dev->clk);
1677                dev_err(&pdev->dev, "Failed to get clk: %d\n", ret);
1678                return ret;
1679        }
1680
1681        dev->mmio = devm_platform_ioremap_resource(pdev, 0);
1682        if (IS_ERR(dev->mmio))
1683                return PTR_ERR(dev->mmio);
1684
1685        irq = platform_get_irq(pdev, 0);
1686        if (irq < 0)
1687                return irq;
1688
1689        spin_lock_init(&dev->irqlock);
1690
1691        ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, pxp_irq_handler,
1692                        IRQF_ONESHOT, dev_name(&pdev->dev), dev);
1693        if (ret < 0) {
1694                dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
1695                return ret;
1696        }
1697
1698        ret = clk_prepare_enable(dev->clk);
1699        if (ret < 0)
1700                return ret;
1701
1702        ret = pxp_soft_reset(dev);
1703        if (ret < 0) {
1704                dev_err(&pdev->dev, "PXP reset timeout: %d\n", ret);
1705                goto err_clk;
1706        }
1707
1708        ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
1709        if (ret)
1710                goto err_clk;
1711
1712        atomic_set(&dev->num_inst, 0);
1713        mutex_init(&dev->dev_mutex);
1714
1715        dev->vfd = pxp_videodev;
1716        vfd = &dev->vfd;
1717        vfd->lock = &dev->dev_mutex;
1718        vfd->v4l2_dev = &dev->v4l2_dev;
1719
1720        video_set_drvdata(vfd, dev);
1721        snprintf(vfd->name, sizeof(vfd->name), "%s", pxp_videodev.name);
1722        v4l2_info(&dev->v4l2_dev,
1723                        "Device registered as /dev/video%d\n", vfd->num);
1724
1725        platform_set_drvdata(pdev, dev);
1726
1727        dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
1728        if (IS_ERR(dev->m2m_dev)) {
1729                v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
1730                ret = PTR_ERR(dev->m2m_dev);
1731                goto err_v4l2;
1732        }
1733
1734        ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
1735        if (ret) {
1736                v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1737                goto err_m2m;
1738        }
1739
1740        return 0;
1741
1742err_m2m:
1743        v4l2_m2m_release(dev->m2m_dev);
1744err_v4l2:
1745        v4l2_device_unregister(&dev->v4l2_dev);
1746err_clk:
1747        clk_disable_unprepare(dev->clk);
1748
1749        return ret;
1750}
1751
1752static int pxp_remove(struct platform_device *pdev)
1753{
1754        struct pxp_dev *dev = platform_get_drvdata(pdev);
1755
1756        writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_SET);
1757        writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_SET);
1758
1759        clk_disable_unprepare(dev->clk);
1760
1761        v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
1762        video_unregister_device(&dev->vfd);
1763        v4l2_m2m_release(dev->m2m_dev);
1764        v4l2_device_unregister(&dev->v4l2_dev);
1765
1766        return 0;
1767}
1768
1769static const struct of_device_id pxp_dt_ids[] = {
1770        { .compatible = "fsl,imx6ull-pxp", .data = NULL },
1771        { },
1772};
1773MODULE_DEVICE_TABLE(of, pxp_dt_ids);
1774
1775static struct platform_driver pxp_driver = {
1776        .probe          = pxp_probe,
1777        .remove         = pxp_remove,
1778        .driver         = {
1779                .name   = MEM2MEM_NAME,
1780                .of_match_table = pxp_dt_ids,
1781        },
1782};
1783
1784module_platform_driver(pxp_driver);
1785
1786MODULE_DESCRIPTION("i.MX PXP mem2mem scaler/CSC/rotator");
1787MODULE_AUTHOR("Philipp Zabel <kernel@pengutronix.de>");
1788MODULE_LICENSE("GPL");
1789