// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright ( C ) 2019 Mentor Graphics Inc .
*/
#include <linux/types.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/sizes.h>
#include "ipu-prv.h"
#define QUANT_MAP(q) \
((q) == V4L2_QUANTIZATION_FULL_RANGE || \
(q) == V4L2_QUANTIZATION_DEFAULT ? 0 : 1 )
/* identity matrix */
static const struct ipu_ic_csc_params identity = {
.coeff = {
{ 128 , 0 , 0 , },
{ 0 , 128 , 0 , },
{ 0 , 0 , 128 , },
},
.offset = { 0 , 0 , 0 , },
.scale = 2 ,
};
/*
* RGB full - range to RGB limited - range
*
* R_lim = 0 . 8588 * R_full + 16
* G_lim = 0 . 8588 * G_full + 16
* B_lim = 0 . 8588 * B_full + 16
*/
static const struct ipu_ic_csc_params rgbf2rgbl = {
.coeff = {
{ 220 , 0 , 0 , },
{ 0 , 220 , 0 , },
{ 0 , 0 , 220 , },
},
.offset = { 64 , 64 , 64 , },
.scale = 1 ,
};
/*
* RGB limited - range to RGB full - range
*
* R_full = 1 . 1644 * ( R_lim - 16 )
* G_full = 1 . 1644 * ( G_lim - 16 )
* B_full = 1 . 1644 * ( B_lim - 16 )
*/
static const struct ipu_ic_csc_params rgbl2rgbf = {
.coeff = {
{ 149 , 0 , 0 , },
{ 0 , 149 , 0 , },
{ 0 , 0 , 149 , },
},
.offset = { -37 , -37 , -37 , },
.scale = 2 ,
};
/*
* YUV full - range to YUV limited - range
*
* Y_lim = 0 . 8588 * Y_full + 16
* Cb_lim = 0 . 8784 * ( Cb_full - 128 ) + 128
* Cr_lim = 0 . 8784 * ( Cr_full - 128 ) + 128
*/
static const struct ipu_ic_csc_params yuvf2yuvl = {
.coeff = {
{ 220 , 0 , 0 , },
{ 0 , 225 , 0 , },
{ 0 , 0 , 225 , },
},
.offset = { 64 , 62 , 62 , },
.scale = 1 ,
.sat = true ,
};
/*
* YUV limited - range to YUV full - range
*
* Y_full = 1 . 1644 * ( Y_lim - 16 )
* Cb_full = 1 . 1384 * ( Cb_lim - 128 ) + 128
* Cr_full = 1 . 1384 * ( Cr_lim - 128 ) + 128
*/
static const struct ipu_ic_csc_params yuvl2yuvf = {
.coeff = {
{ 149 , 0 , 0 , },
{ 0 , 146 , 0 , },
{ 0 , 0 , 146 , },
},
.offset = { -37 , -35 , -35 , },
.scale = 2 ,
};
static const struct ipu_ic_csc_params *rgb2rgb[] = {
&identity,
&rgbf2rgbl,
&rgbl2rgbf,
&identity,
};
static const struct ipu_ic_csc_params *yuv2yuv[] = {
&identity,
&yuvf2yuvl,
&yuvl2yuvf,
&identity,
};
/*
* BT . 601 RGB full - range to YUV full - range
*
* Y = . 2990 * R + . 5870 * G + . 1140 * B
* U = - . 1687 * R - . 3313 * G + . 5000 * B + 128
* V = . 5000 * R - . 4187 * G - . 0813 * B + 128
*/
static const struct ipu_ic_csc_params rgbf2yuvf_601 = {
.coeff = {
{ 77 , 150 , 29 , },
{ -43 , -85 , 128 , },
{ 128 , -107 , -21 , },
},
.offset = { 0 , 512 , 512 , },
.scale = 1 ,
};
/* BT.601 RGB full-range to YUV limited-range */
static const struct ipu_ic_csc_params rgbf2yuvl_601 = {
.coeff = {
{ 66 , 129 , 25 , },
{ -38 , -74 , 112 , },
{ 112 , -94 , -18 , },
},
.offset = { 64 , 512 , 512 , },
.scale = 1 ,
.sat = true ,
};
/* BT.601 RGB limited-range to YUV full-range */
static const struct ipu_ic_csc_params rgbl2yuvf_601 = {
.coeff = {
{ 89 , 175 , 34 , },
{ -50 , -99 , 149 , },
{ 149 , -125 , -24 , },
},
.offset = { -75 , 512 , 512 , },
.scale = 1 ,
};
/* BT.601 RGB limited-range to YUV limited-range */
static const struct ipu_ic_csc_params rgbl2yuvl_601 = {
.coeff = {
{ 77 , 150 , 29 , },
{ -44 , -87 , 131 , },
{ 131 , -110 , -21 , },
},
.offset = { 0 , 512 , 512 , },
.scale = 1 ,
.sat = true ,
};
/*
* BT . 601 YUV full - range to RGB full - range
*
* R = 1 . * Y + 0 * ( Cb - 128 ) + 1 . 4020 * ( Cr - 128 )
* G = 1 . * Y - . 3441 * ( Cb - 128 ) - . 7141 * ( Cr - 128 )
* B = 1 . * Y + 1 . 7720 * ( Cb - 128 ) + 0 * ( Cr - 128 )
*
* equivalently ( factoring out the offsets ) :
*
* R = 1 . * Y + 0 * Cb + 1 . 4020 * Cr - 179 . 456
* G = 1 . * Y - . 3441 * Cb - . 7141 * Cr + 135 . 450
* B = 1 . * Y + 1 . 7720 * Cb + 0 * Cr - 226 . 816
*/
static const struct ipu_ic_csc_params yuvf2rgbf_601 = {
.coeff = {
{ 128 , 0 , 179 , },
{ 128 , -44 , -91 , },
{ 128 , 227 , 0 , },
},
.offset = { -359 , 271 , -454 , },
.scale = 2 ,
};
/* BT.601 YUV full-range to RGB limited-range */
static const struct ipu_ic_csc_params yuvf2rgbl_601 = {
.coeff = {
{ 110 , 0 , 154 , },
{ 110 , -38 , -78 , },
{ 110 , 195 , 0 , },
},
.offset = { -276 , 265 , -358 , },
.scale = 2 ,
};
/* BT.601 YUV limited-range to RGB full-range */
static const struct ipu_ic_csc_params yuvl2rgbf_601 = {
.coeff = {
{ 75 , 0 , 102 , },
{ 75 , -25 , -52 , },
{ 75 , 129 , 0 , },
},
.offset = { -223 , 136 , -277 , },
.scale = 3 ,
};
/* BT.601 YUV limited-range to RGB limited-range */
static const struct ipu_ic_csc_params yuvl2rgbl_601 = {
.coeff = {
{ 128 , 0 , 175 , },
{ 128 , -43 , -89 , },
{ 128 , 222 , 0 , },
},
.offset = { -351 , 265 , -443 , },
.scale = 2 ,
};
static const struct ipu_ic_csc_params *rgb2yuv_601[] = {
&rgbf2yuvf_601,
&rgbf2yuvl_601,
&rgbl2yuvf_601,
&rgbl2yuvl_601,
};
static const struct ipu_ic_csc_params *yuv2rgb_601[] = {
&yuvf2rgbf_601,
&yuvf2rgbl_601,
&yuvl2rgbf_601,
&yuvl2rgbl_601,
};
/*
* REC . 709 encoding from RGB full range to YUV full range :
*
* Y = . 2126 * R + . 7152 * G + . 0722 * B
* U = - . 1146 * R - . 3854 * G + . 5000 * B + 128
* V = . 5000 * R - . 4542 * G - . 0458 * B + 128
*/
static const struct ipu_ic_csc_params rgbf2yuvf_709 = {
.coeff = {
{ 54 , 183 , 19 },
{ -29 , -99 , 128 },
{ 128 , -116 , -12 },
},
.offset = { 0 , 512 , 512 },
.scale = 1 ,
};
/* Rec.709 RGB full-range to YUV limited-range */
static const struct ipu_ic_csc_params rgbf2yuvl_709 = {
.coeff = {
{ 47 , 157 , 16 , },
{ -26 , -87 , 112 , },
{ 112 , -102 , -10 , },
},
.offset = { 64 , 512 , 512 , },
.scale = 1 ,
.sat = true ,
};
/* Rec.709 RGB limited-range to YUV full-range */
static const struct ipu_ic_csc_params rgbl2yuvf_709 = {
.coeff = {
{ 63 , 213 , 22 , },
{ -34 , -115 , 149 , },
{ 149 , -135 , -14 , },
},
.offset = { -75 , 512 , 512 , },
.scale = 1 ,
};
/* Rec.709 RGB limited-range to YUV limited-range */
static const struct ipu_ic_csc_params rgbl2yuvl_709 = {
.coeff = {
{ 54 , 183 , 18 , },
{ -30 , -101 , 131 , },
{ 131 , -119 , -12 , },
},
.offset = { 0 , 512 , 512 , },
.scale = 1 ,
.sat = true ,
};
/*
* Inverse REC . 709 encoding from YUV full range to RGB full range :
*
* R = 1 . * Y + 0 * ( Cb - 128 ) + 1 . 5748 * ( Cr - 128 )
* G = 1 . * Y - . 1873 * ( Cb - 128 ) - . 4681 * ( Cr - 128 )
* B = 1 . * Y + 1 . 8556 * ( Cb - 128 ) + 0 * ( Cr - 128 )
*
* equivalently ( factoring out the offsets ) :
*
* R = 1 . * Y + 0 * Cb + 1 . 5748 * Cr - 201 . 574
* G = 1 . * Y - . 1873 * Cb - . 4681 * Cr + 83 . 891
* B = 1 . * Y + 1 . 8556 * Cb + 0 * Cr - 237 . 517
*/
static const struct ipu_ic_csc_params yuvf2rgbf_709 = {
.coeff = {
{ 128 , 0 , 202 },
{ 128 , -24 , -60 },
{ 128 , 238 , 0 },
},
.offset = { -403 , 168 , -475 },
.scale = 2 ,
};
/* Rec.709 YUV full-range to RGB limited-range */
static const struct ipu_ic_csc_params yuvf2rgbl_709 = {
.coeff = {
{ 110 , 0 , 173 , },
{ 110 , -21 , -51 , },
{ 110 , 204 , 0 , },
},
.offset = { -314 , 176 , -376 , },
.scale = 2 ,
};
/* Rec.709 YUV limited-range to RGB full-range */
static const struct ipu_ic_csc_params yuvl2rgbf_709 = {
.coeff = {
{ 75 , 0 , 115 , },
{ 75 , -14 , -34 , },
{ 75 , 135 , 0 , },
},
.offset = { -248 , 77 , -289 , },
.scale = 3 ,
};
/* Rec.709 YUV limited-range to RGB limited-range */
static const struct ipu_ic_csc_params yuvl2rgbl_709 = {
.coeff = {
{ 128 , 0 , 197 , },
{ 128 , -23 , -59 , },
{ 128 , 232 , 0 , },
},
.offset = { -394 , 164 , -464 , },
.scale = 2 ,
};
static const struct ipu_ic_csc_params *rgb2yuv_709[] = {
&rgbf2yuvf_709,
&rgbf2yuvl_709,
&rgbl2yuvf_709,
&rgbl2yuvl_709,
};
static const struct ipu_ic_csc_params *yuv2rgb_709[] = {
&yuvf2rgbf_709,
&yuvf2rgbl_709,
&yuvl2rgbf_709,
&yuvl2rgbl_709,
};
static int calc_csc_coeffs(struct ipu_ic_csc *csc)
{
const struct ipu_ic_csc_params **params_tbl;
int tbl_idx;
tbl_idx = (QUANT_MAP(csc->in_cs.quant) << 1 ) |
QUANT_MAP(csc->out_cs.quant);
if (csc->in_cs.cs == csc->out_cs.cs) {
csc->params = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ?
*yuv2yuv[tbl_idx] : *rgb2rgb[tbl_idx];
return 0 ;
}
/* YUV <-> RGB encoding is required */
switch (csc->out_cs.enc) {
case V4L2_YCBCR_ENC_601:
params_tbl = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ?
yuv2rgb_601 : rgb2yuv_601;
break ;
case V4L2_YCBCR_ENC_709:
params_tbl = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ?
yuv2rgb_709 : rgb2yuv_709;
break ;
default :
return -ENOTSUPP;
}
csc->params = *params_tbl[tbl_idx];
return 0 ;
}
int __ipu_ic_calc_csc(struct ipu_ic_csc *csc)
{
return calc_csc_coeffs(csc);
}
EXPORT_SYMBOL_GPL(__ipu_ic_calc_csc);
int ipu_ic_calc_csc(struct ipu_ic_csc *csc,
enum v4l2_ycbcr_encoding in_enc,
enum v4l2_quantization in_quant,
enum ipu_color_space in_cs,
enum v4l2_ycbcr_encoding out_enc,
enum v4l2_quantization out_quant,
enum ipu_color_space out_cs)
{
ipu_ic_fill_colorspace(&csc->in_cs, in_enc, in_quant, in_cs);
ipu_ic_fill_colorspace(&csc->out_cs, out_enc, out_quant, out_cs);
return __ipu_ic_calc_csc(csc);
}
EXPORT_SYMBOL_GPL(ipu_ic_calc_csc);
Messung V0.5 in Prozent C=95 H=100 G=97
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-10-01)
¤
*© Formatika GbR, Deutschland