Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpu: ipu-v3: ipu-ic: Fully describe colorspace conversions

Only providing the input and output RGB/YUV space to the IC task init
functions is not sufficient. To fully characterize a colorspace
conversion, the Y'CbCr encoding standard, and quantization also
need to be specified.

Define a 'struct ipu_ic_colorspace' that includes all the above.

This allows to actually enforce the fact that the IC:

- can only encode to/from YUV and RGB full range. A follow-up patch will
remove this restriction.
- can only encode using BT.601 standard. A follow-up patch will add
Rec.709 encoding support.

The determination of the CSC coefficients based on the input/output
'struct ipu_ic_colorspace' are moved to a new exported function
ipu_ic_calc_csc(), and 'struct ic_csc_params' is exported as
'struct ipu_ic_csc_params'. ipu_ic_calc_csc() fills a 'struct ipu_ic_csc'
with the input/output 'struct ipu_ic_colorspace' and the calculated
'struct ic_csc_params' from those input/output colorspaces.

The functions ipu_ic_task_init(_rsc)() now take a filled 'struct
ipu_ic_csc'.

The existing CSC coefficient tables and ipu_ic_calc_csc() are moved
to a new module ipu-ic-csc.c. This is in preparation for adding more
coefficient tables for limited range quantization and more encoding
standards.

The existing ycbcr2rgb and inverse rgb2ycbcr tables defined the BT.601
Y'CbCr encoding coefficients. The rgb2ycbcr table specifically described
the BT.601 encoding from full range RGB to full range YUV. Table
comments have been added in ipu-ic-csc.c to make this more clear.

The ycbcr2rgb inverse table described encoding YUV limited range to RGB
full range. To be consistent with the rgb2ycbcr table, this table is
converted to YUV full range to RGB full range, and the comments are
expanded in ipu-ic-csc.c.

The ic_csc_rgb2rgb table was just an identity matrix, so it is renamed
'identity' in ipu-ic-csc.c.

Signed-off-by: Steve Longerbeam <slongerbeam@gmail.com>
[p.zabel@pengutronix.de: removed a superfluous blank line]
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>

authored by

Steve Longerbeam and committed by
Philipp Zabel
f208b26e 3d1f62c6

+270 -118
+2 -2
drivers/gpu/ipu-v3/Makefile
··· 2 2 obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o 3 3 4 4 imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \ 5 - ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-image-convert.o \ 6 - ipu-smfc.o ipu-vdi.o 5 + ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-ic-csc.o \ 6 + ipu-image-convert.o ipu-smfc.o ipu-vdi.o 7 7 8 8 ifdef CONFIG_DRM 9 9 imx-ipu-v3-objs += ipu-pre.o ipu-prg.o
+128
drivers/gpu/ipu-v3/ipu-ic-csc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Copyright (C) 2019 Mentor Graphics Inc. 4 + */ 5 + 6 + #include <linux/types.h> 7 + #include <linux/init.h> 8 + #include <linux/errno.h> 9 + #include <linux/err.h> 10 + #include <linux/sizes.h> 11 + #include "ipu-prv.h" 12 + 13 + /* identity matrix */ 14 + static const struct ipu_ic_csc_params identity = { 15 + .coeff = { 16 + { 128, 0, 0, }, 17 + { 0, 128, 0, }, 18 + { 0, 0, 128, }, 19 + }, 20 + .offset = { 0, 0, 0, }, 21 + .scale = 2, 22 + }; 23 + 24 + static const struct ipu_ic_csc_params *rgb2rgb[] = { 25 + &identity, 26 + }; 27 + 28 + static const struct ipu_ic_csc_params *yuv2yuv[] = { 29 + &identity, 30 + }; 31 + 32 + /* 33 + * BT.601 RGB full-range to YUV full-range 34 + * 35 + * Y = .2990 * R + .5870 * G + .1140 * B 36 + * U = -.1687 * R - .3313 * G + .5000 * B + 128 37 + * V = .5000 * R - .4187 * G - .0813 * B + 128 38 + */ 39 + static const struct ipu_ic_csc_params rgbf2yuvf_601 = { 40 + .coeff = { 41 + { 77, 150, 29, }, 42 + { -43, -85, 128, }, 43 + { 128, -107, -21, }, 44 + }, 45 + .offset = { 0, 512, 512, }, 46 + .scale = 1, 47 + }; 48 + 49 + /* 50 + * BT.601 YUV full-range to RGB full-range 51 + * 52 + * R = 1. * Y + 0 * (Cb - 128) + 1.4020 * (Cr - 128) 53 + * G = 1. * Y - .3441 * (Cb - 128) - .7141 * (Cr - 128) 54 + * B = 1. * Y + 1.7720 * (Cb - 128) + 0 * (Cr - 128) 55 + * 56 + * equivalently (factoring out the offsets): 57 + * 58 + * R = 1. * Y + 0 * Cb + 1.4020 * Cr - 179.456 59 + * G = 1. * Y - .3441 * Cb - .7141 * Cr + 135.450 60 + * B = 1. * Y + 1.7720 * Cb + 0 * Cr - 226.816 61 + */ 62 + static const struct ipu_ic_csc_params yuvf2rgbf_601 = { 63 + .coeff = { 64 + { 128, 0, 179, }, 65 + { 128, -44, -91, }, 66 + { 128, 227, 0, }, 67 + }, 68 + .offset = { -359, 271, -454, }, 69 + .scale = 2, 70 + }; 71 + 72 + static const struct ipu_ic_csc_params *rgb2yuv_601[] = { 73 + &rgbf2yuvf_601, 74 + }; 75 + 76 + static const struct ipu_ic_csc_params *yuv2rgb_601[] = { 77 + &yuvf2rgbf_601, 78 + }; 79 + 80 + static int calc_csc_coeffs(struct ipu_ic_csc *csc) 81 + { 82 + if (csc->out_cs.enc != V4L2_YCBCR_ENC_601) 83 + return -ENOTSUPP; 84 + 85 + if ((csc->in_cs.cs == IPUV3_COLORSPACE_YUV && 86 + csc->in_cs.quant != V4L2_QUANTIZATION_FULL_RANGE) || 87 + (csc->out_cs.cs == IPUV3_COLORSPACE_YUV && 88 + csc->out_cs.quant != V4L2_QUANTIZATION_FULL_RANGE)) 89 + return -ENOTSUPP; 90 + 91 + if ((csc->in_cs.cs == IPUV3_COLORSPACE_RGB && 92 + csc->in_cs.quant != V4L2_QUANTIZATION_FULL_RANGE) || 93 + (csc->out_cs.cs == IPUV3_COLORSPACE_RGB && 94 + csc->out_cs.quant != V4L2_QUANTIZATION_FULL_RANGE)) 95 + return -ENOTSUPP; 96 + 97 + if (csc->in_cs.cs == csc->out_cs.cs) { 98 + csc->params = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ? 99 + *yuv2yuv[0] : *rgb2rgb[0]; 100 + return 0; 101 + } 102 + 103 + csc->params = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ? 104 + *yuv2rgb_601[0] : *rgb2yuv_601[0]; 105 + 106 + return 0; 107 + } 108 + 109 + int __ipu_ic_calc_csc(struct ipu_ic_csc *csc) 110 + { 111 + return calc_csc_coeffs(csc); 112 + } 113 + EXPORT_SYMBOL_GPL(__ipu_ic_calc_csc); 114 + 115 + int ipu_ic_calc_csc(struct ipu_ic_csc *csc, 116 + enum v4l2_ycbcr_encoding in_enc, 117 + enum v4l2_quantization in_quant, 118 + enum ipu_color_space in_cs, 119 + enum v4l2_ycbcr_encoding out_enc, 120 + enum v4l2_quantization out_quant, 121 + enum ipu_color_space out_cs) 122 + { 123 + ipu_ic_fill_colorspace(&csc->in_cs, in_enc, in_quant, in_cs); 124 + ipu_ic_fill_colorspace(&csc->out_cs, out_enc, out_quant, out_cs); 125 + 126 + return __ipu_ic_calc_csc(csc); 127 + } 128 + EXPORT_SYMBOL_GPL(ipu_ic_calc_csc);
+45 -93
drivers/gpu/ipu-v3/ipu-ic.c
··· 140 140 const struct ic_task_regoffs *reg; 141 141 const struct ic_task_bitfields *bit; 142 142 143 - enum ipu_color_space in_cs, g_in_cs; 144 - enum ipu_color_space out_cs; 143 + struct ipu_ic_colorspace in_cs; 144 + struct ipu_ic_colorspace g_in_cs; 145 + struct ipu_ic_colorspace out_cs; 146 + 145 147 bool graphics; 146 148 bool rotation; 147 149 bool in_use; ··· 171 169 writel(value, ic->priv->base + offset); 172 170 } 173 171 174 - struct ic_csc_params { 175 - s16 coeff[3][3]; /* signed 9-bit integer coefficients */ 176 - s16 offset[3]; /* signed 11+2-bit fixed point offset */ 177 - u8 scale:2; /* scale coefficients * 2^(scale-1) */ 178 - bool sat:1; /* saturate to (16, 235(Y) / 240(U, V)) */ 179 - }; 180 - 181 - /* 182 - * Y = R * .299 + G * .587 + B * .114; 183 - * U = R * -.169 + G * -.332 + B * .500 + 128.; 184 - * V = R * .500 + G * -.419 + B * -.0813 + 128.; 185 - */ 186 - static const struct ic_csc_params ic_csc_rgb2ycbcr = { 187 - .coeff = { 188 - { 77, 150, 29 }, 189 - { 469, 427, 128 }, 190 - { 128, 405, 491 }, 191 - }, 192 - .offset = { 0, 512, 512 }, 193 - .scale = 1, 194 - }; 195 - 196 - /* transparent RGB->RGB matrix for graphics combining */ 197 - static const struct ic_csc_params ic_csc_rgb2rgb = { 198 - .coeff = { 199 - { 128, 0, 0 }, 200 - { 0, 128, 0 }, 201 - { 0, 0, 128 }, 202 - }, 203 - .scale = 2, 204 - }; 205 - 206 - /* 207 - * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128)); 208 - * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128)); 209 - * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); 210 - */ 211 - static const struct ic_csc_params ic_csc_ycbcr2rgb = { 212 - .coeff = { 213 - { 149, 0, 204 }, 214 - { 149, 462, 408 }, 215 - { 149, 255, 0 }, 216 - }, 217 - .offset = { -446, 266, -554 }, 218 - .scale = 2, 219 - }; 220 - 221 172 static int init_csc(struct ipu_ic *ic, 222 - enum ipu_color_space inf, 223 - enum ipu_color_space outf, 173 + const struct ipu_ic_csc *csc, 224 174 int csc_index) 225 175 { 226 176 struct ipu_ic_priv *priv = ic->priv; 227 - const struct ic_csc_params *params; 228 177 u32 __iomem *base; 229 178 const u16 (*c)[3]; 230 179 const u16 *a; ··· 184 231 base = (u32 __iomem *) 185 232 (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]); 186 233 187 - if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB) 188 - params = &ic_csc_ycbcr2rgb; 189 - else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV) 190 - params = &ic_csc_rgb2ycbcr; 191 - else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB) 192 - params = &ic_csc_rgb2rgb; 193 - else { 194 - dev_err(priv->ipu->dev, "Unsupported color space conversion\n"); 195 - return -EINVAL; 196 - } 197 - 198 234 /* Cast to unsigned */ 199 - c = (const u16 (*)[3])params->coeff; 200 - a = (const u16 *)params->offset; 235 + c = (const u16 (*)[3])csc->params.coeff; 236 + a = (const u16 *)csc->params.offset; 201 237 202 238 param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) | 203 239 ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff); 204 240 writel(param, base++); 205 241 206 - param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) | 207 - (params->sat << 10); 242 + param = ((a[0] & 0x1fe0) >> 5) | (csc->params.scale << 8) | 243 + (csc->params.sat << 10); 208 244 writel(param, base++); 209 245 210 246 param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) | ··· 280 338 if (ic->rotation) 281 339 ic_conf |= ic->bit->ic_conf_rot_en; 282 340 283 - if (ic->in_cs != ic->out_cs) 341 + if (ic->in_cs.cs != ic->out_cs.cs) 284 342 ic_conf |= ic->bit->ic_conf_csc1_en; 285 343 286 344 if (ic->graphics) { 287 345 ic_conf |= ic->bit->ic_conf_cmb_en; 288 346 ic_conf |= ic->bit->ic_conf_csc1_en; 289 347 290 - if (ic->g_in_cs != ic->out_cs) 348 + if (ic->g_in_cs.cs != ic->out_cs.cs) 291 349 ic_conf |= ic->bit->ic_conf_csc2_en; 292 350 } 293 351 ··· 322 380 EXPORT_SYMBOL_GPL(ipu_ic_task_disable); 323 381 324 382 int ipu_ic_task_graphics_init(struct ipu_ic *ic, 325 - enum ipu_color_space in_g_cs, 383 + const struct ipu_ic_colorspace *g_in_cs, 326 384 bool galpha_en, u32 galpha, 327 385 bool colorkey_en, u32 colorkey) 328 386 { 329 387 struct ipu_ic_priv *priv = ic->priv; 388 + struct ipu_ic_csc csc2; 330 389 unsigned long flags; 331 390 u32 reg, ic_conf; 332 391 int ret = 0; ··· 340 397 ic_conf = ipu_ic_read(ic, IC_CONF); 341 398 342 399 if (!(ic_conf & ic->bit->ic_conf_csc1_en)) { 400 + struct ipu_ic_csc csc1; 401 + 402 + ret = ipu_ic_calc_csc(&csc1, 403 + V4L2_YCBCR_ENC_601, 404 + V4L2_QUANTIZATION_FULL_RANGE, 405 + IPUV3_COLORSPACE_RGB, 406 + V4L2_YCBCR_ENC_601, 407 + V4L2_QUANTIZATION_FULL_RANGE, 408 + IPUV3_COLORSPACE_RGB); 409 + if (ret) 410 + goto unlock; 411 + 343 412 /* need transparent CSC1 conversion */ 344 - ret = init_csc(ic, IPUV3_COLORSPACE_RGB, 345 - IPUV3_COLORSPACE_RGB, 0); 413 + ret = init_csc(ic, &csc1, 0); 346 414 if (ret) 347 415 goto unlock; 348 416 } 349 417 350 - ic->g_in_cs = in_g_cs; 418 + ic->g_in_cs = *g_in_cs; 419 + csc2.in_cs = ic->g_in_cs; 420 + csc2.out_cs = ic->out_cs; 351 421 352 - if (ic->g_in_cs != ic->out_cs) { 353 - ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1); 354 - if (ret) 355 - goto unlock; 356 - } 422 + ret = __ipu_ic_calc_csc(&csc2); 423 + if (ret) 424 + goto unlock; 425 + 426 + ret = init_csc(ic, &csc2, 1); 427 + if (ret) 428 + goto unlock; 357 429 358 430 if (galpha_en) { 359 431 ic_conf |= IC_CONF_IC_GLB_LOC_A; ··· 395 437 EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init); 396 438 397 439 int ipu_ic_task_init_rsc(struct ipu_ic *ic, 440 + const struct ipu_ic_csc *csc, 398 441 int in_width, int in_height, 399 442 int out_width, int out_height, 400 - enum ipu_color_space in_cs, 401 - enum ipu_color_space out_cs, 402 443 u32 rsc) 403 444 { 404 445 struct ipu_ic_priv *priv = ic->priv; ··· 429 472 ipu_ic_write(ic, rsc, ic->reg->rsc); 430 473 431 474 /* Setup color space conversion */ 432 - ic->in_cs = in_cs; 433 - ic->out_cs = out_cs; 475 + ic->in_cs = csc->in_cs; 476 + ic->out_cs = csc->out_cs; 434 477 435 - if (ic->in_cs != ic->out_cs) { 436 - ret = init_csc(ic, ic->in_cs, ic->out_cs, 0); 437 - if (ret) 438 - goto unlock; 439 - } 478 + ret = init_csc(ic, csc, 0); 440 479 441 - unlock: 442 480 spin_unlock_irqrestore(&priv->lock, flags); 443 481 return ret; 444 482 } 445 483 446 484 int ipu_ic_task_init(struct ipu_ic *ic, 485 + const struct ipu_ic_csc *csc, 447 486 int in_width, int in_height, 448 - int out_width, int out_height, 449 - enum ipu_color_space in_cs, 450 - enum ipu_color_space out_cs) 487 + int out_width, int out_height) 451 488 { 452 - return ipu_ic_task_init_rsc(ic, in_width, in_height, out_width, 453 - out_height, in_cs, out_cs, 0); 489 + return ipu_ic_task_init_rsc(ic, csc, 490 + in_width, in_height, 491 + out_width, out_height, 0); 454 492 } 455 493 EXPORT_SYMBOL_GPL(ipu_ic_task_init); 456 494
+17 -11
drivers/gpu/ipu-v3/ipu-image-convert.c
··· 146 146 /* Source/destination image data and rotation mode */ 147 147 struct ipu_image_convert_image in; 148 148 struct ipu_image_convert_image out; 149 + struct ipu_ic_csc csc; 149 150 enum ipu_rotate_mode rot_mode; 150 151 u32 downsize_coeff_h; 151 152 u32 downsize_coeff_v; ··· 1309 1308 struct ipu_image_convert_priv *priv = chan->priv; 1310 1309 struct ipu_image_convert_image *s_image = &ctx->in; 1311 1310 struct ipu_image_convert_image *d_image = &ctx->out; 1312 - enum ipu_color_space src_cs, dest_cs; 1313 1311 unsigned int dst_tile = ctx->out_tile_map[tile]; 1314 1312 unsigned int dest_width, dest_height; 1315 1313 unsigned int col, row; ··· 1317 1317 1318 1318 dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n", 1319 1319 __func__, chan->ic_task, ctx, run, tile, dst_tile); 1320 - 1321 - src_cs = ipu_pixelformat_to_colorspace(s_image->fmt->fourcc); 1322 - dest_cs = ipu_pixelformat_to_colorspace(d_image->fmt->fourcc); 1323 1320 1324 1321 if (ipu_rot_mode_is_irt(ctx->rot_mode)) { 1325 1322 /* swap width/height for resizer */ ··· 1340 1343 s_image->tile[tile].height, dest_width, dest_height, rsc); 1341 1344 1342 1345 /* setup the IC resizer and CSC */ 1343 - ret = ipu_ic_task_init_rsc(chan->ic, 1344 - s_image->tile[tile].width, 1345 - s_image->tile[tile].height, 1346 - dest_width, 1347 - dest_height, 1348 - src_cs, dest_cs, 1349 - rsc); 1346 + ret = ipu_ic_task_init_rsc(chan->ic, &ctx->csc, 1347 + s_image->tile[tile].width, 1348 + s_image->tile[tile].height, 1349 + dest_width, 1350 + dest_height, 1351 + rsc); 1350 1352 if (ret) { 1351 1353 dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret); 1352 1354 return ret; ··· 2044 2048 goto out_free; 2045 2049 2046 2050 calc_tile_resize_coefficients(ctx); 2051 + 2052 + ret = ipu_ic_calc_csc(&ctx->csc, 2053 + s_image->base.pix.ycbcr_enc, 2054 + s_image->base.pix.quantization, 2055 + ipu_pixelformat_to_colorspace(s_image->fmt->fourcc), 2056 + d_image->base.pix.ycbcr_enc, 2057 + d_image->base.pix.quantization, 2058 + ipu_pixelformat_to_colorspace(d_image->fmt->fourcc)); 2059 + if (ret) 2060 + goto out_free; 2047 2061 2048 2062 dump_format(ctx, s_image); 2049 2063 dump_format(ctx, d_image);
+28 -6
drivers/staging/media/imx/imx-ic-prpencvf.c
··· 456 456 const struct imx_media_pixfmt *outcc, *incc; 457 457 struct v4l2_mbus_framefmt *infmt; 458 458 struct v4l2_pix_format *outfmt; 459 + struct ipu_ic_csc csc; 459 460 dma_addr_t phys[2]; 460 461 int ret; 461 462 ··· 464 463 outfmt = &vdev->fmt.fmt.pix; 465 464 incc = priv->cc[PRPENCVF_SINK_PAD]; 466 465 outcc = vdev->cc; 466 + 467 + ret = ipu_ic_calc_csc(&csc, 468 + infmt->ycbcr_enc, infmt->quantization, 469 + incc->cs, 470 + outfmt->ycbcr_enc, outfmt->quantization, 471 + outcc->cs); 472 + if (ret) { 473 + v4l2_err(&ic_priv->sd, "ipu_ic_calc_csc failed, %d\n", 474 + ret); 475 + return ret; 476 + } 467 477 468 478 ret = imx_media_alloc_dma_buf(priv->md, &priv->rot_buf[0], 469 479 outfmt->sizeimage); ··· 489 477 goto free_rot0; 490 478 } 491 479 492 - ret = ipu_ic_task_init(priv->ic, 480 + ret = ipu_ic_task_init(priv->ic, &csc, 493 481 infmt->width, infmt->height, 494 - outfmt->height, outfmt->width, 495 - incc->cs, outcc->cs); 482 + outfmt->height, outfmt->width); 496 483 if (ret) { 497 484 v4l2_err(&ic_priv->sd, "ipu_ic_task_init failed, %d\n", ret); 498 485 goto free_rot1; ··· 583 572 const struct imx_media_pixfmt *outcc, *incc; 584 573 struct v4l2_mbus_framefmt *infmt; 585 574 struct v4l2_pix_format *outfmt; 575 + struct ipu_ic_csc csc; 586 576 dma_addr_t phys[2]; 587 577 int ret; 588 578 ··· 592 580 incc = priv->cc[PRPENCVF_SINK_PAD]; 593 581 outcc = vdev->cc; 594 582 595 - ret = ipu_ic_task_init(priv->ic, 583 + ret = ipu_ic_calc_csc(&csc, 584 + infmt->ycbcr_enc, infmt->quantization, 585 + incc->cs, 586 + outfmt->ycbcr_enc, outfmt->quantization, 587 + outcc->cs); 588 + if (ret) { 589 + v4l2_err(&ic_priv->sd, "ipu_ic_calc_csc failed, %d\n", 590 + ret); 591 + return ret; 592 + } 593 + 594 + ret = ipu_ic_task_init(priv->ic, &csc, 596 595 infmt->width, infmt->height, 597 - outfmt->width, outfmt->height, 598 - incc->cs, outcc->cs); 596 + outfmt->width, outfmt->height); 599 597 if (ret) { 600 598 v4l2_err(&ic_priv->sd, "ipu_ic_task_init failed, %d\n", ret); 601 599 return ret;
+50 -6
include/video/imx-ipu-v3.h
··· 387 387 IC_NUM_TASKS, 388 388 }; 389 389 390 + /* 391 + * The parameters that describe a colorspace according to the 392 + * Image Converter: 393 + * - Y'CbCr encoding 394 + * - quantization 395 + * - "colorspace" (RGB or YUV). 396 + */ 397 + struct ipu_ic_colorspace { 398 + enum v4l2_ycbcr_encoding enc; 399 + enum v4l2_quantization quant; 400 + enum ipu_color_space cs; 401 + }; 402 + 403 + static inline void 404 + ipu_ic_fill_colorspace(struct ipu_ic_colorspace *ic_cs, 405 + enum v4l2_ycbcr_encoding enc, 406 + enum v4l2_quantization quant, 407 + enum ipu_color_space cs) 408 + { 409 + ic_cs->enc = enc; 410 + ic_cs->quant = quant; 411 + ic_cs->cs = cs; 412 + } 413 + 414 + struct ipu_ic_csc_params { 415 + s16 coeff[3][3]; /* signed 9-bit integer coefficients */ 416 + s16 offset[3]; /* signed 11+2-bit fixed point offset */ 417 + u8 scale:2; /* scale coefficients * 2^(scale-1) */ 418 + bool sat:1; /* saturate to (16, 235(Y) / 240(U, V)) */ 419 + }; 420 + 421 + struct ipu_ic_csc { 422 + struct ipu_ic_colorspace in_cs; 423 + struct ipu_ic_colorspace out_cs; 424 + struct ipu_ic_csc_params params; 425 + }; 426 + 390 427 struct ipu_ic; 428 + 429 + int __ipu_ic_calc_csc(struct ipu_ic_csc *csc); 430 + int ipu_ic_calc_csc(struct ipu_ic_csc *csc, 431 + enum v4l2_ycbcr_encoding in_enc, 432 + enum v4l2_quantization in_quant, 433 + enum ipu_color_space in_cs, 434 + enum v4l2_ycbcr_encoding out_enc, 435 + enum v4l2_quantization out_quant, 436 + enum ipu_color_space out_cs); 391 437 int ipu_ic_task_init(struct ipu_ic *ic, 438 + const struct ipu_ic_csc *csc, 392 439 int in_width, int in_height, 393 - int out_width, int out_height, 394 - enum ipu_color_space in_cs, 395 - enum ipu_color_space out_cs); 440 + int out_width, int out_height); 396 441 int ipu_ic_task_init_rsc(struct ipu_ic *ic, 442 + const struct ipu_ic_csc *csc, 397 443 int in_width, int in_height, 398 444 int out_width, int out_height, 399 - enum ipu_color_space in_cs, 400 - enum ipu_color_space out_cs, 401 445 u32 rsc); 402 446 int ipu_ic_task_graphics_init(struct ipu_ic *ic, 403 - enum ipu_color_space in_g_cs, 447 + const struct ipu_ic_colorspace *g_in_cs, 404 448 bool galpha_en, u32 galpha, 405 449 bool colorkey_en, u32 colorkey); 406 450 void ipu_ic_task_enable(struct ipu_ic *ic);