@@ -175,7 +175,7 @@ static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset)
writel(value, ic->priv->base + offset);
}
-struct ic_csc_params {
+struct ic_encode_coeff {
s16 coeff[3][3]; /* signed 9-bit integer coefficients */
s16 offset[3]; /* signed 11+2-bit fixed point offset */
u8 scale:2; /* scale coefficients * 2^(scale-1) */
@@ -183,22 +183,27 @@ struct ic_csc_params {
};
/*
- * Y = R * .299 + G * .587 + B * .114;
- * U = R * -.169 + G * -.332 + B * .500 + 128.;
- * V = R * .500 + G * -.419 + B * -.0813 + 128.;
+ * BT.601 encoding from 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 ic_csc_params ic_csc_rgb2ycbcr = {
+static const struct ic_encode_coeff ic_encode_rgb2ycbcr_601 = {
.coeff = {
- { 77, 150, 29 },
- { 469, 427, 128 },
+ { 76, 150, 29 },
+ { 469, 428, 128 },
{ 128, 405, 491 },
},
.offset = { 0, 512, 512 },
.scale = 1,
};
-/* transparent RGB->RGB matrix for graphics combining */
-static const struct ic_csc_params ic_csc_rgb2rgb = {
+/*
+ * identity matrix, used for transparent RGB->RGB graphics
+ * combining.
+ */
+static const struct ic_encode_coeff ic_encode_identity = {
.coeff = {
{ 128, 0, 0 },
{ 0, 128, 0 },
@@ -208,17 +213,25 @@ static const struct ic_csc_params ic_csc_rgb2rgb = {
};
/*
- * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
- * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
- * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
+ * Inverse BT.601 encoding from YUV full range to RGB full range:
+ *
+ * R = 1. * Y + 0 * (Cb - 128) + 1.4020 * (Cr - 128)
+ * G = 1. * Y - .3442 * (Cb - 128) - 0.7142 * (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 - .3442 * Cb - 0.7142 * Cr + 135.475
+ * B = 1. * Y + 1.7720 * Cb + 0 * Cr - 226.816
*/
-static const struct ic_csc_params ic_csc_ycbcr2rgb = {
+static const struct ic_encode_coeff ic_encode_ycbcr2rgb_601 = {
.coeff = {
- { 149, 0, 204 },
- { 149, 462, 408 },
- { 149, 255, 0 },
+ { 128, 0, 179 },
+ { 128, 468, 421 },
+ { 128, 226, 0 },
},
- .offset = { -446, 266, -554 },
+ .offset = { -359, 271, -454 },
.scale = 2,
};
@@ -228,7 +241,7 @@ static int init_csc(struct ipu_ic *ic,
int csc_index)
{
struct ipu_ic_priv *priv = ic->priv;
- const struct ic_csc_params *params;
+ const struct ic_encode_coeff *coeff;
u32 __iomem *base;
const u16 (*c)[3];
const u16 *a;
@@ -238,26 +251,26 @@ static int init_csc(struct ipu_ic *ic,
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
- params = &ic_csc_ycbcr2rgb;
+ coeff = &ic_encode_ycbcr2rgb_601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
- params = &ic_csc_rgb2ycbcr;
+ coeff = &ic_encode_rgb2ycbcr_601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
- params = &ic_csc_rgb2rgb;
+ coeff = &ic_encode_identity;
else {
dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
return -EINVAL;
}
/* Cast to unsigned */
- c = (const u16 (*)[3])params->coeff;
- a = (const u16 *)params->offset;
+ c = (const u16 (*)[3])coeff->coeff;
+ a = (const u16 *)coeff->offset;
param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) |
((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff);
writel(param, base++);
- param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) |
- (params->sat << 10);
+ param = ((a[0] & 0x1fe0) >> 5) | (coeff->scale << 8) |
+ (coeff->sat << 10);
writel(param, base++);
param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |