linux/drivers/gpu/ipu-v3/ipu-ic-csc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2019 Mentor Graphics Inc.
   4 */
   5
   6#include <linux/types.h>
   7#include <linux/init.h>
   8#include <linux/errno.h>
   9#include <linux/err.h>
  10#include <linux/sizes.h>
  11#include "ipu-prv.h"
  12
  13#define QUANT_MAP(q)                                    \
  14        ((q) == V4L2_QUANTIZATION_FULL_RANGE ||         \
  15         (q) == V4L2_QUANTIZATION_DEFAULT ? 0 : 1)
  16
  17/* identity matrix */
  18static const struct ipu_ic_csc_params identity = {
  19        .coeff = {
  20                {  128,    0,    0, },
  21                {    0,  128,    0, },
  22                {    0,    0,  128, },
  23        },
  24        .offset = { 0, 0, 0, },
  25        .scale = 2,
  26};
  27
  28/*
  29 * RGB full-range to RGB limited-range
  30 *
  31 * R_lim = 0.8588 * R_full + 16
  32 * G_lim = 0.8588 * G_full + 16
  33 * B_lim = 0.8588 * B_full + 16
  34 */
  35static const struct ipu_ic_csc_params rgbf2rgbl = {
  36        .coeff = {
  37                {  220,    0,    0, },
  38                {    0,  220,    0, },
  39                {    0,    0,  220, },
  40        },
  41        .offset = { 64, 64, 64, },
  42        .scale = 1,
  43};
  44
  45/*
  46 * RGB limited-range to RGB full-range
  47 *
  48 * R_full = 1.1644 * (R_lim - 16)
  49 * G_full = 1.1644 * (G_lim - 16)
  50 * B_full = 1.1644 * (B_lim - 16)
  51 */
  52static const struct ipu_ic_csc_params rgbl2rgbf = {
  53        .coeff = {
  54                {  149,    0,    0, },
  55                {    0,  149,    0, },
  56                {    0,    0,  149, },
  57        },
  58        .offset = { -37, -37, -37, },
  59        .scale = 2,
  60};
  61
  62/*
  63 * YUV full-range to YUV limited-range
  64 *
  65 * Y_lim  = 0.8588 * Y_full + 16
  66 * Cb_lim = 0.8784 * (Cb_full - 128) + 128
  67 * Cr_lim = 0.8784 * (Cr_full - 128) + 128
  68 */
  69static const struct ipu_ic_csc_params yuvf2yuvl = {
  70        .coeff = {
  71                {  220,    0,    0, },
  72                {    0,  225,    0, },
  73                {    0,    0,  225, },
  74        },
  75        .offset = { 64, 62, 62, },
  76        .scale = 1,
  77        .sat = true,
  78};
  79
  80/*
  81 * YUV limited-range to YUV full-range
  82 *
  83 * Y_full  = 1.1644 * (Y_lim - 16)
  84 * Cb_full = 1.1384 * (Cb_lim - 128) + 128
  85 * Cr_full = 1.1384 * (Cr_lim - 128) + 128
  86 */
  87static const struct ipu_ic_csc_params yuvl2yuvf = {
  88        .coeff = {
  89                {  149,    0,    0, },
  90                {    0,  146,    0, },
  91                {    0,    0,  146, },
  92        },
  93        .offset = { -37, -35, -35, },
  94        .scale = 2,
  95};
  96
  97static const struct ipu_ic_csc_params *rgb2rgb[] = {
  98        &identity,
  99        &rgbf2rgbl,
 100        &rgbl2rgbf,
 101        &identity,
 102};
 103
 104static const struct ipu_ic_csc_params *yuv2yuv[] = {
 105        &identity,
 106        &yuvf2yuvl,
 107        &yuvl2yuvf,
 108        &identity,
 109};
 110
 111/*
 112 * BT.601 RGB full-range to YUV full-range
 113 *
 114 * Y =  .2990 * R + .5870 * G + .1140 * B
 115 * U = -.1687 * R - .3313 * G + .5000 * B + 128
 116 * V =  .5000 * R - .4187 * G - .0813 * B + 128
 117 */
 118static const struct ipu_ic_csc_params rgbf2yuvf_601 = {
 119        .coeff = {
 120                {   77,  150,   29, },
 121                {  -43,  -85,  128, },
 122                {  128, -107,  -21, },
 123        },
 124        .offset = { 0, 512, 512, },
 125        .scale = 1,
 126};
 127
 128/* BT.601 RGB full-range to YUV limited-range */
 129static const struct ipu_ic_csc_params rgbf2yuvl_601 = {
 130        .coeff = {
 131                {   66,  129,   25, },
 132                {  -38,  -74,  112, },
 133                {  112,  -94,  -18, },
 134        },
 135        .offset = { 64, 512, 512, },
 136        .scale = 1,
 137        .sat = true,
 138};
 139
 140/* BT.601 RGB limited-range to YUV full-range */
 141static const struct ipu_ic_csc_params rgbl2yuvf_601 = {
 142        .coeff = {
 143                {   89,  175,   34, },
 144                {  -50,  -99,  149, },
 145                {  149, -125,  -24, },
 146        },
 147        .offset = { -75, 512, 512, },
 148        .scale = 1,
 149};
 150
 151/* BT.601 RGB limited-range to YUV limited-range */
 152static const struct ipu_ic_csc_params rgbl2yuvl_601 = {
 153        .coeff = {
 154                {   77,  150,   29, },
 155                {  -44,  -87,  131, },
 156                {  131, -110,  -21, },
 157        },
 158        .offset = { 0, 512, 512, },
 159        .scale = 1,
 160        .sat = true,
 161};
 162
 163/*
 164 * BT.601 YUV full-range to RGB full-range
 165 *
 166 * R = 1. * Y +      0 * (Cb - 128) + 1.4020 * (Cr - 128)
 167 * G = 1. * Y -  .3441 * (Cb - 128) -  .7141 * (Cr - 128)
 168 * B = 1. * Y + 1.7720 * (Cb - 128) +      0 * (Cr - 128)
 169 *
 170 * equivalently (factoring out the offsets):
 171 *
 172 * R = 1. * Y  +      0 * Cb + 1.4020 * Cr - 179.456
 173 * G = 1. * Y  -  .3441 * Cb -  .7141 * Cr + 135.450
 174 * B = 1. * Y  + 1.7720 * Cb +      0 * Cr - 226.816
 175 */
 176static const struct ipu_ic_csc_params yuvf2rgbf_601 = {
 177        .coeff = {
 178                {  128,    0,  179, },
 179                {  128,  -44,  -91, },
 180                {  128,  227,    0, },
 181        },
 182        .offset = { -359, 271, -454, },
 183        .scale = 2,
 184};
 185
 186/* BT.601 YUV full-range to RGB limited-range */
 187static const struct ipu_ic_csc_params yuvf2rgbl_601 = {
 188        .coeff = {
 189                {  110,    0,  154, },
 190                {  110,  -38,  -78, },
 191                {  110,  195,    0, },
 192        },
 193        .offset = { -276, 265, -358, },
 194        .scale = 2,
 195};
 196
 197/* BT.601 YUV limited-range to RGB full-range */
 198static const struct ipu_ic_csc_params yuvl2rgbf_601 = {
 199        .coeff = {
 200                {   75,    0,  102, },
 201                {   75,  -25,  -52, },
 202                {   75,  129,    0, },
 203        },
 204        .offset = { -223, 136, -277, },
 205        .scale = 3,
 206};
 207
 208/* BT.601 YUV limited-range to RGB limited-range */
 209static const struct ipu_ic_csc_params yuvl2rgbl_601 = {
 210        .coeff = {
 211                {  128,    0,  175, },
 212                {  128,  -43,  -89, },
 213                {  128,  222,    0, },
 214        },
 215        .offset = { -351, 265, -443, },
 216        .scale = 2,
 217};
 218
 219static const struct ipu_ic_csc_params *rgb2yuv_601[] = {
 220        &rgbf2yuvf_601,
 221        &rgbf2yuvl_601,
 222        &rgbl2yuvf_601,
 223        &rgbl2yuvl_601,
 224};
 225
 226static const struct ipu_ic_csc_params *yuv2rgb_601[] = {
 227        &yuvf2rgbf_601,
 228        &yuvf2rgbl_601,
 229        &yuvl2rgbf_601,
 230        &yuvl2rgbl_601,
 231};
 232
 233/*
 234 * REC.709 encoding from RGB full range to YUV full range:
 235 *
 236 * Y =  .2126 * R + .7152 * G + .0722 * B
 237 * U = -.1146 * R - .3854 * G + .5000 * B + 128
 238 * V =  .5000 * R - .4542 * G - .0458 * B + 128
 239 */
 240static const struct ipu_ic_csc_params rgbf2yuvf_709 = {
 241        .coeff = {
 242                {  54,  183,  19 },
 243                { -29,  -99, 128 },
 244                { 128, -116, -12 },
 245        },
 246        .offset = { 0, 512, 512 },
 247        .scale = 1,
 248};
 249
 250/* Rec.709 RGB full-range to YUV limited-range */
 251static const struct ipu_ic_csc_params rgbf2yuvl_709 = {
 252        .coeff = {
 253                {   47,  157,   16, },
 254                {  -26,  -87,  112, },
 255                {  112, -102,  -10, },
 256        },
 257        .offset = { 64, 512, 512, },
 258        .scale = 1,
 259        .sat = true,
 260};
 261
 262/* Rec.709 RGB limited-range to YUV full-range */
 263static const struct ipu_ic_csc_params rgbl2yuvf_709 = {
 264        .coeff = {
 265                {   63,  213,   22, },
 266                {  -34, -115,  149, },
 267                {  149, -135,  -14, },
 268        },
 269        .offset = { -75, 512, 512, },
 270        .scale = 1,
 271};
 272
 273/* Rec.709 RGB limited-range to YUV limited-range */
 274static const struct ipu_ic_csc_params rgbl2yuvl_709 = {
 275        .coeff = {
 276                {   54,  183,   18, },
 277                {  -30, -101,  131, },
 278                {  131, -119,  -12, },
 279        },
 280        .offset = { 0, 512, 512, },
 281        .scale = 1,
 282        .sat = true,
 283};
 284
 285/*
 286 * Inverse REC.709 encoding from YUV full range to RGB full range:
 287 *
 288 * R = 1. * Y +      0 * (Cb - 128) + 1.5748 * (Cr - 128)
 289 * G = 1. * Y -  .1873 * (Cb - 128) -  .4681 * (Cr - 128)
 290 * B = 1. * Y + 1.8556 * (Cb - 128) +      0 * (Cr - 128)
 291 *
 292 * equivalently (factoring out the offsets):
 293 *
 294 * R = 1. * Y  +      0 * Cb + 1.5748 * Cr - 201.574
 295 * G = 1. * Y  -  .1873 * Cb -  .4681 * Cr +  83.891
 296 * B = 1. * Y  + 1.8556 * Cb +      0 * Cr - 237.517
 297 */
 298static const struct ipu_ic_csc_params yuvf2rgbf_709 = {
 299        .coeff = {
 300                {  128,   0, 202 },
 301                {  128, -24, -60 },
 302                {  128, 238,   0 },
 303        },
 304        .offset = { -403, 168, -475 },
 305        .scale = 2,
 306};
 307
 308/* Rec.709 YUV full-range to RGB limited-range */
 309static const struct ipu_ic_csc_params yuvf2rgbl_709 = {
 310        .coeff = {
 311                {  110,    0,  173, },
 312                {  110,  -21,  -51, },
 313                {  110,  204,    0, },
 314        },
 315        .offset = { -314, 176, -376, },
 316        .scale = 2,
 317};
 318
 319/* Rec.709 YUV limited-range to RGB full-range */
 320static const struct ipu_ic_csc_params yuvl2rgbf_709 = {
 321        .coeff = {
 322                {   75,    0,  115, },
 323                {   75,  -14,  -34, },
 324                {   75,  135,    0, },
 325        },
 326        .offset = { -248, 77, -289, },
 327        .scale = 3,
 328};
 329
 330/* Rec.709 YUV limited-range to RGB limited-range */
 331static const struct ipu_ic_csc_params yuvl2rgbl_709 = {
 332        .coeff = {
 333                {  128,    0,  197, },
 334                {  128,  -23,  -59, },
 335                {  128,  232,    0, },
 336        },
 337        .offset = { -394, 164, -464, },
 338        .scale = 2,
 339};
 340
 341static const struct ipu_ic_csc_params *rgb2yuv_709[] = {
 342        &rgbf2yuvf_709,
 343        &rgbf2yuvl_709,
 344        &rgbl2yuvf_709,
 345        &rgbl2yuvl_709,
 346};
 347
 348static const struct ipu_ic_csc_params *yuv2rgb_709[] = {
 349        &yuvf2rgbf_709,
 350        &yuvf2rgbl_709,
 351        &yuvl2rgbf_709,
 352        &yuvl2rgbl_709,
 353};
 354
 355static int calc_csc_coeffs(struct ipu_ic_csc *csc)
 356{
 357        const struct ipu_ic_csc_params **params_tbl;
 358        int tbl_idx;
 359
 360        tbl_idx = (QUANT_MAP(csc->in_cs.quant) << 1) |
 361                QUANT_MAP(csc->out_cs.quant);
 362
 363        if (csc->in_cs.cs == csc->out_cs.cs) {
 364                csc->params = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ?
 365                        *yuv2yuv[tbl_idx] : *rgb2rgb[tbl_idx];
 366
 367                return 0;
 368        }
 369
 370        /* YUV <-> RGB encoding is required */
 371
 372        switch (csc->out_cs.enc) {
 373        case V4L2_YCBCR_ENC_601:
 374                params_tbl = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ?
 375                        yuv2rgb_601 : rgb2yuv_601;
 376                break;
 377        case V4L2_YCBCR_ENC_709:
 378                params_tbl = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ?
 379                        yuv2rgb_709 : rgb2yuv_709;
 380                break;
 381        default:
 382                return -ENOTSUPP;
 383        }
 384
 385        csc->params = *params_tbl[tbl_idx];
 386
 387        return 0;
 388}
 389
 390int __ipu_ic_calc_csc(struct ipu_ic_csc *csc)
 391{
 392        return calc_csc_coeffs(csc);
 393}
 394EXPORT_SYMBOL_GPL(__ipu_ic_calc_csc);
 395
 396int ipu_ic_calc_csc(struct ipu_ic_csc *csc,
 397                    enum v4l2_ycbcr_encoding in_enc,
 398                    enum v4l2_quantization in_quant,
 399                    enum ipu_color_space in_cs,
 400                    enum v4l2_ycbcr_encoding out_enc,
 401                    enum v4l2_quantization out_quant,
 402                    enum ipu_color_space out_cs)
 403{
 404        ipu_ic_fill_colorspace(&csc->in_cs, in_enc, in_quant, in_cs);
 405        ipu_ic_fill_colorspace(&csc->out_cs, out_enc, out_quant, out_cs);
 406
 407        return __ipu_ic_calc_csc(csc);
 408}
 409EXPORT_SYMBOL_GPL(ipu_ic_calc_csc);
 410