Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/ipu-v3/ipu-ic-csc.c
26428 views
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
#define QUANT_MAP(q) \
14
((q) == V4L2_QUANTIZATION_FULL_RANGE || \
15
(q) == V4L2_QUANTIZATION_DEFAULT ? 0 : 1)
16
17
/* identity matrix */
18
static const struct ipu_ic_csc_params identity = {
19
.coeff = {
20
{ 128, 0, 0, },
21
{ 0, 128, 0, },
22
{ 0, 0, 128, },
23
},
24
.offset = { 0, 0, 0, },
25
.scale = 2,
26
};
27
28
/*
29
* RGB full-range to RGB limited-range
30
*
31
* R_lim = 0.8588 * R_full + 16
32
* G_lim = 0.8588 * G_full + 16
33
* B_lim = 0.8588 * B_full + 16
34
*/
35
static const struct ipu_ic_csc_params rgbf2rgbl = {
36
.coeff = {
37
{ 220, 0, 0, },
38
{ 0, 220, 0, },
39
{ 0, 0, 220, },
40
},
41
.offset = { 64, 64, 64, },
42
.scale = 1,
43
};
44
45
/*
46
* RGB limited-range to RGB full-range
47
*
48
* R_full = 1.1644 * (R_lim - 16)
49
* G_full = 1.1644 * (G_lim - 16)
50
* B_full = 1.1644 * (B_lim - 16)
51
*/
52
static const struct ipu_ic_csc_params rgbl2rgbf = {
53
.coeff = {
54
{ 149, 0, 0, },
55
{ 0, 149, 0, },
56
{ 0, 0, 149, },
57
},
58
.offset = { -37, -37, -37, },
59
.scale = 2,
60
};
61
62
/*
63
* YUV full-range to YUV limited-range
64
*
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
68
*/
69
static const struct ipu_ic_csc_params yuvf2yuvl = {
70
.coeff = {
71
{ 220, 0, 0, },
72
{ 0, 225, 0, },
73
{ 0, 0, 225, },
74
},
75
.offset = { 64, 62, 62, },
76
.scale = 1,
77
.sat = true,
78
};
79
80
/*
81
* YUV limited-range to YUV full-range
82
*
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
86
*/
87
static const struct ipu_ic_csc_params yuvl2yuvf = {
88
.coeff = {
89
{ 149, 0, 0, },
90
{ 0, 146, 0, },
91
{ 0, 0, 146, },
92
},
93
.offset = { -37, -35, -35, },
94
.scale = 2,
95
};
96
97
static const struct ipu_ic_csc_params *rgb2rgb[] = {
98
&identity,
99
&rgbf2rgbl,
100
&rgbl2rgbf,
101
&identity,
102
};
103
104
static const struct ipu_ic_csc_params *yuv2yuv[] = {
105
&identity,
106
&yuvf2yuvl,
107
&yuvl2yuvf,
108
&identity,
109
};
110
111
/*
112
* BT.601 RGB full-range to YUV full-range
113
*
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
117
*/
118
static const struct ipu_ic_csc_params rgbf2yuvf_601 = {
119
.coeff = {
120
{ 77, 150, 29, },
121
{ -43, -85, 128, },
122
{ 128, -107, -21, },
123
},
124
.offset = { 0, 512, 512, },
125
.scale = 1,
126
};
127
128
/* BT.601 RGB full-range to YUV limited-range */
129
static const struct ipu_ic_csc_params rgbf2yuvl_601 = {
130
.coeff = {
131
{ 66, 129, 25, },
132
{ -38, -74, 112, },
133
{ 112, -94, -18, },
134
},
135
.offset = { 64, 512, 512, },
136
.scale = 1,
137
.sat = true,
138
};
139
140
/* BT.601 RGB limited-range to YUV full-range */
141
static const struct ipu_ic_csc_params rgbl2yuvf_601 = {
142
.coeff = {
143
{ 89, 175, 34, },
144
{ -50, -99, 149, },
145
{ 149, -125, -24, },
146
},
147
.offset = { -75, 512, 512, },
148
.scale = 1,
149
};
150
151
/* BT.601 RGB limited-range to YUV limited-range */
152
static const struct ipu_ic_csc_params rgbl2yuvl_601 = {
153
.coeff = {
154
{ 77, 150, 29, },
155
{ -44, -87, 131, },
156
{ 131, -110, -21, },
157
},
158
.offset = { 0, 512, 512, },
159
.scale = 1,
160
.sat = true,
161
};
162
163
/*
164
* BT.601 YUV full-range to RGB full-range
165
*
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)
169
*
170
* equivalently (factoring out the offsets):
171
*
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
175
*/
176
static const struct ipu_ic_csc_params yuvf2rgbf_601 = {
177
.coeff = {
178
{ 128, 0, 179, },
179
{ 128, -44, -91, },
180
{ 128, 227, 0, },
181
},
182
.offset = { -359, 271, -454, },
183
.scale = 2,
184
};
185
186
/* BT.601 YUV full-range to RGB limited-range */
187
static const struct ipu_ic_csc_params yuvf2rgbl_601 = {
188
.coeff = {
189
{ 110, 0, 154, },
190
{ 110, -38, -78, },
191
{ 110, 195, 0, },
192
},
193
.offset = { -276, 265, -358, },
194
.scale = 2,
195
};
196
197
/* BT.601 YUV limited-range to RGB full-range */
198
static const struct ipu_ic_csc_params yuvl2rgbf_601 = {
199
.coeff = {
200
{ 75, 0, 102, },
201
{ 75, -25, -52, },
202
{ 75, 129, 0, },
203
},
204
.offset = { -223, 136, -277, },
205
.scale = 3,
206
};
207
208
/* BT.601 YUV limited-range to RGB limited-range */
209
static const struct ipu_ic_csc_params yuvl2rgbl_601 = {
210
.coeff = {
211
{ 128, 0, 175, },
212
{ 128, -43, -89, },
213
{ 128, 222, 0, },
214
},
215
.offset = { -351, 265, -443, },
216
.scale = 2,
217
};
218
219
static const struct ipu_ic_csc_params *rgb2yuv_601[] = {
220
&rgbf2yuvf_601,
221
&rgbf2yuvl_601,
222
&rgbl2yuvf_601,
223
&rgbl2yuvl_601,
224
};
225
226
static const struct ipu_ic_csc_params *yuv2rgb_601[] = {
227
&yuvf2rgbf_601,
228
&yuvf2rgbl_601,
229
&yuvl2rgbf_601,
230
&yuvl2rgbl_601,
231
};
232
233
/*
234
* REC.709 encoding from RGB full range to YUV full range:
235
*
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
239
*/
240
static const struct ipu_ic_csc_params rgbf2yuvf_709 = {
241
.coeff = {
242
{ 54, 183, 19 },
243
{ -29, -99, 128 },
244
{ 128, -116, -12 },
245
},
246
.offset = { 0, 512, 512 },
247
.scale = 1,
248
};
249
250
/* Rec.709 RGB full-range to YUV limited-range */
251
static const struct ipu_ic_csc_params rgbf2yuvl_709 = {
252
.coeff = {
253
{ 47, 157, 16, },
254
{ -26, -87, 112, },
255
{ 112, -102, -10, },
256
},
257
.offset = { 64, 512, 512, },
258
.scale = 1,
259
.sat = true,
260
};
261
262
/* Rec.709 RGB limited-range to YUV full-range */
263
static const struct ipu_ic_csc_params rgbl2yuvf_709 = {
264
.coeff = {
265
{ 63, 213, 22, },
266
{ -34, -115, 149, },
267
{ 149, -135, -14, },
268
},
269
.offset = { -75, 512, 512, },
270
.scale = 1,
271
};
272
273
/* Rec.709 RGB limited-range to YUV limited-range */
274
static const struct ipu_ic_csc_params rgbl2yuvl_709 = {
275
.coeff = {
276
{ 54, 183, 18, },
277
{ -30, -101, 131, },
278
{ 131, -119, -12, },
279
},
280
.offset = { 0, 512, 512, },
281
.scale = 1,
282
.sat = true,
283
};
284
285
/*
286
* Inverse REC.709 encoding from YUV full range to RGB full range:
287
*
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)
291
*
292
* equivalently (factoring out the offsets):
293
*
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
297
*/
298
static const struct ipu_ic_csc_params yuvf2rgbf_709 = {
299
.coeff = {
300
{ 128, 0, 202 },
301
{ 128, -24, -60 },
302
{ 128, 238, 0 },
303
},
304
.offset = { -403, 168, -475 },
305
.scale = 2,
306
};
307
308
/* Rec.709 YUV full-range to RGB limited-range */
309
static const struct ipu_ic_csc_params yuvf2rgbl_709 = {
310
.coeff = {
311
{ 110, 0, 173, },
312
{ 110, -21, -51, },
313
{ 110, 204, 0, },
314
},
315
.offset = { -314, 176, -376, },
316
.scale = 2,
317
};
318
319
/* Rec.709 YUV limited-range to RGB full-range */
320
static const struct ipu_ic_csc_params yuvl2rgbf_709 = {
321
.coeff = {
322
{ 75, 0, 115, },
323
{ 75, -14, -34, },
324
{ 75, 135, 0, },
325
},
326
.offset = { -248, 77, -289, },
327
.scale = 3,
328
};
329
330
/* Rec.709 YUV limited-range to RGB limited-range */
331
static const struct ipu_ic_csc_params yuvl2rgbl_709 = {
332
.coeff = {
333
{ 128, 0, 197, },
334
{ 128, -23, -59, },
335
{ 128, 232, 0, },
336
},
337
.offset = { -394, 164, -464, },
338
.scale = 2,
339
};
340
341
static const struct ipu_ic_csc_params *rgb2yuv_709[] = {
342
&rgbf2yuvf_709,
343
&rgbf2yuvl_709,
344
&rgbl2yuvf_709,
345
&rgbl2yuvl_709,
346
};
347
348
static const struct ipu_ic_csc_params *yuv2rgb_709[] = {
349
&yuvf2rgbf_709,
350
&yuvf2rgbl_709,
351
&yuvl2rgbf_709,
352
&yuvl2rgbl_709,
353
};
354
355
static int calc_csc_coeffs(struct ipu_ic_csc *csc)
356
{
357
const struct ipu_ic_csc_params **params_tbl;
358
int tbl_idx;
359
360
tbl_idx = (QUANT_MAP(csc->in_cs.quant) << 1) |
361
QUANT_MAP(csc->out_cs.quant);
362
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];
366
367
return 0;
368
}
369
370
/* YUV <-> RGB encoding is required */
371
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;
376
break;
377
case V4L2_YCBCR_ENC_709:
378
params_tbl = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ?
379
yuv2rgb_709 : rgb2yuv_709;
380
break;
381
default:
382
return -ENOTSUPP;
383
}
384
385
csc->params = *params_tbl[tbl_idx];
386
387
return 0;
388
}
389
390
int __ipu_ic_calc_csc(struct ipu_ic_csc *csc)
391
{
392
return calc_csc_coeffs(csc);
393
}
394
EXPORT_SYMBOL_GPL(__ipu_ic_calc_csc);
395
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)
403
{
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);
406
407
return __ipu_ic_calc_csc(csc);
408
}
409
EXPORT_SYMBOL_GPL(ipu_ic_calc_csc);
410
411