1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2019 Mentor Graphics Inc.
6 #include <linux/types.h>
7 #include <linux/init.h>
8 #include <linux/errno.h>
10 #include <linux/sizes.h>
13 #define QUANT_MAP(q) \
14 ((q) == V4L2_QUANTIZATION_FULL_RANGE || \
15 (q) == V4L2_QUANTIZATION_DEFAULT ? 0 : 1)
18 static const struct ipu_ic_csc_params identity
= {
24 .offset
= { 0, 0, 0, },
29 * RGB full-range to RGB limited-range
31 * R_lim = 0.8588 * R_full + 16
32 * G_lim = 0.8588 * G_full + 16
33 * B_lim = 0.8588 * B_full + 16
35 static const struct ipu_ic_csc_params rgbf2rgbl
= {
41 .offset
= { 64, 64, 64, },
46 * RGB limited-range to RGB full-range
48 * R_full = 1.1644 * (R_lim - 16)
49 * G_full = 1.1644 * (G_lim - 16)
50 * B_full = 1.1644 * (B_lim - 16)
52 static const struct ipu_ic_csc_params rgbl2rgbf
= {
58 .offset
= { -37, -37, -37, },
63 * YUV full-range to YUV limited-range
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
69 static const struct ipu_ic_csc_params yuvf2yuvl
= {
75 .offset
= { 64, 62, 62, },
81 * YUV limited-range to YUV full-range
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
87 static const struct ipu_ic_csc_params yuvl2yuvf
= {
93 .offset
= { -37, -35, -35, },
97 static const struct ipu_ic_csc_params
*rgb2rgb
[] = {
104 static const struct ipu_ic_csc_params
*yuv2yuv
[] = {
112 * BT.601 RGB full-range to YUV full-range
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
118 static const struct ipu_ic_csc_params rgbf2yuvf_601
= {
124 .offset
= { 0, 512, 512, },
128 /* BT.601 RGB full-range to YUV limited-range */
129 static const struct ipu_ic_csc_params rgbf2yuvl_601
= {
135 .offset
= { 64, 512, 512, },
140 /* BT.601 RGB limited-range to YUV full-range */
141 static const struct ipu_ic_csc_params rgbl2yuvf_601
= {
147 .offset
= { -75, 512, 512, },
151 /* BT.601 RGB limited-range to YUV limited-range */
152 static const struct ipu_ic_csc_params rgbl2yuvl_601
= {
158 .offset
= { 0, 512, 512, },
164 * BT.601 YUV full-range to RGB full-range
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)
170 * equivalently (factoring out the offsets):
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
176 static const struct ipu_ic_csc_params yuvf2rgbf_601
= {
182 .offset
= { -359, 271, -454, },
186 /* BT.601 YUV full-range to RGB limited-range */
187 static const struct ipu_ic_csc_params yuvf2rgbl_601
= {
193 .offset
= { -276, 265, -358, },
197 /* BT.601 YUV limited-range to RGB full-range */
198 static const struct ipu_ic_csc_params yuvl2rgbf_601
= {
204 .offset
= { -223, 136, -277, },
208 /* BT.601 YUV limited-range to RGB limited-range */
209 static const struct ipu_ic_csc_params yuvl2rgbl_601
= {
215 .offset
= { -351, 265, -443, },
219 static const struct ipu_ic_csc_params
*rgb2yuv_601
[] = {
226 static const struct ipu_ic_csc_params
*yuv2rgb_601
[] = {
234 * REC.709 encoding from RGB full range to YUV full range:
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
240 static const struct ipu_ic_csc_params rgbf2yuvf_709
= {
246 .offset
= { 0, 512, 512 },
250 /* Rec.709 RGB full-range to YUV limited-range */
251 static const struct ipu_ic_csc_params rgbf2yuvl_709
= {
257 .offset
= { 64, 512, 512, },
262 /* Rec.709 RGB limited-range to YUV full-range */
263 static const struct ipu_ic_csc_params rgbl2yuvf_709
= {
269 .offset
= { -75, 512, 512, },
273 /* Rec.709 RGB limited-range to YUV limited-range */
274 static const struct ipu_ic_csc_params rgbl2yuvl_709
= {
280 .offset
= { 0, 512, 512, },
286 * Inverse REC.709 encoding from YUV full range to RGB full range:
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)
292 * equivalently (factoring out the offsets):
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
298 static const struct ipu_ic_csc_params yuvf2rgbf_709
= {
304 .offset
= { -403, 168, -475 },
308 /* Rec.709 YUV full-range to RGB limited-range */
309 static const struct ipu_ic_csc_params yuvf2rgbl_709
= {
315 .offset
= { -314, 176, -376, },
319 /* Rec.709 YUV limited-range to RGB full-range */
320 static const struct ipu_ic_csc_params yuvl2rgbf_709
= {
326 .offset
= { -248, 77, -289, },
330 /* Rec.709 YUV limited-range to RGB limited-range */
331 static const struct ipu_ic_csc_params yuvl2rgbl_709
= {
337 .offset
= { -394, 164, -464, },
341 static const struct ipu_ic_csc_params
*rgb2yuv_709
[] = {
348 static const struct ipu_ic_csc_params
*yuv2rgb_709
[] = {
355 static int calc_csc_coeffs(struct ipu_ic_csc
*csc
)
357 const struct ipu_ic_csc_params
**params_tbl
;
360 tbl_idx
= (QUANT_MAP(csc
->in_cs
.quant
) << 1) |
361 QUANT_MAP(csc
->out_cs
.quant
);
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
];
370 /* YUV <-> RGB encoding is required */
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
;
377 case V4L2_YCBCR_ENC_709
:
378 params_tbl
= (csc
->in_cs
.cs
== IPUV3_COLORSPACE_YUV
) ?
379 yuv2rgb_709
: rgb2yuv_709
;
385 csc
->params
= *params_tbl
[tbl_idx
];
390 int __ipu_ic_calc_csc(struct ipu_ic_csc
*csc
)
392 return calc_csc_coeffs(csc
);
394 EXPORT_SYMBOL_GPL(__ipu_ic_calc_csc
);
396 int 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
)
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
);
407 return __ipu_ic_calc_csc(csc
);
409 EXPORT_SYMBOL_GPL(ipu_ic_calc_csc
);