diff options
author | Steve Longerbeam <slongerbeam@gmail.com> | 2019-05-21 18:03:15 -0700 |
---|---|---|
committer | Philipp Zabel <p.zabel@pengutronix.de> | 2019-06-14 15:33:02 +0200 |
commit | e3e4820d054c0d616fc9636489b7b87844ac104d (patch) | |
tree | eb5fe1da12e9584f49c0e0e5ee0e29e4f7de6367 /drivers/gpu/ipu-v3 | |
parent | f208b26e61df411cf0bee413bee57ff434e8b38a (diff) | |
download | linux-e3e4820d054c0d616fc9636489b7b87844ac104d.tar.bz2 |
gpu: ipu-v3: ipu-ic-csc: Add support for limited range encoding
Add support for encodings to or from limited range quantization.
Signed-off-by: Steve Longerbeam <slongerbeam@gmail.com>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Diffstat (limited to 'drivers/gpu/ipu-v3')
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-ic-csc.c | 180 |
1 files changed, 166 insertions, 14 deletions
diff --git a/drivers/gpu/ipu-v3/ipu-ic-csc.c b/drivers/gpu/ipu-v3/ipu-ic-csc.c index a5a26fe37608..0c7ff4e361f4 100644 --- a/drivers/gpu/ipu-v3/ipu-ic-csc.c +++ b/drivers/gpu/ipu-v3/ipu-ic-csc.c @@ -10,6 +10,10 @@ #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 = { @@ -21,12 +25,87 @@ static const struct ipu_ic_csc_params identity = { .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, }; /* @@ -46,6 +125,41 @@ static const struct ipu_ic_csc_params rgbf2yuvf_601 = { .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 * @@ -69,39 +183,77 @@ static const struct ipu_ic_csc_params yuvf2rgbf_601 = { .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, }; static int calc_csc_coeffs(struct ipu_ic_csc *csc) { + const struct ipu_ic_csc_params **params_tbl; + int tbl_idx; + if (csc->out_cs.enc != V4L2_YCBCR_ENC_601) return -ENOTSUPP; - if ((csc->in_cs.cs == IPUV3_COLORSPACE_YUV && - csc->in_cs.quant != V4L2_QUANTIZATION_FULL_RANGE) || - (csc->out_cs.cs == IPUV3_COLORSPACE_YUV && - csc->out_cs.quant != V4L2_QUANTIZATION_FULL_RANGE)) - return -ENOTSUPP; - - if ((csc->in_cs.cs == IPUV3_COLORSPACE_RGB && - csc->in_cs.quant != V4L2_QUANTIZATION_FULL_RANGE) || - (csc->out_cs.cs == IPUV3_COLORSPACE_RGB && - csc->out_cs.quant != V4L2_QUANTIZATION_FULL_RANGE)) - return -ENOTSUPP; + 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[0] : *rgb2rgb[0]; + *yuv2yuv[tbl_idx] : *rgb2rgb[tbl_idx]; + return 0; } - csc->params = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ? - *yuv2rgb_601[0] : *rgb2yuv_601[0]; + /* YUV <-> RGB encoding is required */ + + params_tbl = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ? + yuv2rgb_601 : rgb2yuv_601; + + csc->params = *params_tbl[tbl_idx]; return 0; } |