2019-05-22 04:03:14 +03:00
// 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"
2019-05-22 04:03:15 +03:00
# define QUANT_MAP(q) \
( ( q ) = = V4L2_QUANTIZATION_FULL_RANGE | | \
( q ) = = V4L2_QUANTIZATION_DEFAULT ? 0 : 1 )
2019-05-22 04:03:14 +03:00
/* 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 ,
} ;
2019-05-22 04:03:15 +03:00
/*
* 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 ,
} ;
2019-05-22 04:03:14 +03:00
static const struct ipu_ic_csc_params * rgb2rgb [ ] = {
& identity ,
2019-05-22 04:03:15 +03:00
& rgbf2rgbl ,
& rgbl2rgbf ,
& identity ,
2019-05-22 04:03:14 +03:00
} ;
static const struct ipu_ic_csc_params * yuv2yuv [ ] = {
& identity ,
2019-05-22 04:03:15 +03:00
& yuvf2yuvl ,
& yuvl2yuvf ,
& identity ,
2019-05-22 04:03:14 +03:00
} ;
/*
* 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 ,
} ;
2019-05-22 04:03:15 +03:00
/* 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 ,
} ;
2019-05-22 04:03:14 +03:00
/*
* 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 ,
} ;
2019-05-22 04:03:15 +03:00
/* 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 ,
} ;
2019-05-22 04:03:14 +03:00
static const struct ipu_ic_csc_params * rgb2yuv_601 [ ] = {
& rgbf2yuvf_601 ,
2019-05-22 04:03:15 +03:00
& rgbf2yuvl_601 ,
& rgbl2yuvf_601 ,
& rgbl2yuvl_601 ,
2019-05-22 04:03:14 +03:00
} ;
static const struct ipu_ic_csc_params * yuv2rgb_601 [ ] = {
& yuvf2rgbf_601 ,
2019-05-22 04:03:15 +03:00
& yuvf2rgbl_601 ,
& yuvl2rgbf_601 ,
& yuvl2rgbl_601 ,
2019-05-22 04:03:14 +03:00
} ;
2019-05-22 04:03:16 +03:00
/*
* 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 ,
} ;
2019-05-22 04:03:14 +03:00
static int calc_csc_coeffs ( struct ipu_ic_csc * csc )
{
2019-05-22 04:03:15 +03:00
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 ) ;
2019-05-22 04:03:14 +03:00
if ( csc - > in_cs . cs = = csc - > out_cs . cs ) {
csc - > params = ( csc - > in_cs . cs = = IPUV3_COLORSPACE_YUV ) ?
2019-05-22 04:03:15 +03:00
* yuv2yuv [ tbl_idx ] : * rgb2rgb [ tbl_idx ] ;
2019-05-22 04:03:14 +03:00
return 0 ;
}
2019-05-22 04:03:15 +03:00
/* YUV <-> RGB encoding is required */
2019-05-22 04:03:16 +03:00
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 ;
}
2019-05-22 04:03:15 +03:00
csc - > params = * params_tbl [ tbl_idx ] ;
2019-05-22 04:03:14 +03:00
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 ) ;