1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * v4l2-tpg-core.c - Test Pattern Generator
4 *
5 * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the
6 * vivi.c source for the copyright information of those functions.
7 *
8 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
9 */
10
11#include <linux/module.h>
12#include <media/tpg/v4l2-tpg.h>
13
14/* Must remain in sync with enum tpg_pattern */
15const char * const tpg_pattern_strings[] = {
16 "75% Colorbar",
17 "100% Colorbar",
18 "CSC Colorbar",
19 "Horizontal 100% Colorbar",
20 "100% Color Squares",
21 "100% Black",
22 "100% White",
23 "100% Red",
24 "100% Green",
25 "100% Blue",
26 "16x16 Checkers",
27 "2x2 Checkers",
28 "1x1 Checkers",
29 "2x2 Red/Green Checkers",
30 "1x1 Red/Green Checkers",
31 "Alternating Hor Lines",
32 "Alternating Vert Lines",
33 "One Pixel Wide Cross",
34 "Two Pixels Wide Cross",
35 "Ten Pixels Wide Cross",
36 "Gray Ramp",
37 "Noise",
38 NULL
39};
40EXPORT_SYMBOL_GPL(tpg_pattern_strings);
41
42/* Must remain in sync with enum tpg_aspect */
43const char * const tpg_aspect_strings[] = {
44 "Source Width x Height",
45 "4x3",
46 "14x9",
47 "16x9",
48 "16x9 Anamorphic",
49 NULL
50};
51EXPORT_SYMBOL_GPL(tpg_aspect_strings);
52
53/*
54 * Sine table: sin[0] = 127 * sin(-180 degrees)
55 * sin[128] = 127 * sin(0 degrees)
56 * sin[256] = 127 * sin(180 degrees)
57 */
58static const s8 sin[257] = {
59 0, -4, -7, -11, -13, -18, -20, -22, -26, -29, -33, -35, -37, -41, -43, -48,
60 -50, -52, -56, -58, -62, -63, -65, -69, -71, -75, -76, -78, -82, -83, -87, -88,
61 -90, -93, -94, -97, -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
62 -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
63 -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
64 -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100, -97, -96, -93, -91,
65 -90, -87, -85, -82, -80, -76, -75, -73, -69, -67, -63, -62, -60, -56, -54, -50,
66 -48, -46, -41, -39, -35, -33, -31, -26, -24, -20, -18, -15, -11, -9, -4, -2,
67 0, 2, 4, 9, 11, 15, 18, 20, 24, 26, 31, 33, 35, 39, 41, 46,
68 48, 50, 54, 56, 60, 62, 64, 67, 69, 73, 75, 76, 80, 82, 85, 87,
69 90, 91, 93, 96, 97, 100, 101, 103, 105, 107, 109, 110, 111, 113, 114, 116,
70 117, 118, 119, 120, 121, 122, 123, 124, 124, 125, 125, 126, 126, 127, 127, 127,
71 127, 127, 127, 127, 127, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119,
72 118, 117, 115, 114, 112, 111, 110, 108, 107, 104, 103, 101, 99, 97, 94, 93,
73 90, 88, 87, 83, 82, 78, 76, 75, 71, 69, 65, 64, 62, 58, 56, 52,
74 50, 48, 43, 41, 37, 35, 33, 29, 26, 22, 20, 18, 13, 11, 7, 4,
75 0,
76};
77
78#define cos(idx) sin[((idx) + 64) % sizeof(sin)]
79
80/* Global font descriptor */
81static const u8 *font8x16;
82
83void tpg_set_font(const u8 *f)
84{
85 font8x16 = f;
86}
87EXPORT_SYMBOL_GPL(tpg_set_font);
88
89void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
90{
91 memset(tpg, 0, sizeof(*tpg));
92 tpg->scaled_width = tpg->src_width = w;
93 tpg->src_height = tpg->buf_height = h;
94 tpg->crop.width = tpg->compose.width = w;
95 tpg->crop.height = tpg->compose.height = h;
96 tpg->recalc_colors = true;
97 tpg->recalc_square_border = true;
98 tpg->brightness = 128;
99 tpg->contrast = 128;
100 tpg->saturation = 128;
101 tpg->hue = 0;
102 tpg->mv_hor_mode = TPG_MOVE_NONE;
103 tpg->mv_vert_mode = TPG_MOVE_NONE;
104 tpg->field = V4L2_FIELD_NONE;
105 tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24);
106 tpg->colorspace = V4L2_COLORSPACE_SRGB;
107 tpg->perc_fill = 100;
108 tpg->hsv_enc = V4L2_HSV_ENC_180;
109}
110EXPORT_SYMBOL_GPL(tpg_init);
111
112int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
113{
114 unsigned pat;
115 unsigned plane;
116 int ret = 0;
117
118 tpg->max_line_width = max_w;
119 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
120 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
121 unsigned pixelsz = plane ? 2 : 4;
122
123 tpg->lines[pat][plane] =
124 vzalloc(array3_size(max_w, 2, pixelsz));
125 if (!tpg->lines[pat][plane]) {
126 ret = -ENOMEM;
127 goto free_lines;
128 }
129 if (plane == 0)
130 continue;
131 tpg->downsampled_lines[pat][plane] =
132 vzalloc(array3_size(max_w, 2, pixelsz));
133 if (!tpg->downsampled_lines[pat][plane]) {
134 ret = -ENOMEM;
135 goto free_lines;
136 }
137 }
138 }
139 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
140 unsigned pixelsz = plane ? 2 : 4;
141
142 tpg->contrast_line[plane] =
143 vzalloc(array_size(pixelsz, max_w));
144 if (!tpg->contrast_line[plane]) {
145 ret = -ENOMEM;
146 goto free_contrast_line;
147 }
148 tpg->black_line[plane] =
149 vzalloc(array_size(pixelsz, max_w));
150 if (!tpg->black_line[plane]) {
151 ret = -ENOMEM;
152 goto free_contrast_line;
153 }
154 tpg->random_line[plane] =
155 vzalloc(array3_size(max_w, 2, pixelsz));
156 if (!tpg->random_line[plane]) {
157 ret = -ENOMEM;
158 goto free_contrast_line;
159 }
160 }
161 return 0;
162
163free_contrast_line:
164 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
165 vfree(addr: tpg->contrast_line[plane]);
166 vfree(addr: tpg->black_line[plane]);
167 vfree(addr: tpg->random_line[plane]);
168 tpg->contrast_line[plane] = NULL;
169 tpg->black_line[plane] = NULL;
170 tpg->random_line[plane] = NULL;
171 }
172free_lines:
173 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
174 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
175 vfree(addr: tpg->lines[pat][plane]);
176 tpg->lines[pat][plane] = NULL;
177 if (plane == 0)
178 continue;
179 vfree(addr: tpg->downsampled_lines[pat][plane]);
180 tpg->downsampled_lines[pat][plane] = NULL;
181 }
182 return ret;
183}
184EXPORT_SYMBOL_GPL(tpg_alloc);
185
186void tpg_free(struct tpg_data *tpg)
187{
188 unsigned pat;
189 unsigned plane;
190
191 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
192 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
193 vfree(addr: tpg->lines[pat][plane]);
194 tpg->lines[pat][plane] = NULL;
195 if (plane == 0)
196 continue;
197 vfree(addr: tpg->downsampled_lines[pat][plane]);
198 tpg->downsampled_lines[pat][plane] = NULL;
199 }
200 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
201 vfree(addr: tpg->contrast_line[plane]);
202 vfree(addr: tpg->black_line[plane]);
203 vfree(addr: tpg->random_line[plane]);
204 tpg->contrast_line[plane] = NULL;
205 tpg->black_line[plane] = NULL;
206 tpg->random_line[plane] = NULL;
207 }
208}
209EXPORT_SYMBOL_GPL(tpg_free);
210
211bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
212{
213 tpg->fourcc = fourcc;
214 tpg->planes = 1;
215 tpg->buffers = 1;
216 tpg->recalc_colors = true;
217 tpg->interleaved = false;
218 tpg->vdownsampling[0] = 1;
219 tpg->hdownsampling[0] = 1;
220 tpg->hmask[0] = ~0;
221 tpg->hmask[1] = ~0;
222 tpg->hmask[2] = ~0;
223
224 switch (fourcc) {
225 case V4L2_PIX_FMT_SBGGR8:
226 case V4L2_PIX_FMT_SGBRG8:
227 case V4L2_PIX_FMT_SGRBG8:
228 case V4L2_PIX_FMT_SRGGB8:
229 case V4L2_PIX_FMT_SBGGR10:
230 case V4L2_PIX_FMT_SGBRG10:
231 case V4L2_PIX_FMT_SGRBG10:
232 case V4L2_PIX_FMT_SRGGB10:
233 case V4L2_PIX_FMT_SBGGR12:
234 case V4L2_PIX_FMT_SGBRG12:
235 case V4L2_PIX_FMT_SGRBG12:
236 case V4L2_PIX_FMT_SRGGB12:
237 case V4L2_PIX_FMT_SBGGR16:
238 case V4L2_PIX_FMT_SGBRG16:
239 case V4L2_PIX_FMT_SGRBG16:
240 case V4L2_PIX_FMT_SRGGB16:
241 tpg->interleaved = true;
242 tpg->vdownsampling[1] = 1;
243 tpg->hdownsampling[1] = 1;
244 tpg->planes = 2;
245 fallthrough;
246 case V4L2_PIX_FMT_RGB332:
247 case V4L2_PIX_FMT_RGB565:
248 case V4L2_PIX_FMT_RGB565X:
249 case V4L2_PIX_FMT_RGB444:
250 case V4L2_PIX_FMT_XRGB444:
251 case V4L2_PIX_FMT_ARGB444:
252 case V4L2_PIX_FMT_RGBX444:
253 case V4L2_PIX_FMT_RGBA444:
254 case V4L2_PIX_FMT_XBGR444:
255 case V4L2_PIX_FMT_ABGR444:
256 case V4L2_PIX_FMT_BGRX444:
257 case V4L2_PIX_FMT_BGRA444:
258 case V4L2_PIX_FMT_RGB555:
259 case V4L2_PIX_FMT_XRGB555:
260 case V4L2_PIX_FMT_ARGB555:
261 case V4L2_PIX_FMT_RGBX555:
262 case V4L2_PIX_FMT_RGBA555:
263 case V4L2_PIX_FMT_XBGR555:
264 case V4L2_PIX_FMT_ABGR555:
265 case V4L2_PIX_FMT_BGRX555:
266 case V4L2_PIX_FMT_BGRA555:
267 case V4L2_PIX_FMT_RGB555X:
268 case V4L2_PIX_FMT_XRGB555X:
269 case V4L2_PIX_FMT_ARGB555X:
270 case V4L2_PIX_FMT_BGR666:
271 case V4L2_PIX_FMT_RGB24:
272 case V4L2_PIX_FMT_BGR24:
273 case V4L2_PIX_FMT_RGB32:
274 case V4L2_PIX_FMT_BGR32:
275 case V4L2_PIX_FMT_XRGB32:
276 case V4L2_PIX_FMT_XBGR32:
277 case V4L2_PIX_FMT_ARGB32:
278 case V4L2_PIX_FMT_ABGR32:
279 case V4L2_PIX_FMT_RGBX32:
280 case V4L2_PIX_FMT_BGRX32:
281 case V4L2_PIX_FMT_RGBA32:
282 case V4L2_PIX_FMT_BGRA32:
283 tpg->color_enc = TGP_COLOR_ENC_RGB;
284 break;
285 case V4L2_PIX_FMT_GREY:
286 case V4L2_PIX_FMT_Y10:
287 case V4L2_PIX_FMT_Y12:
288 case V4L2_PIX_FMT_Y16:
289 case V4L2_PIX_FMT_Y16_BE:
290 case V4L2_PIX_FMT_Z16:
291 tpg->color_enc = TGP_COLOR_ENC_LUMA;
292 break;
293 case V4L2_PIX_FMT_YUV444:
294 case V4L2_PIX_FMT_YUV555:
295 case V4L2_PIX_FMT_YUV565:
296 case V4L2_PIX_FMT_YUV32:
297 case V4L2_PIX_FMT_AYUV32:
298 case V4L2_PIX_FMT_XYUV32:
299 case V4L2_PIX_FMT_VUYA32:
300 case V4L2_PIX_FMT_VUYX32:
301 case V4L2_PIX_FMT_YUVA32:
302 case V4L2_PIX_FMT_YUVX32:
303 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
304 break;
305 case V4L2_PIX_FMT_YUV420M:
306 case V4L2_PIX_FMT_YVU420M:
307 tpg->buffers = 3;
308 fallthrough;
309 case V4L2_PIX_FMT_YUV420:
310 case V4L2_PIX_FMT_YVU420:
311 tpg->vdownsampling[1] = 2;
312 tpg->vdownsampling[2] = 2;
313 tpg->hdownsampling[1] = 2;
314 tpg->hdownsampling[2] = 2;
315 tpg->planes = 3;
316 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
317 break;
318 case V4L2_PIX_FMT_YUV422M:
319 case V4L2_PIX_FMT_YVU422M:
320 tpg->buffers = 3;
321 fallthrough;
322 case V4L2_PIX_FMT_YUV422P:
323 tpg->vdownsampling[1] = 1;
324 tpg->vdownsampling[2] = 1;
325 tpg->hdownsampling[1] = 2;
326 tpg->hdownsampling[2] = 2;
327 tpg->planes = 3;
328 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
329 break;
330 case V4L2_PIX_FMT_NV16M:
331 case V4L2_PIX_FMT_NV61M:
332 tpg->buffers = 2;
333 fallthrough;
334 case V4L2_PIX_FMT_NV16:
335 case V4L2_PIX_FMT_NV61:
336 tpg->vdownsampling[1] = 1;
337 tpg->hdownsampling[1] = 1;
338 tpg->hmask[1] = ~1;
339 tpg->planes = 2;
340 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
341 break;
342 case V4L2_PIX_FMT_NV12M:
343 case V4L2_PIX_FMT_NV21M:
344 tpg->buffers = 2;
345 fallthrough;
346 case V4L2_PIX_FMT_NV12:
347 case V4L2_PIX_FMT_NV21:
348 tpg->vdownsampling[1] = 2;
349 tpg->hdownsampling[1] = 1;
350 tpg->hmask[1] = ~1;
351 tpg->planes = 2;
352 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
353 break;
354 case V4L2_PIX_FMT_YUV444M:
355 case V4L2_PIX_FMT_YVU444M:
356 tpg->buffers = 3;
357 tpg->planes = 3;
358 tpg->vdownsampling[1] = 1;
359 tpg->vdownsampling[2] = 1;
360 tpg->hdownsampling[1] = 1;
361 tpg->hdownsampling[2] = 1;
362 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
363 break;
364 case V4L2_PIX_FMT_NV24:
365 case V4L2_PIX_FMT_NV42:
366 tpg->vdownsampling[1] = 1;
367 tpg->hdownsampling[1] = 1;
368 tpg->planes = 2;
369 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
370 break;
371 case V4L2_PIX_FMT_YUYV:
372 case V4L2_PIX_FMT_UYVY:
373 case V4L2_PIX_FMT_YVYU:
374 case V4L2_PIX_FMT_VYUY:
375 tpg->hmask[0] = ~1;
376 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
377 break;
378 case V4L2_PIX_FMT_HSV24:
379 case V4L2_PIX_FMT_HSV32:
380 tpg->color_enc = TGP_COLOR_ENC_HSV;
381 break;
382 default:
383 return false;
384 }
385
386 switch (fourcc) {
387 case V4L2_PIX_FMT_GREY:
388 case V4L2_PIX_FMT_RGB332:
389 tpg->twopixelsize[0] = 2;
390 break;
391 case V4L2_PIX_FMT_RGB565:
392 case V4L2_PIX_FMT_RGB565X:
393 case V4L2_PIX_FMT_RGB444:
394 case V4L2_PIX_FMT_XRGB444:
395 case V4L2_PIX_FMT_ARGB444:
396 case V4L2_PIX_FMT_RGBX444:
397 case V4L2_PIX_FMT_RGBA444:
398 case V4L2_PIX_FMT_XBGR444:
399 case V4L2_PIX_FMT_ABGR444:
400 case V4L2_PIX_FMT_BGRX444:
401 case V4L2_PIX_FMT_BGRA444:
402 case V4L2_PIX_FMT_RGB555:
403 case V4L2_PIX_FMT_XRGB555:
404 case V4L2_PIX_FMT_ARGB555:
405 case V4L2_PIX_FMT_RGBX555:
406 case V4L2_PIX_FMT_RGBA555:
407 case V4L2_PIX_FMT_XBGR555:
408 case V4L2_PIX_FMT_ABGR555:
409 case V4L2_PIX_FMT_BGRX555:
410 case V4L2_PIX_FMT_BGRA555:
411 case V4L2_PIX_FMT_RGB555X:
412 case V4L2_PIX_FMT_XRGB555X:
413 case V4L2_PIX_FMT_ARGB555X:
414 case V4L2_PIX_FMT_YUYV:
415 case V4L2_PIX_FMT_UYVY:
416 case V4L2_PIX_FMT_YVYU:
417 case V4L2_PIX_FMT_VYUY:
418 case V4L2_PIX_FMT_YUV444:
419 case V4L2_PIX_FMT_YUV555:
420 case V4L2_PIX_FMT_YUV565:
421 case V4L2_PIX_FMT_Y10:
422 case V4L2_PIX_FMT_Y12:
423 case V4L2_PIX_FMT_Y16:
424 case V4L2_PIX_FMT_Y16_BE:
425 case V4L2_PIX_FMT_Z16:
426 tpg->twopixelsize[0] = 2 * 2;
427 break;
428 case V4L2_PIX_FMT_RGB24:
429 case V4L2_PIX_FMT_BGR24:
430 case V4L2_PIX_FMT_HSV24:
431 tpg->twopixelsize[0] = 2 * 3;
432 break;
433 case V4L2_PIX_FMT_BGR666:
434 case V4L2_PIX_FMT_RGB32:
435 case V4L2_PIX_FMT_BGR32:
436 case V4L2_PIX_FMT_XRGB32:
437 case V4L2_PIX_FMT_XBGR32:
438 case V4L2_PIX_FMT_ARGB32:
439 case V4L2_PIX_FMT_ABGR32:
440 case V4L2_PIX_FMT_RGBX32:
441 case V4L2_PIX_FMT_BGRX32:
442 case V4L2_PIX_FMT_RGBA32:
443 case V4L2_PIX_FMT_BGRA32:
444 case V4L2_PIX_FMT_YUV32:
445 case V4L2_PIX_FMT_AYUV32:
446 case V4L2_PIX_FMT_XYUV32:
447 case V4L2_PIX_FMT_VUYA32:
448 case V4L2_PIX_FMT_VUYX32:
449 case V4L2_PIX_FMT_YUVA32:
450 case V4L2_PIX_FMT_YUVX32:
451 case V4L2_PIX_FMT_HSV32:
452 tpg->twopixelsize[0] = 2 * 4;
453 break;
454 case V4L2_PIX_FMT_NV12:
455 case V4L2_PIX_FMT_NV21:
456 case V4L2_PIX_FMT_NV12M:
457 case V4L2_PIX_FMT_NV21M:
458 case V4L2_PIX_FMT_NV16:
459 case V4L2_PIX_FMT_NV61:
460 case V4L2_PIX_FMT_NV16M:
461 case V4L2_PIX_FMT_NV61M:
462 case V4L2_PIX_FMT_SBGGR8:
463 case V4L2_PIX_FMT_SGBRG8:
464 case V4L2_PIX_FMT_SGRBG8:
465 case V4L2_PIX_FMT_SRGGB8:
466 tpg->twopixelsize[0] = 2;
467 tpg->twopixelsize[1] = 2;
468 break;
469 case V4L2_PIX_FMT_SRGGB10:
470 case V4L2_PIX_FMT_SGRBG10:
471 case V4L2_PIX_FMT_SGBRG10:
472 case V4L2_PIX_FMT_SBGGR10:
473 case V4L2_PIX_FMT_SRGGB12:
474 case V4L2_PIX_FMT_SGRBG12:
475 case V4L2_PIX_FMT_SGBRG12:
476 case V4L2_PIX_FMT_SBGGR12:
477 case V4L2_PIX_FMT_SRGGB16:
478 case V4L2_PIX_FMT_SGRBG16:
479 case V4L2_PIX_FMT_SGBRG16:
480 case V4L2_PIX_FMT_SBGGR16:
481 tpg->twopixelsize[0] = 4;
482 tpg->twopixelsize[1] = 4;
483 break;
484 case V4L2_PIX_FMT_YUV444M:
485 case V4L2_PIX_FMT_YVU444M:
486 case V4L2_PIX_FMT_YUV422M:
487 case V4L2_PIX_FMT_YVU422M:
488 case V4L2_PIX_FMT_YUV422P:
489 case V4L2_PIX_FMT_YUV420:
490 case V4L2_PIX_FMT_YVU420:
491 case V4L2_PIX_FMT_YUV420M:
492 case V4L2_PIX_FMT_YVU420M:
493 tpg->twopixelsize[0] = 2;
494 tpg->twopixelsize[1] = 2;
495 tpg->twopixelsize[2] = 2;
496 break;
497 case V4L2_PIX_FMT_NV24:
498 case V4L2_PIX_FMT_NV42:
499 tpg->twopixelsize[0] = 2;
500 tpg->twopixelsize[1] = 4;
501 break;
502 }
503 return true;
504}
505EXPORT_SYMBOL_GPL(tpg_s_fourcc);
506
507void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
508 const struct v4l2_rect *compose)
509{
510 tpg->crop = *crop;
511 tpg->compose = *compose;
512 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
513 tpg->crop.width - 1) / tpg->crop.width;
514 tpg->scaled_width &= ~1;
515 if (tpg->scaled_width > tpg->max_line_width)
516 tpg->scaled_width = tpg->max_line_width;
517 if (tpg->scaled_width < 2)
518 tpg->scaled_width = 2;
519 tpg->recalc_lines = true;
520}
521EXPORT_SYMBOL_GPL(tpg_s_crop_compose);
522
523void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
524 u32 field)
525{
526 unsigned p;
527
528 tpg->src_width = width;
529 tpg->src_height = height;
530 tpg->field = field;
531 tpg->buf_height = height;
532 if (V4L2_FIELD_HAS_T_OR_B(field))
533 tpg->buf_height /= 2;
534 tpg->scaled_width = width;
535 tpg->crop.top = tpg->crop.left = 0;
536 tpg->crop.width = width;
537 tpg->crop.height = height;
538 tpg->compose.top = tpg->compose.left = 0;
539 tpg->compose.width = width;
540 tpg->compose.height = tpg->buf_height;
541 for (p = 0; p < tpg->planes; p++)
542 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
543 (2 * tpg->hdownsampling[p]);
544 tpg->recalc_square_border = true;
545}
546EXPORT_SYMBOL_GPL(tpg_reset_source);
547
548static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
549{
550 switch (tpg->pattern) {
551 case TPG_PAT_BLACK:
552 return TPG_COLOR_100_WHITE;
553 case TPG_PAT_CSC_COLORBAR:
554 return TPG_COLOR_CSC_BLACK;
555 default:
556 return TPG_COLOR_100_BLACK;
557 }
558}
559
560static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
561{
562 switch (tpg->pattern) {
563 case TPG_PAT_75_COLORBAR:
564 case TPG_PAT_CSC_COLORBAR:
565 return TPG_COLOR_CSC_WHITE;
566 case TPG_PAT_BLACK:
567 return TPG_COLOR_100_BLACK;
568 default:
569 return TPG_COLOR_100_WHITE;
570 }
571}
572
573static inline int rec709_to_linear(int v)
574{
575 v = clamp(v, 0, 0xff0);
576 return tpg_rec709_to_linear[v];
577}
578
579static inline int linear_to_rec709(int v)
580{
581 v = clamp(v, 0, 0xff0);
582 return tpg_linear_to_rec709[v];
583}
584
585static void color_to_hsv(struct tpg_data *tpg, int r, int g, int b,
586 int *h, int *s, int *v)
587{
588 int max_rgb, min_rgb, diff_rgb;
589 int aux;
590 int third;
591 int third_size;
592
593 r >>= 4;
594 g >>= 4;
595 b >>= 4;
596
597 /* Value */
598 max_rgb = max3(r, g, b);
599 *v = max_rgb;
600 if (!max_rgb) {
601 *h = 0;
602 *s = 0;
603 return;
604 }
605
606 /* Saturation */
607 min_rgb = min3(r, g, b);
608 diff_rgb = max_rgb - min_rgb;
609 aux = 255 * diff_rgb;
610 aux += max_rgb / 2;
611 aux /= max_rgb;
612 *s = aux;
613 if (!aux) {
614 *h = 0;
615 return;
616 }
617
618 third_size = (tpg->real_hsv_enc == V4L2_HSV_ENC_180) ? 60 : 85;
619
620 /* Hue */
621 if (max_rgb == r) {
622 aux = g - b;
623 third = 0;
624 } else if (max_rgb == g) {
625 aux = b - r;
626 third = third_size;
627 } else {
628 aux = r - g;
629 third = third_size * 2;
630 }
631
632 aux *= third_size / 2;
633 aux += diff_rgb / 2;
634 aux /= diff_rgb;
635 aux += third;
636
637 /* Clamp Hue */
638 if (tpg->real_hsv_enc == V4L2_HSV_ENC_180) {
639 if (aux < 0)
640 aux += 180;
641 else if (aux > 180)
642 aux -= 180;
643 } else {
644 aux = aux & 0xff;
645 }
646
647 *h = aux;
648}
649
650static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
651 int y_offset, int *y, int *cb, int *cr)
652{
653 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
654 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
655 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
656}
657
658static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
659 int *y, int *cb, int *cr)
660{
661#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
662
663 static const int bt601[3][3] = {
664 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
665 { COEFF(-0.1687, 224), COEFF(-0.3313, 224), COEFF(0.5, 224) },
666 { COEFF(0.5, 224), COEFF(-0.4187, 224), COEFF(-0.0813, 224) },
667 };
668 static const int bt601_full[3][3] = {
669 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
670 { COEFF(-0.1687, 255), COEFF(-0.3313, 255), COEFF(0.5, 255) },
671 { COEFF(0.5, 255), COEFF(-0.4187, 255), COEFF(-0.0813, 255) },
672 };
673 static const int rec709[3][3] = {
674 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
675 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
676 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
677 };
678 static const int rec709_full[3][3] = {
679 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
680 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
681 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
682 };
683 static const int smpte240m[3][3] = {
684 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
685 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
686 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
687 };
688 static const int smpte240m_full[3][3] = {
689 { COEFF(0.212, 255), COEFF(0.701, 255), COEFF(0.087, 255) },
690 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255) },
691 { COEFF(0.5, 255), COEFF(-0.445, 255), COEFF(-0.055, 255) },
692 };
693 static const int bt2020[3][3] = {
694 { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
695 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
696 { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
697 };
698 static const int bt2020_full[3][3] = {
699 { COEFF(0.2627, 255), COEFF(0.6780, 255), COEFF(0.0593, 255) },
700 { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255) },
701 { COEFF(0.5, 255), COEFF(-0.4598, 255), COEFF(-0.0402, 255) },
702 };
703 static const int bt2020c[4] = {
704 COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224),
705 COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224),
706 };
707 static const int bt2020c_full[4] = {
708 COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255),
709 COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255),
710 };
711
712 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
713 unsigned y_offset = full ? 0 : 16;
714 int lin_y, yc;
715
716 switch (tpg->real_ycbcr_enc) {
717 case V4L2_YCBCR_ENC_601:
718 rgb2ycbcr(m: full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
719 break;
720 case V4L2_YCBCR_ENC_XV601:
721 /* Ignore quantization range, there is only one possible
722 * Y'CbCr encoding. */
723 rgb2ycbcr(m: bt601, r, g, b, y_offset: 16, y, cb, cr);
724 break;
725 case V4L2_YCBCR_ENC_XV709:
726 /* Ignore quantization range, there is only one possible
727 * Y'CbCr encoding. */
728 rgb2ycbcr(m: rec709, r, g, b, y_offset: 16, y, cb, cr);
729 break;
730 case V4L2_YCBCR_ENC_BT2020:
731 rgb2ycbcr(m: full ? bt2020_full : bt2020, r, g, b, y_offset, y, cb, cr);
732 break;
733 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
734 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(v: r) +
735 COEFF(0.6780, 255) * rec709_to_linear(v: g) +
736 COEFF(0.0593, 255) * rec709_to_linear(v: b)) >> 16;
737 yc = linear_to_rec709(v: lin_y);
738 *y = full ? yc : (yc * 219) / 255 + (16 << 4);
739 if (b <= yc)
740 *cb = (((b - yc) * (full ? bt2020c_full[0] : bt2020c[0])) >> 16) + (128 << 4);
741 else
742 *cb = (((b - yc) * (full ? bt2020c_full[1] : bt2020c[1])) >> 16) + (128 << 4);
743 if (r <= yc)
744 *cr = (((r - yc) * (full ? bt2020c_full[2] : bt2020c[2])) >> 16) + (128 << 4);
745 else
746 *cr = (((r - yc) * (full ? bt2020c_full[3] : bt2020c[3])) >> 16) + (128 << 4);
747 break;
748 case V4L2_YCBCR_ENC_SMPTE240M:
749 rgb2ycbcr(m: full ? smpte240m_full : smpte240m, r, g, b, y_offset, y, cb, cr);
750 break;
751 case V4L2_YCBCR_ENC_709:
752 default:
753 rgb2ycbcr(m: full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
754 break;
755 }
756}
757
758static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
759 int y_offset, int *r, int *g, int *b)
760{
761 y -= y_offset << 4;
762 cb -= 128 << 4;
763 cr -= 128 << 4;
764 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
765 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
766 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
767 *r = clamp(*r >> 12, 0, 0xff0);
768 *g = clamp(*g >> 12, 0, 0xff0);
769 *b = clamp(*b >> 12, 0, 0xff0);
770}
771
772static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
773 int *r, int *g, int *b)
774{
775#undef COEFF
776#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
777 static const int bt601[3][3] = {
778 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
779 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
780 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
781 };
782 static const int bt601_full[3][3] = {
783 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
784 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
785 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
786 };
787 static const int rec709[3][3] = {
788 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
789 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
790 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
791 };
792 static const int rec709_full[3][3] = {
793 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
794 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
795 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
796 };
797 static const int smpte240m[3][3] = {
798 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
799 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
800 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
801 };
802 static const int smpte240m_full[3][3] = {
803 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5756, 255) },
804 { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },
805 { COEFF(1, 255), COEFF(1.8270, 255), COEFF(0, 255) },
806 };
807 static const int bt2020[3][3] = {
808 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
809 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
810 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
811 };
812 static const int bt2020_full[3][3] = {
813 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4746, 255) },
814 { COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) },
815 { COEFF(1, 255), COEFF(1.8814, 255), COEFF(0, 255) },
816 };
817 static const int bt2020c[4] = {
818 COEFF(1.9404, 224), COEFF(1.5816, 224),
819 COEFF(1.7184, 224), COEFF(0.9936, 224),
820 };
821 static const int bt2020c_full[4] = {
822 COEFF(1.9404, 255), COEFF(1.5816, 255),
823 COEFF(1.7184, 255), COEFF(0.9936, 255),
824 };
825
826 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
827 unsigned y_offset = full ? 0 : 16;
828 int y_fac = full ? COEFF(1.0, 255) : COEFF(1.0, 219);
829 int lin_r, lin_g, lin_b, lin_y;
830
831 switch (tpg->real_ycbcr_enc) {
832 case V4L2_YCBCR_ENC_601:
833 ycbcr2rgb(m: full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
834 break;
835 case V4L2_YCBCR_ENC_XV601:
836 /* Ignore quantization range, there is only one possible
837 * Y'CbCr encoding. */
838 ycbcr2rgb(m: bt601, y, cb, cr, y_offset: 16, r, g, b);
839 break;
840 case V4L2_YCBCR_ENC_XV709:
841 /* Ignore quantization range, there is only one possible
842 * Y'CbCr encoding. */
843 ycbcr2rgb(m: rec709, y, cb, cr, y_offset: 16, r, g, b);
844 break;
845 case V4L2_YCBCR_ENC_BT2020:
846 ycbcr2rgb(m: full ? bt2020_full : bt2020, y, cb, cr, y_offset, r, g, b);
847 break;
848 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
849 y -= full ? 0 : 16 << 4;
850 cb -= 128 << 4;
851 cr -= 128 << 4;
852
853 if (cb <= 0)
854 *b = y_fac * y + (full ? bt2020c_full[0] : bt2020c[0]) * cb;
855 else
856 *b = y_fac * y + (full ? bt2020c_full[1] : bt2020c[1]) * cb;
857 *b = *b >> 12;
858 if (cr <= 0)
859 *r = y_fac * y + (full ? bt2020c_full[2] : bt2020c[2]) * cr;
860 else
861 *r = y_fac * y + (full ? bt2020c_full[3] : bt2020c[3]) * cr;
862 *r = *r >> 12;
863 lin_r = rec709_to_linear(v: *r);
864 lin_b = rec709_to_linear(v: *b);
865 lin_y = rec709_to_linear(v: (y * 255) / (full ? 255 : 219));
866
867 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
868 COEFF(0.2627 / 0.6780, 255) * lin_r -
869 COEFF(0.0593 / 0.6780, 255) * lin_b;
870 *g = linear_to_rec709(v: lin_g >> 12);
871 break;
872 case V4L2_YCBCR_ENC_SMPTE240M:
873 ycbcr2rgb(m: full ? smpte240m_full : smpte240m, y, cb, cr, y_offset, r, g, b);
874 break;
875 case V4L2_YCBCR_ENC_709:
876 default:
877 ycbcr2rgb(m: full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
878 break;
879 }
880}
881
882/* precalculate color bar values to speed up rendering */
883static void precalculate_color(struct tpg_data *tpg, int k)
884{
885 int col = k;
886 int r = tpg_colors[col].r;
887 int g = tpg_colors[col].g;
888 int b = tpg_colors[col].b;
889 int y, cb, cr;
890 bool ycbcr_valid = false;
891
892 if (k == TPG_COLOR_TEXTBG) {
893 col = tpg_get_textbg_color(tpg);
894
895 r = tpg_colors[col].r;
896 g = tpg_colors[col].g;
897 b = tpg_colors[col].b;
898 } else if (k == TPG_COLOR_TEXTFG) {
899 col = tpg_get_textfg_color(tpg);
900
901 r = tpg_colors[col].r;
902 g = tpg_colors[col].g;
903 b = tpg_colors[col].b;
904 } else if (tpg->pattern == TPG_PAT_NOISE) {
905 r = g = b = get_random_u8();
906 } else if (k == TPG_COLOR_RANDOM) {
907 r = g = b = tpg->qual_offset + get_random_u32_below(ceil: 196);
908 } else if (k >= TPG_COLOR_RAMP) {
909 r = g = b = k - TPG_COLOR_RAMP;
910 }
911
912 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
913 r = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].r;
914 g = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].g;
915 b = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].b;
916 } else {
917 r <<= 4;
918 g <<= 4;
919 b <<= 4;
920 }
921
922 if (tpg->qual == TPG_QUAL_GRAY ||
923 tpg->color_enc == TGP_COLOR_ENC_LUMA) {
924 /* Rec. 709 Luma function */
925 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
926 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
927 }
928
929 /*
930 * The assumption is that the RGB output is always full range,
931 * so only if the rgb_range overrides the 'real' rgb range do
932 * we need to convert the RGB values.
933 *
934 * Remember that r, g and b are still in the 0 - 0xff0 range.
935 */
936 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
937 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL &&
938 tpg->color_enc == TGP_COLOR_ENC_RGB) {
939 /*
940 * Convert from full range (which is what r, g and b are)
941 * to limited range (which is the 'real' RGB range), which
942 * is then interpreted as full range.
943 */
944 r = (r * 219) / 255 + (16 << 4);
945 g = (g * 219) / 255 + (16 << 4);
946 b = (b * 219) / 255 + (16 << 4);
947 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
948 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
949 tpg->color_enc == TGP_COLOR_ENC_RGB) {
950
951 /*
952 * Clamp r, g and b to the limited range and convert to full
953 * range since that's what we deliver.
954 */
955 r = clamp(r, 16 << 4, 235 << 4);
956 g = clamp(g, 16 << 4, 235 << 4);
957 b = clamp(b, 16 << 4, 235 << 4);
958 r = (r - (16 << 4)) * 255 / 219;
959 g = (g - (16 << 4)) * 255 / 219;
960 b = (b - (16 << 4)) * 255 / 219;
961 }
962
963 if ((tpg->brightness != 128 || tpg->contrast != 128 ||
964 tpg->saturation != 128 || tpg->hue) &&
965 tpg->color_enc != TGP_COLOR_ENC_LUMA) {
966 /* Implement these operations */
967 int tmp_cb, tmp_cr;
968
969 /* First convert to YCbCr */
970
971 color_to_ycbcr(tpg, r, g, b, y: &y, cb: &cb, cr: &cr);
972
973 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
974 y += (tpg->brightness << 4) - (128 << 4);
975
976 cb -= 128 << 4;
977 cr -= 128 << 4;
978 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
979 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
980
981 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
982 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
983 if (tpg->color_enc == TGP_COLOR_ENC_YCBCR)
984 ycbcr_valid = true;
985 else
986 ycbcr_to_color(tpg, y, cb, cr, r: &r, g: &g, b: &b);
987 } else if ((tpg->brightness != 128 || tpg->contrast != 128) &&
988 tpg->color_enc == TGP_COLOR_ENC_LUMA) {
989 r = (16 << 4) + ((r - (16 << 4)) * tpg->contrast) / 128;
990 r += (tpg->brightness << 4) - (128 << 4);
991 }
992
993 switch (tpg->color_enc) {
994 case TGP_COLOR_ENC_HSV:
995 {
996 int h, s, v;
997
998 color_to_hsv(tpg, r, g, b, h: &h, s: &s, v: &v);
999 tpg->colors[k][0] = h;
1000 tpg->colors[k][1] = s;
1001 tpg->colors[k][2] = v;
1002 break;
1003 }
1004 case TGP_COLOR_ENC_YCBCR:
1005 {
1006 /* Convert to YCbCr */
1007 if (!ycbcr_valid)
1008 color_to_ycbcr(tpg, r, g, b, y: &y, cb: &cb, cr: &cr);
1009
1010 y >>= 4;
1011 cb >>= 4;
1012 cr >>= 4;
1013 /*
1014 * XV601/709 use the header/footer margins to encode R', G'
1015 * and B' values outside the range [0-1]. So do not clamp
1016 * XV601/709 values.
1017 */
1018 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE &&
1019 tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV601 &&
1020 tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV709) {
1021 y = clamp(y, 16, 235);
1022 cb = clamp(cb, 16, 240);
1023 cr = clamp(cr, 16, 240);
1024 } else {
1025 y = clamp(y, 1, 254);
1026 cb = clamp(cb, 1, 254);
1027 cr = clamp(cr, 1, 254);
1028 }
1029 switch (tpg->fourcc) {
1030 case V4L2_PIX_FMT_YUV444:
1031 y >>= 4;
1032 cb >>= 4;
1033 cr >>= 4;
1034 break;
1035 case V4L2_PIX_FMT_YUV555:
1036 y >>= 3;
1037 cb >>= 3;
1038 cr >>= 3;
1039 break;
1040 case V4L2_PIX_FMT_YUV565:
1041 y >>= 3;
1042 cb >>= 2;
1043 cr >>= 3;
1044 break;
1045 }
1046 tpg->colors[k][0] = y;
1047 tpg->colors[k][1] = cb;
1048 tpg->colors[k][2] = cr;
1049 break;
1050 }
1051 case TGP_COLOR_ENC_LUMA:
1052 {
1053 tpg->colors[k][0] = r >> 4;
1054 break;
1055 }
1056 case TGP_COLOR_ENC_RGB:
1057 {
1058 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
1059 r = (r * 219) / 255 + (16 << 4);
1060 g = (g * 219) / 255 + (16 << 4);
1061 b = (b * 219) / 255 + (16 << 4);
1062 }
1063 switch (tpg->fourcc) {
1064 case V4L2_PIX_FMT_RGB332:
1065 r >>= 9;
1066 g >>= 9;
1067 b >>= 10;
1068 break;
1069 case V4L2_PIX_FMT_RGB565:
1070 case V4L2_PIX_FMT_RGB565X:
1071 r >>= 7;
1072 g >>= 6;
1073 b >>= 7;
1074 break;
1075 case V4L2_PIX_FMT_RGB444:
1076 case V4L2_PIX_FMT_XRGB444:
1077 case V4L2_PIX_FMT_ARGB444:
1078 case V4L2_PIX_FMT_RGBX444:
1079 case V4L2_PIX_FMT_RGBA444:
1080 case V4L2_PIX_FMT_XBGR444:
1081 case V4L2_PIX_FMT_ABGR444:
1082 case V4L2_PIX_FMT_BGRX444:
1083 case V4L2_PIX_FMT_BGRA444:
1084 r >>= 8;
1085 g >>= 8;
1086 b >>= 8;
1087 break;
1088 case V4L2_PIX_FMT_RGB555:
1089 case V4L2_PIX_FMT_XRGB555:
1090 case V4L2_PIX_FMT_ARGB555:
1091 case V4L2_PIX_FMT_RGBX555:
1092 case V4L2_PIX_FMT_RGBA555:
1093 case V4L2_PIX_FMT_XBGR555:
1094 case V4L2_PIX_FMT_ABGR555:
1095 case V4L2_PIX_FMT_BGRX555:
1096 case V4L2_PIX_FMT_BGRA555:
1097 case V4L2_PIX_FMT_RGB555X:
1098 case V4L2_PIX_FMT_XRGB555X:
1099 case V4L2_PIX_FMT_ARGB555X:
1100 r >>= 7;
1101 g >>= 7;
1102 b >>= 7;
1103 break;
1104 case V4L2_PIX_FMT_BGR666:
1105 r >>= 6;
1106 g >>= 6;
1107 b >>= 6;
1108 break;
1109 default:
1110 r >>= 4;
1111 g >>= 4;
1112 b >>= 4;
1113 break;
1114 }
1115
1116 tpg->colors[k][0] = r;
1117 tpg->colors[k][1] = g;
1118 tpg->colors[k][2] = b;
1119 break;
1120 }
1121 }
1122}
1123
1124static void tpg_precalculate_colors(struct tpg_data *tpg)
1125{
1126 int k;
1127
1128 for (k = 0; k < TPG_COLOR_MAX; k++)
1129 precalculate_color(tpg, k);
1130}
1131
1132/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
1133static void gen_twopix(struct tpg_data *tpg,
1134 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
1135{
1136 unsigned offset = odd * tpg->twopixelsize[0] / 2;
1137 u8 alpha = tpg->alpha_component;
1138 u8 r_y_h, g_u_s, b_v;
1139
1140 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
1141 color != TPG_COLOR_100_RED &&
1142 color != TPG_COLOR_75_RED)
1143 alpha = 0;
1144 if (color == TPG_COLOR_RANDOM)
1145 precalculate_color(tpg, k: color);
1146 r_y_h = tpg->colors[color][0]; /* R or precalculated Y, H */
1147 g_u_s = tpg->colors[color][1]; /* G or precalculated U, V */
1148 b_v = tpg->colors[color][2]; /* B or precalculated V */
1149
1150 switch (tpg->fourcc) {
1151 case V4L2_PIX_FMT_GREY:
1152 buf[0][offset] = r_y_h;
1153 break;
1154 case V4L2_PIX_FMT_Y10:
1155 buf[0][offset] = (r_y_h << 2) & 0xff;
1156 buf[0][offset+1] = r_y_h >> 6;
1157 break;
1158 case V4L2_PIX_FMT_Y12:
1159 buf[0][offset] = (r_y_h << 4) & 0xff;
1160 buf[0][offset+1] = r_y_h >> 4;
1161 break;
1162 case V4L2_PIX_FMT_Y16:
1163 case V4L2_PIX_FMT_Z16:
1164 /*
1165 * Ideally both bytes should be set to r_y_h, but then you won't
1166 * be able to detect endian problems. So keep it 0 except for
1167 * the corner case where r_y_h is 0xff so white really will be
1168 * white (0xffff).
1169 */
1170 buf[0][offset] = r_y_h == 0xff ? r_y_h : 0;
1171 buf[0][offset+1] = r_y_h;
1172 break;
1173 case V4L2_PIX_FMT_Y16_BE:
1174 /* See comment for V4L2_PIX_FMT_Y16 above */
1175 buf[0][offset] = r_y_h;
1176 buf[0][offset+1] = r_y_h == 0xff ? r_y_h : 0;
1177 break;
1178 case V4L2_PIX_FMT_YUV422M:
1179 case V4L2_PIX_FMT_YUV422P:
1180 case V4L2_PIX_FMT_YUV420:
1181 case V4L2_PIX_FMT_YUV420M:
1182 buf[0][offset] = r_y_h;
1183 if (odd) {
1184 buf[1][0] = (buf[1][0] + g_u_s) / 2;
1185 buf[2][0] = (buf[2][0] + b_v) / 2;
1186 buf[1][1] = buf[1][0];
1187 buf[2][1] = buf[2][0];
1188 break;
1189 }
1190 buf[1][0] = g_u_s;
1191 buf[2][0] = b_v;
1192 break;
1193 case V4L2_PIX_FMT_YVU422M:
1194 case V4L2_PIX_FMT_YVU420:
1195 case V4L2_PIX_FMT_YVU420M:
1196 buf[0][offset] = r_y_h;
1197 if (odd) {
1198 buf[1][0] = (buf[1][0] + b_v) / 2;
1199 buf[2][0] = (buf[2][0] + g_u_s) / 2;
1200 buf[1][1] = buf[1][0];
1201 buf[2][1] = buf[2][0];
1202 break;
1203 }
1204 buf[1][0] = b_v;
1205 buf[2][0] = g_u_s;
1206 break;
1207
1208 case V4L2_PIX_FMT_NV12:
1209 case V4L2_PIX_FMT_NV12M:
1210 case V4L2_PIX_FMT_NV16:
1211 case V4L2_PIX_FMT_NV16M:
1212 buf[0][offset] = r_y_h;
1213 if (odd) {
1214 buf[1][0] = (buf[1][0] + g_u_s) / 2;
1215 buf[1][1] = (buf[1][1] + b_v) / 2;
1216 break;
1217 }
1218 buf[1][0] = g_u_s;
1219 buf[1][1] = b_v;
1220 break;
1221 case V4L2_PIX_FMT_NV21:
1222 case V4L2_PIX_FMT_NV21M:
1223 case V4L2_PIX_FMT_NV61:
1224 case V4L2_PIX_FMT_NV61M:
1225 buf[0][offset] = r_y_h;
1226 if (odd) {
1227 buf[1][0] = (buf[1][0] + b_v) / 2;
1228 buf[1][1] = (buf[1][1] + g_u_s) / 2;
1229 break;
1230 }
1231 buf[1][0] = b_v;
1232 buf[1][1] = g_u_s;
1233 break;
1234
1235 case V4L2_PIX_FMT_YUV444M:
1236 buf[0][offset] = r_y_h;
1237 buf[1][offset] = g_u_s;
1238 buf[2][offset] = b_v;
1239 break;
1240
1241 case V4L2_PIX_FMT_YVU444M:
1242 buf[0][offset] = r_y_h;
1243 buf[1][offset] = b_v;
1244 buf[2][offset] = g_u_s;
1245 break;
1246
1247 case V4L2_PIX_FMT_NV24:
1248 buf[0][offset] = r_y_h;
1249 buf[1][2 * offset] = g_u_s;
1250 buf[1][(2 * offset + 1) % 8] = b_v;
1251 break;
1252
1253 case V4L2_PIX_FMT_NV42:
1254 buf[0][offset] = r_y_h;
1255 buf[1][2 * offset] = b_v;
1256 buf[1][(2 * offset + 1) % 8] = g_u_s;
1257 break;
1258
1259 case V4L2_PIX_FMT_YUYV:
1260 buf[0][offset] = r_y_h;
1261 if (odd) {
1262 buf[0][1] = (buf[0][1] + g_u_s) / 2;
1263 buf[0][3] = (buf[0][3] + b_v) / 2;
1264 break;
1265 }
1266 buf[0][1] = g_u_s;
1267 buf[0][3] = b_v;
1268 break;
1269 case V4L2_PIX_FMT_UYVY:
1270 buf[0][offset + 1] = r_y_h;
1271 if (odd) {
1272 buf[0][0] = (buf[0][0] + g_u_s) / 2;
1273 buf[0][2] = (buf[0][2] + b_v) / 2;
1274 break;
1275 }
1276 buf[0][0] = g_u_s;
1277 buf[0][2] = b_v;
1278 break;
1279 case V4L2_PIX_FMT_YVYU:
1280 buf[0][offset] = r_y_h;
1281 if (odd) {
1282 buf[0][1] = (buf[0][1] + b_v) / 2;
1283 buf[0][3] = (buf[0][3] + g_u_s) / 2;
1284 break;
1285 }
1286 buf[0][1] = b_v;
1287 buf[0][3] = g_u_s;
1288 break;
1289 case V4L2_PIX_FMT_VYUY:
1290 buf[0][offset + 1] = r_y_h;
1291 if (odd) {
1292 buf[0][0] = (buf[0][0] + b_v) / 2;
1293 buf[0][2] = (buf[0][2] + g_u_s) / 2;
1294 break;
1295 }
1296 buf[0][0] = b_v;
1297 buf[0][2] = g_u_s;
1298 break;
1299 case V4L2_PIX_FMT_RGB332:
1300 buf[0][offset] = (r_y_h << 5) | (g_u_s << 2) | b_v;
1301 break;
1302 case V4L2_PIX_FMT_YUV565:
1303 case V4L2_PIX_FMT_RGB565:
1304 buf[0][offset] = (g_u_s << 5) | b_v;
1305 buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 3);
1306 break;
1307 case V4L2_PIX_FMT_RGB565X:
1308 buf[0][offset] = (r_y_h << 3) | (g_u_s >> 3);
1309 buf[0][offset + 1] = (g_u_s << 5) | b_v;
1310 break;
1311 case V4L2_PIX_FMT_RGB444:
1312 case V4L2_PIX_FMT_XRGB444:
1313 alpha = 0;
1314 fallthrough;
1315 case V4L2_PIX_FMT_YUV444:
1316 case V4L2_PIX_FMT_ARGB444:
1317 buf[0][offset] = (g_u_s << 4) | b_v;
1318 buf[0][offset + 1] = (alpha & 0xf0) | r_y_h;
1319 break;
1320 case V4L2_PIX_FMT_RGBX444:
1321 alpha = 0;
1322 fallthrough;
1323 case V4L2_PIX_FMT_RGBA444:
1324 buf[0][offset] = (b_v << 4) | (alpha >> 4);
1325 buf[0][offset + 1] = (r_y_h << 4) | g_u_s;
1326 break;
1327 case V4L2_PIX_FMT_XBGR444:
1328 alpha = 0;
1329 fallthrough;
1330 case V4L2_PIX_FMT_ABGR444:
1331 buf[0][offset] = (g_u_s << 4) | r_y_h;
1332 buf[0][offset + 1] = (alpha & 0xf0) | b_v;
1333 break;
1334 case V4L2_PIX_FMT_BGRX444:
1335 alpha = 0;
1336 fallthrough;
1337 case V4L2_PIX_FMT_BGRA444:
1338 buf[0][offset] = (r_y_h << 4) | (alpha >> 4);
1339 buf[0][offset + 1] = (b_v << 4) | g_u_s;
1340 break;
1341 case V4L2_PIX_FMT_RGB555:
1342 case V4L2_PIX_FMT_XRGB555:
1343 alpha = 0;
1344 fallthrough;
1345 case V4L2_PIX_FMT_YUV555:
1346 case V4L2_PIX_FMT_ARGB555:
1347 buf[0][offset] = (g_u_s << 5) | b_v;
1348 buf[0][offset + 1] = (alpha & 0x80) | (r_y_h << 2)
1349 | (g_u_s >> 3);
1350 break;
1351 case V4L2_PIX_FMT_RGBX555:
1352 alpha = 0;
1353 fallthrough;
1354 case V4L2_PIX_FMT_RGBA555:
1355 buf[0][offset] = (g_u_s << 6) | (b_v << 1) |
1356 ((alpha & 0x80) >> 7);
1357 buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 2);
1358 break;
1359 case V4L2_PIX_FMT_XBGR555:
1360 alpha = 0;
1361 fallthrough;
1362 case V4L2_PIX_FMT_ABGR555:
1363 buf[0][offset] = (g_u_s << 5) | r_y_h;
1364 buf[0][offset + 1] = (alpha & 0x80) | (b_v << 2)
1365 | (g_u_s >> 3);
1366 break;
1367 case V4L2_PIX_FMT_BGRX555:
1368 alpha = 0;
1369 fallthrough;
1370 case V4L2_PIX_FMT_BGRA555:
1371 buf[0][offset] = (g_u_s << 6) | (r_y_h << 1) |
1372 ((alpha & 0x80) >> 7);
1373 buf[0][offset + 1] = (b_v << 3) | (g_u_s >> 2);
1374 break;
1375 case V4L2_PIX_FMT_RGB555X:
1376 case V4L2_PIX_FMT_XRGB555X:
1377 alpha = 0;
1378 fallthrough;
1379 case V4L2_PIX_FMT_ARGB555X:
1380 buf[0][offset] = (alpha & 0x80) | (r_y_h << 2) | (g_u_s >> 3);
1381 buf[0][offset + 1] = (g_u_s << 5) | b_v;
1382 break;
1383 case V4L2_PIX_FMT_RGB24:
1384 case V4L2_PIX_FMT_HSV24:
1385 buf[0][offset] = r_y_h;
1386 buf[0][offset + 1] = g_u_s;
1387 buf[0][offset + 2] = b_v;
1388 break;
1389 case V4L2_PIX_FMT_BGR24:
1390 buf[0][offset] = b_v;
1391 buf[0][offset + 1] = g_u_s;
1392 buf[0][offset + 2] = r_y_h;
1393 break;
1394 case V4L2_PIX_FMT_BGR666:
1395 buf[0][offset] = (b_v << 2) | (g_u_s >> 4);
1396 buf[0][offset + 1] = (g_u_s << 4) | (r_y_h >> 2);
1397 buf[0][offset + 2] = r_y_h << 6;
1398 buf[0][offset + 3] = 0;
1399 break;
1400 case V4L2_PIX_FMT_RGB32:
1401 case V4L2_PIX_FMT_XRGB32:
1402 case V4L2_PIX_FMT_HSV32:
1403 case V4L2_PIX_FMT_XYUV32:
1404 alpha = 0;
1405 fallthrough;
1406 case V4L2_PIX_FMT_YUV32:
1407 case V4L2_PIX_FMT_ARGB32:
1408 case V4L2_PIX_FMT_AYUV32:
1409 buf[0][offset] = alpha;
1410 buf[0][offset + 1] = r_y_h;
1411 buf[0][offset + 2] = g_u_s;
1412 buf[0][offset + 3] = b_v;
1413 break;
1414 case V4L2_PIX_FMT_RGBX32:
1415 case V4L2_PIX_FMT_YUVX32:
1416 alpha = 0;
1417 fallthrough;
1418 case V4L2_PIX_FMT_RGBA32:
1419 case V4L2_PIX_FMT_YUVA32:
1420 buf[0][offset] = r_y_h;
1421 buf[0][offset + 1] = g_u_s;
1422 buf[0][offset + 2] = b_v;
1423 buf[0][offset + 3] = alpha;
1424 break;
1425 case V4L2_PIX_FMT_BGR32:
1426 case V4L2_PIX_FMT_XBGR32:
1427 case V4L2_PIX_FMT_VUYX32:
1428 alpha = 0;
1429 fallthrough;
1430 case V4L2_PIX_FMT_ABGR32:
1431 case V4L2_PIX_FMT_VUYA32:
1432 buf[0][offset] = b_v;
1433 buf[0][offset + 1] = g_u_s;
1434 buf[0][offset + 2] = r_y_h;
1435 buf[0][offset + 3] = alpha;
1436 break;
1437 case V4L2_PIX_FMT_BGRX32:
1438 alpha = 0;
1439 fallthrough;
1440 case V4L2_PIX_FMT_BGRA32:
1441 buf[0][offset] = alpha;
1442 buf[0][offset + 1] = b_v;
1443 buf[0][offset + 2] = g_u_s;
1444 buf[0][offset + 3] = r_y_h;
1445 break;
1446 case V4L2_PIX_FMT_SBGGR8:
1447 buf[0][offset] = odd ? g_u_s : b_v;
1448 buf[1][offset] = odd ? r_y_h : g_u_s;
1449 break;
1450 case V4L2_PIX_FMT_SGBRG8:
1451 buf[0][offset] = odd ? b_v : g_u_s;
1452 buf[1][offset] = odd ? g_u_s : r_y_h;
1453 break;
1454 case V4L2_PIX_FMT_SGRBG8:
1455 buf[0][offset] = odd ? r_y_h : g_u_s;
1456 buf[1][offset] = odd ? g_u_s : b_v;
1457 break;
1458 case V4L2_PIX_FMT_SRGGB8:
1459 buf[0][offset] = odd ? g_u_s : r_y_h;
1460 buf[1][offset] = odd ? b_v : g_u_s;
1461 break;
1462 case V4L2_PIX_FMT_SBGGR10:
1463 buf[0][offset] = odd ? g_u_s << 2 : b_v << 2;
1464 buf[0][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6;
1465 buf[1][offset] = odd ? r_y_h << 2 : g_u_s << 2;
1466 buf[1][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6;
1467 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1468 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1469 break;
1470 case V4L2_PIX_FMT_SGBRG10:
1471 buf[0][offset] = odd ? b_v << 2 : g_u_s << 2;
1472 buf[0][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6;
1473 buf[1][offset] = odd ? g_u_s << 2 : r_y_h << 2;
1474 buf[1][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6;
1475 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1476 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1477 break;
1478 case V4L2_PIX_FMT_SGRBG10:
1479 buf[0][offset] = odd ? r_y_h << 2 : g_u_s << 2;
1480 buf[0][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6;
1481 buf[1][offset] = odd ? g_u_s << 2 : b_v << 2;
1482 buf[1][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6;
1483 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1484 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1485 break;
1486 case V4L2_PIX_FMT_SRGGB10:
1487 buf[0][offset] = odd ? g_u_s << 2 : r_y_h << 2;
1488 buf[0][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6;
1489 buf[1][offset] = odd ? b_v << 2 : g_u_s << 2;
1490 buf[1][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6;
1491 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1492 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1493 break;
1494 case V4L2_PIX_FMT_SBGGR12:
1495 buf[0][offset] = odd ? g_u_s << 4 : b_v << 4;
1496 buf[0][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4;
1497 buf[1][offset] = odd ? r_y_h << 4 : g_u_s << 4;
1498 buf[1][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4;
1499 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1500 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1501 break;
1502 case V4L2_PIX_FMT_SGBRG12:
1503 buf[0][offset] = odd ? b_v << 4 : g_u_s << 4;
1504 buf[0][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4;
1505 buf[1][offset] = odd ? g_u_s << 4 : r_y_h << 4;
1506 buf[1][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4;
1507 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1508 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1509 break;
1510 case V4L2_PIX_FMT_SGRBG12:
1511 buf[0][offset] = odd ? r_y_h << 4 : g_u_s << 4;
1512 buf[0][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4;
1513 buf[1][offset] = odd ? g_u_s << 4 : b_v << 4;
1514 buf[1][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4;
1515 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1516 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1517 break;
1518 case V4L2_PIX_FMT_SRGGB12:
1519 buf[0][offset] = odd ? g_u_s << 4 : r_y_h << 4;
1520 buf[0][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4;
1521 buf[1][offset] = odd ? b_v << 4 : g_u_s << 4;
1522 buf[1][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4;
1523 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1524 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1525 break;
1526 case V4L2_PIX_FMT_SBGGR16:
1527 buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : b_v;
1528 buf[1][offset] = buf[1][offset + 1] = odd ? r_y_h : g_u_s;
1529 break;
1530 case V4L2_PIX_FMT_SGBRG16:
1531 buf[0][offset] = buf[0][offset + 1] = odd ? b_v : g_u_s;
1532 buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : r_y_h;
1533 break;
1534 case V4L2_PIX_FMT_SGRBG16:
1535 buf[0][offset] = buf[0][offset + 1] = odd ? r_y_h : g_u_s;
1536 buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : b_v;
1537 break;
1538 case V4L2_PIX_FMT_SRGGB16:
1539 buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : r_y_h;
1540 buf[1][offset] = buf[1][offset + 1] = odd ? b_v : g_u_s;
1541 break;
1542 }
1543}
1544
1545unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
1546{
1547 switch (tpg->fourcc) {
1548 case V4L2_PIX_FMT_SBGGR8:
1549 case V4L2_PIX_FMT_SGBRG8:
1550 case V4L2_PIX_FMT_SGRBG8:
1551 case V4L2_PIX_FMT_SRGGB8:
1552 case V4L2_PIX_FMT_SBGGR10:
1553 case V4L2_PIX_FMT_SGBRG10:
1554 case V4L2_PIX_FMT_SGRBG10:
1555 case V4L2_PIX_FMT_SRGGB10:
1556 case V4L2_PIX_FMT_SBGGR12:
1557 case V4L2_PIX_FMT_SGBRG12:
1558 case V4L2_PIX_FMT_SGRBG12:
1559 case V4L2_PIX_FMT_SRGGB12:
1560 case V4L2_PIX_FMT_SBGGR16:
1561 case V4L2_PIX_FMT_SGBRG16:
1562 case V4L2_PIX_FMT_SGRBG16:
1563 case V4L2_PIX_FMT_SRGGB16:
1564 return buf_line & 1;
1565 default:
1566 return 0;
1567 }
1568}
1569EXPORT_SYMBOL_GPL(tpg_g_interleaved_plane);
1570
1571/* Return how many pattern lines are used by the current pattern. */
1572static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
1573{
1574 switch (tpg->pattern) {
1575 case TPG_PAT_CHECKERS_16X16:
1576 case TPG_PAT_CHECKERS_2X2:
1577 case TPG_PAT_CHECKERS_1X1:
1578 case TPG_PAT_COLOR_CHECKERS_2X2:
1579 case TPG_PAT_COLOR_CHECKERS_1X1:
1580 case TPG_PAT_ALTERNATING_HLINES:
1581 case TPG_PAT_CROSS_1_PIXEL:
1582 case TPG_PAT_CROSS_2_PIXELS:
1583 case TPG_PAT_CROSS_10_PIXELS:
1584 return 2;
1585 case TPG_PAT_100_COLORSQUARES:
1586 case TPG_PAT_100_HCOLORBAR:
1587 return 8;
1588 default:
1589 return 1;
1590 }
1591}
1592
1593/* Which pattern line should be used for the given frame line. */
1594static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
1595{
1596 switch (tpg->pattern) {
1597 case TPG_PAT_CHECKERS_16X16:
1598 return (line >> 4) & 1;
1599 case TPG_PAT_CHECKERS_1X1:
1600 case TPG_PAT_COLOR_CHECKERS_1X1:
1601 case TPG_PAT_ALTERNATING_HLINES:
1602 return line & 1;
1603 case TPG_PAT_CHECKERS_2X2:
1604 case TPG_PAT_COLOR_CHECKERS_2X2:
1605 return (line & 2) >> 1;
1606 case TPG_PAT_100_COLORSQUARES:
1607 case TPG_PAT_100_HCOLORBAR:
1608 return (line * 8) / tpg->src_height;
1609 case TPG_PAT_CROSS_1_PIXEL:
1610 return line == tpg->src_height / 2;
1611 case TPG_PAT_CROSS_2_PIXELS:
1612 return (line + 1) / 2 == tpg->src_height / 4;
1613 case TPG_PAT_CROSS_10_PIXELS:
1614 return (line + 10) / 20 == tpg->src_height / 40;
1615 default:
1616 return 0;
1617 }
1618}
1619
1620/*
1621 * Which color should be used for the given pattern line and X coordinate.
1622 * Note: x is in the range 0 to 2 * tpg->src_width.
1623 */
1624static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
1625 unsigned pat_line, unsigned x)
1626{
1627 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
1628 should be modified */
1629 static const enum tpg_color bars[3][8] = {
1630 /* Standard ITU-R 75% color bar sequence */
1631 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
1632 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
1633 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
1634 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
1635 /* Standard ITU-R 100% color bar sequence */
1636 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
1637 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
1638 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
1639 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
1640 /* Color bar sequence suitable to test CSC */
1641 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
1642 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
1643 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
1644 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
1645 };
1646
1647 switch (tpg->pattern) {
1648 case TPG_PAT_75_COLORBAR:
1649 case TPG_PAT_100_COLORBAR:
1650 case TPG_PAT_CSC_COLORBAR:
1651 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
1652 case TPG_PAT_100_COLORSQUARES:
1653 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
1654 case TPG_PAT_100_HCOLORBAR:
1655 return bars[1][pat_line];
1656 case TPG_PAT_BLACK:
1657 return TPG_COLOR_100_BLACK;
1658 case TPG_PAT_WHITE:
1659 return TPG_COLOR_100_WHITE;
1660 case TPG_PAT_RED:
1661 return TPG_COLOR_100_RED;
1662 case TPG_PAT_GREEN:
1663 return TPG_COLOR_100_GREEN;
1664 case TPG_PAT_BLUE:
1665 return TPG_COLOR_100_BLUE;
1666 case TPG_PAT_CHECKERS_16X16:
1667 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
1668 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
1669 case TPG_PAT_CHECKERS_1X1:
1670 return ((x & 1) ^ (pat_line & 1)) ?
1671 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1672 case TPG_PAT_COLOR_CHECKERS_1X1:
1673 return ((x & 1) ^ (pat_line & 1)) ?
1674 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1675 case TPG_PAT_CHECKERS_2X2:
1676 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1677 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1678 case TPG_PAT_COLOR_CHECKERS_2X2:
1679 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1680 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1681 case TPG_PAT_ALTERNATING_HLINES:
1682 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1683 case TPG_PAT_ALTERNATING_VLINES:
1684 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1685 case TPG_PAT_CROSS_1_PIXEL:
1686 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
1687 return TPG_COLOR_100_BLACK;
1688 return TPG_COLOR_100_WHITE;
1689 case TPG_PAT_CROSS_2_PIXELS:
1690 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
1691 return TPG_COLOR_100_BLACK;
1692 return TPG_COLOR_100_WHITE;
1693 case TPG_PAT_CROSS_10_PIXELS:
1694 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
1695 return TPG_COLOR_100_BLACK;
1696 return TPG_COLOR_100_WHITE;
1697 case TPG_PAT_GRAY_RAMP:
1698 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
1699 default:
1700 return TPG_COLOR_100_RED;
1701 }
1702}
1703
1704/*
1705 * Given the pixel aspect ratio and video aspect ratio calculate the
1706 * coordinates of a centered square and the coordinates of the border of
1707 * the active video area. The coordinates are relative to the source
1708 * frame rectangle.
1709 */
1710static void tpg_calculate_square_border(struct tpg_data *tpg)
1711{
1712 unsigned w = tpg->src_width;
1713 unsigned h = tpg->src_height;
1714 unsigned sq_w, sq_h;
1715
1716 sq_w = (w * 2 / 5) & ~1;
1717 if (((w - sq_w) / 2) & 1)
1718 sq_w += 2;
1719 sq_h = sq_w;
1720 tpg->square.width = sq_w;
1721 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
1722 unsigned ana_sq_w = (sq_w / 4) * 3;
1723
1724 if (((w - ana_sq_w) / 2) & 1)
1725 ana_sq_w += 2;
1726 tpg->square.width = ana_sq_w;
1727 }
1728 tpg->square.left = (w - tpg->square.width) / 2;
1729 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
1730 sq_h = sq_w * 10 / 11;
1731 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
1732 sq_h = sq_w * 59 / 54;
1733 tpg->square.height = sq_h;
1734 tpg->square.top = (h - sq_h) / 2;
1735 tpg->border.left = 0;
1736 tpg->border.width = w;
1737 tpg->border.top = 0;
1738 tpg->border.height = h;
1739 switch (tpg->vid_aspect) {
1740 case TPG_VIDEO_ASPECT_4X3:
1741 if (tpg->pix_aspect)
1742 return;
1743 if (3 * w >= 4 * h) {
1744 tpg->border.width = ((4 * h) / 3) & ~1;
1745 if (((w - tpg->border.width) / 2) & ~1)
1746 tpg->border.width -= 2;
1747 tpg->border.left = (w - tpg->border.width) / 2;
1748 break;
1749 }
1750 tpg->border.height = ((3 * w) / 4) & ~1;
1751 tpg->border.top = (h - tpg->border.height) / 2;
1752 break;
1753 case TPG_VIDEO_ASPECT_14X9_CENTRE:
1754 if (tpg->pix_aspect) {
1755 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
1756 tpg->border.top = (h - tpg->border.height) / 2;
1757 break;
1758 }
1759 if (9 * w >= 14 * h) {
1760 tpg->border.width = ((14 * h) / 9) & ~1;
1761 if (((w - tpg->border.width) / 2) & ~1)
1762 tpg->border.width -= 2;
1763 tpg->border.left = (w - tpg->border.width) / 2;
1764 break;
1765 }
1766 tpg->border.height = ((9 * w) / 14) & ~1;
1767 tpg->border.top = (h - tpg->border.height) / 2;
1768 break;
1769 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1770 if (tpg->pix_aspect) {
1771 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1772 tpg->border.top = (h - tpg->border.height) / 2;
1773 break;
1774 }
1775 if (9 * w >= 16 * h) {
1776 tpg->border.width = ((16 * h) / 9) & ~1;
1777 if (((w - tpg->border.width) / 2) & ~1)
1778 tpg->border.width -= 2;
1779 tpg->border.left = (w - tpg->border.width) / 2;
1780 break;
1781 }
1782 tpg->border.height = ((9 * w) / 16) & ~1;
1783 tpg->border.top = (h - tpg->border.height) / 2;
1784 break;
1785 default:
1786 break;
1787 }
1788}
1789
1790static void tpg_precalculate_line(struct tpg_data *tpg)
1791{
1792 enum tpg_color contrast;
1793 u8 pix[TPG_MAX_PLANES][8];
1794 unsigned pat;
1795 unsigned p;
1796 unsigned x;
1797
1798 switch (tpg->pattern) {
1799 case TPG_PAT_GREEN:
1800 contrast = TPG_COLOR_100_RED;
1801 break;
1802 case TPG_PAT_CSC_COLORBAR:
1803 contrast = TPG_COLOR_CSC_GREEN;
1804 break;
1805 default:
1806 contrast = TPG_COLOR_100_GREEN;
1807 break;
1808 }
1809
1810 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1811 /* Coarse scaling with Bresenham */
1812 unsigned int_part = tpg->src_width / tpg->scaled_width;
1813 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1814 unsigned src_x = 0;
1815 unsigned error = 0;
1816
1817 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1818 unsigned real_x = src_x;
1819 enum tpg_color color1, color2;
1820
1821 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1822 color1 = tpg_get_color(tpg, pat_line: pat, x: real_x);
1823
1824 src_x += int_part;
1825 error += fract_part;
1826 if (error >= tpg->scaled_width) {
1827 error -= tpg->scaled_width;
1828 src_x++;
1829 }
1830
1831 real_x = src_x;
1832 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1833 color2 = tpg_get_color(tpg, pat_line: pat, x: real_x);
1834
1835 src_x += int_part;
1836 error += fract_part;
1837 if (error >= tpg->scaled_width) {
1838 error -= tpg->scaled_width;
1839 src_x++;
1840 }
1841
1842 gen_twopix(tpg, buf: pix, color: tpg->hflip ? color2 : color1, odd: 0);
1843 gen_twopix(tpg, buf: pix, color: tpg->hflip ? color1 : color2, odd: 1);
1844 for (p = 0; p < tpg->planes; p++) {
1845 unsigned twopixsize = tpg->twopixelsize[p];
1846 unsigned hdiv = tpg->hdownsampling[p];
1847 u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, plane: p, x);
1848
1849 memcpy(pos, pix[p], twopixsize / hdiv);
1850 }
1851 }
1852 }
1853
1854 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1855 unsigned pat_lines = tpg_get_pat_lines(tpg);
1856
1857 for (pat = 0; pat < pat_lines; pat++) {
1858 unsigned next_pat = (pat + 1) % pat_lines;
1859
1860 for (p = 1; p < tpg->planes; p++) {
1861 unsigned w = tpg_hdiv(tpg, plane: p, x: tpg->scaled_width * 2);
1862 u8 *pos1 = tpg->lines[pat][p];
1863 u8 *pos2 = tpg->lines[next_pat][p];
1864 u8 *dest = tpg->downsampled_lines[pat][p];
1865
1866 for (x = 0; x < w; x++, pos1++, pos2++, dest++)
1867 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
1868 }
1869 }
1870 }
1871
1872 gen_twopix(tpg, buf: pix, color: contrast, odd: 0);
1873 gen_twopix(tpg, buf: pix, color: contrast, odd: 1);
1874 for (p = 0; p < tpg->planes; p++) {
1875 unsigned twopixsize = tpg->twopixelsize[p];
1876 u8 *pos = tpg->contrast_line[p];
1877
1878 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
1879 memcpy(pos, pix[p], twopixsize);
1880 }
1881
1882 gen_twopix(tpg, buf: pix, color: TPG_COLOR_100_BLACK, odd: 0);
1883 gen_twopix(tpg, buf: pix, color: TPG_COLOR_100_BLACK, odd: 1);
1884 for (p = 0; p < tpg->planes; p++) {
1885 unsigned twopixsize = tpg->twopixelsize[p];
1886 u8 *pos = tpg->black_line[p];
1887
1888 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
1889 memcpy(pos, pix[p], twopixsize);
1890 }
1891
1892 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1893 gen_twopix(tpg, buf: pix, color: TPG_COLOR_RANDOM, odd: 0);
1894 gen_twopix(tpg, buf: pix, color: TPG_COLOR_RANDOM, odd: 1);
1895 for (p = 0; p < tpg->planes; p++) {
1896 unsigned twopixsize = tpg->twopixelsize[p];
1897 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1898
1899 memcpy(pos, pix[p], twopixsize);
1900 }
1901 }
1902
1903 gen_twopix(tpg, buf: tpg->textbg, color: TPG_COLOR_TEXTBG, odd: 0);
1904 gen_twopix(tpg, buf: tpg->textbg, color: TPG_COLOR_TEXTBG, odd: 1);
1905 gen_twopix(tpg, buf: tpg->textfg, color: TPG_COLOR_TEXTFG, odd: 0);
1906 gen_twopix(tpg, buf: tpg->textfg, color: TPG_COLOR_TEXTFG, odd: 1);
1907}
1908
1909/* need this to do rgb24 rendering */
1910typedef struct { u16 __; u8 _; } __packed x24;
1911
1912#define PRINTSTR(PIXTYPE) do { \
1913 unsigned vdiv = tpg->vdownsampling[p]; \
1914 unsigned hdiv = tpg->hdownsampling[p]; \
1915 int line; \
1916 PIXTYPE fg; \
1917 PIXTYPE bg; \
1918 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1919 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1920 \
1921 for (line = first; line < 16; line += vdiv * step) { \
1922 int l = tpg->vflip ? 15 - line : line; \
1923 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1924 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1925 (x / hdiv) * sizeof(PIXTYPE)); \
1926 unsigned s; \
1927 \
1928 for (s = 0; s < len; s++) { \
1929 u8 chr = font8x16[(u8)text[s] * 16 + line]; \
1930 \
1931 if (hdiv == 2 && tpg->hflip) { \
1932 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1933 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1934 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1935 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1936 } else if (hdiv == 2) { \
1937 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1938 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1939 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1940 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1941 } else if (tpg->hflip) { \
1942 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1943 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1944 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1945 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1946 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1947 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1948 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1949 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1950 } else { \
1951 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1952 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1953 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1954 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1955 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1956 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1957 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1958 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1959 } \
1960 \
1961 pos += (tpg->hflip ? -8 : 8) / (int)hdiv; \
1962 } \
1963 } \
1964} while (0)
1965
1966static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1967 unsigned p, unsigned first, unsigned div, unsigned step,
1968 int y, int x, const char *text, unsigned len)
1969{
1970 PRINTSTR(u8);
1971}
1972
1973static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1974 unsigned p, unsigned first, unsigned div, unsigned step,
1975 int y, int x, const char *text, unsigned len)
1976{
1977 PRINTSTR(u16);
1978}
1979
1980static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1981 unsigned p, unsigned first, unsigned div, unsigned step,
1982 int y, int x, const char *text, unsigned len)
1983{
1984 PRINTSTR(x24);
1985}
1986
1987static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1988 unsigned p, unsigned first, unsigned div, unsigned step,
1989 int y, int x, const char *text, unsigned len)
1990{
1991 PRINTSTR(u32);
1992}
1993
1994void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1995 int y, int x, const char *text)
1996{
1997 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1998 unsigned div = step;
1999 unsigned first = 0;
2000 unsigned len;
2001 unsigned p;
2002
2003 if (font8x16 == NULL || basep == NULL || text == NULL)
2004 return;
2005
2006 len = strlen(text);
2007
2008 /* Checks if it is possible to show string */
2009 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
2010 return;
2011
2012 if (len > (tpg->compose.width - x) / 8)
2013 len = (tpg->compose.width - x) / 8;
2014 if (tpg->vflip)
2015 y = tpg->compose.height - y - 16;
2016 if (tpg->hflip)
2017 x = tpg->compose.width - x - 8;
2018 y += tpg->compose.top;
2019 x += tpg->compose.left;
2020 if (tpg->field == V4L2_FIELD_BOTTOM)
2021 first = 1;
2022 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
2023 div = 2;
2024
2025 for (p = 0; p < tpg->planes; p++) {
2026 /* Print text */
2027 switch (tpg->twopixelsize[p]) {
2028 case 2:
2029 tpg_print_str_2(tpg, basep, p, first, div, step, y, x,
2030 text, len);
2031 break;
2032 case 4:
2033 tpg_print_str_4(tpg, basep, p, first, div, step, y, x,
2034 text, len);
2035 break;
2036 case 6:
2037 tpg_print_str_6(tpg, basep, p, first, div, step, y, x,
2038 text, len);
2039 break;
2040 case 8:
2041 tpg_print_str_8(tpg, basep, p, first, div, step, y, x,
2042 text, len);
2043 break;
2044 }
2045 }
2046}
2047EXPORT_SYMBOL_GPL(tpg_gen_text);
2048
2049const char *tpg_g_color_order(const struct tpg_data *tpg)
2050{
2051 switch (tpg->pattern) {
2052 case TPG_PAT_75_COLORBAR:
2053 case TPG_PAT_100_COLORBAR:
2054 case TPG_PAT_CSC_COLORBAR:
2055 case TPG_PAT_100_HCOLORBAR:
2056 return "White, yellow, cyan, green, magenta, red, blue, black";
2057 case TPG_PAT_BLACK:
2058 return "Black";
2059 case TPG_PAT_WHITE:
2060 return "White";
2061 case TPG_PAT_RED:
2062 return "Red";
2063 case TPG_PAT_GREEN:
2064 return "Green";
2065 case TPG_PAT_BLUE:
2066 return "Blue";
2067 default:
2068 return NULL;
2069 }
2070}
2071EXPORT_SYMBOL_GPL(tpg_g_color_order);
2072
2073void tpg_update_mv_step(struct tpg_data *tpg)
2074{
2075 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
2076
2077 if (tpg->hflip)
2078 factor = -factor;
2079 switch (tpg->mv_hor_mode) {
2080 case TPG_MOVE_NEG_FAST:
2081 case TPG_MOVE_POS_FAST:
2082 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
2083 break;
2084 case TPG_MOVE_NEG:
2085 case TPG_MOVE_POS:
2086 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
2087 break;
2088 case TPG_MOVE_NEG_SLOW:
2089 case TPG_MOVE_POS_SLOW:
2090 tpg->mv_hor_step = 2;
2091 break;
2092 case TPG_MOVE_NONE:
2093 tpg->mv_hor_step = 0;
2094 break;
2095 }
2096 if (factor < 0)
2097 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
2098
2099 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
2100 switch (tpg->mv_vert_mode) {
2101 case TPG_MOVE_NEG_FAST:
2102 case TPG_MOVE_POS_FAST:
2103 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
2104 break;
2105 case TPG_MOVE_NEG:
2106 case TPG_MOVE_POS:
2107 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
2108 break;
2109 case TPG_MOVE_NEG_SLOW:
2110 case TPG_MOVE_POS_SLOW:
2111 tpg->mv_vert_step = 1;
2112 break;
2113 case TPG_MOVE_NONE:
2114 tpg->mv_vert_step = 0;
2115 break;
2116 }
2117 if (factor < 0)
2118 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
2119}
2120EXPORT_SYMBOL_GPL(tpg_update_mv_step);
2121
2122/* Map the line number relative to the crop rectangle to a frame line number */
2123static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
2124 unsigned field)
2125{
2126 switch (field) {
2127 case V4L2_FIELD_TOP:
2128 return tpg->crop.top + src_y * 2;
2129 case V4L2_FIELD_BOTTOM:
2130 return tpg->crop.top + src_y * 2 + 1;
2131 default:
2132 return src_y + tpg->crop.top;
2133 }
2134}
2135
2136/*
2137 * Map the line number relative to the compose rectangle to a destination
2138 * buffer line number.
2139 */
2140static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
2141 unsigned field)
2142{
2143 y += tpg->compose.top;
2144 switch (field) {
2145 case V4L2_FIELD_SEQ_TB:
2146 if (y & 1)
2147 return tpg->buf_height / 2 + y / 2;
2148 return y / 2;
2149 case V4L2_FIELD_SEQ_BT:
2150 if (y & 1)
2151 return y / 2;
2152 return tpg->buf_height / 2 + y / 2;
2153 default:
2154 return y;
2155 }
2156}
2157
2158static void tpg_recalc(struct tpg_data *tpg)
2159{
2160 if (tpg->recalc_colors) {
2161 tpg->recalc_colors = false;
2162 tpg->recalc_lines = true;
2163 tpg->real_xfer_func = tpg->xfer_func;
2164 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
2165 tpg->real_hsv_enc = tpg->hsv_enc;
2166 tpg->real_quantization = tpg->quantization;
2167
2168 if (tpg->xfer_func == V4L2_XFER_FUNC_DEFAULT)
2169 tpg->real_xfer_func =
2170 V4L2_MAP_XFER_FUNC_DEFAULT(tpg->colorspace);
2171
2172 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
2173 tpg->real_ycbcr_enc =
2174 V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace);
2175
2176 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT)
2177 tpg->real_quantization =
2178 V4L2_MAP_QUANTIZATION_DEFAULT(
2179 tpg->color_enc != TGP_COLOR_ENC_YCBCR,
2180 tpg->colorspace, tpg->real_ycbcr_enc);
2181
2182 tpg_precalculate_colors(tpg);
2183 }
2184 if (tpg->recalc_square_border) {
2185 tpg->recalc_square_border = false;
2186 tpg_calculate_square_border(tpg);
2187 }
2188 if (tpg->recalc_lines) {
2189 tpg->recalc_lines = false;
2190 tpg_precalculate_line(tpg);
2191 }
2192}
2193
2194void tpg_calc_text_basep(struct tpg_data *tpg,
2195 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
2196{
2197 unsigned stride = tpg->bytesperline[p];
2198 unsigned h = tpg->buf_height;
2199
2200 tpg_recalc(tpg);
2201
2202 basep[p][0] = vbuf;
2203 basep[p][1] = vbuf;
2204 h /= tpg->vdownsampling[p];
2205 if (tpg->field == V4L2_FIELD_SEQ_TB)
2206 basep[p][1] += h * stride / 2;
2207 else if (tpg->field == V4L2_FIELD_SEQ_BT)
2208 basep[p][0] += h * stride / 2;
2209 if (p == 0 && tpg->interleaved)
2210 tpg_calc_text_basep(tpg, basep, p: 1, vbuf);
2211}
2212EXPORT_SYMBOL_GPL(tpg_calc_text_basep);
2213
2214static int tpg_pattern_avg(const struct tpg_data *tpg,
2215 unsigned pat1, unsigned pat2)
2216{
2217 unsigned pat_lines = tpg_get_pat_lines(tpg);
2218
2219 if (pat1 == (pat2 + 1) % pat_lines)
2220 return pat2;
2221 if (pat2 == (pat1 + 1) % pat_lines)
2222 return pat1;
2223 return -1;
2224}
2225
2226static const char *tpg_color_enc_str(enum tgp_color_enc
2227 color_enc)
2228{
2229 switch (color_enc) {
2230 case TGP_COLOR_ENC_HSV:
2231 return "HSV";
2232 case TGP_COLOR_ENC_YCBCR:
2233 return "Y'CbCr";
2234 case TGP_COLOR_ENC_LUMA:
2235 return "Luma";
2236 case TGP_COLOR_ENC_RGB:
2237 default:
2238 return "R'G'B";
2239
2240 }
2241}
2242
2243void tpg_log_status(struct tpg_data *tpg)
2244{
2245 pr_info("tpg source WxH: %ux%u (%s)\n",
2246 tpg->src_width, tpg->src_height,
2247 tpg_color_enc_str(tpg->color_enc));
2248 pr_info("tpg field: %u\n", tpg->field);
2249 pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height,
2250 tpg->crop.left, tpg->crop.top);
2251 pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,
2252 tpg->compose.left, tpg->compose.top);
2253 pr_info("tpg colorspace: %d\n", tpg->colorspace);
2254 pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func);
2255 if (tpg->color_enc == TGP_COLOR_ENC_HSV)
2256 pr_info("tpg HSV encoding: %d/%d\n",
2257 tpg->hsv_enc, tpg->real_hsv_enc);
2258 else if (tpg->color_enc == TGP_COLOR_ENC_YCBCR)
2259 pr_info("tpg Y'CbCr encoding: %d/%d\n",
2260 tpg->ycbcr_enc, tpg->real_ycbcr_enc);
2261 pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
2262 pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
2263}
2264EXPORT_SYMBOL_GPL(tpg_log_status);
2265
2266/*
2267 * This struct contains common parameters used by both the drawing of the
2268 * test pattern and the drawing of the extras (borders, square, etc.)
2269 */
2270struct tpg_draw_params {
2271 /* common data */
2272 bool is_tv;
2273 bool is_60hz;
2274 unsigned twopixsize;
2275 unsigned img_width;
2276 unsigned stride;
2277 unsigned hmax;
2278 unsigned frame_line;
2279 unsigned frame_line_next;
2280
2281 /* test pattern */
2282 unsigned mv_hor_old;
2283 unsigned mv_hor_new;
2284 unsigned mv_vert_old;
2285 unsigned mv_vert_new;
2286
2287 /* extras */
2288 unsigned wss_width;
2289 unsigned wss_random_offset;
2290 unsigned sav_eav_f;
2291 unsigned left_pillar_width;
2292 unsigned right_pillar_start;
2293};
2294
2295static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
2296 struct tpg_draw_params *params)
2297{
2298 params->mv_hor_old =
2299 tpg_hscale_div(tpg, plane: p, x: tpg->mv_hor_count % tpg->src_width);
2300 params->mv_hor_new =
2301 tpg_hscale_div(tpg, plane: p, x: (tpg->mv_hor_count + tpg->mv_hor_step) %
2302 tpg->src_width);
2303 params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
2304 params->mv_vert_new =
2305 (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
2306}
2307
2308static void tpg_fill_params_extras(const struct tpg_data *tpg,
2309 unsigned p,
2310 struct tpg_draw_params *params)
2311{
2312 unsigned left_pillar_width = 0;
2313 unsigned right_pillar_start = params->img_width;
2314
2315 params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
2316 tpg->src_width / 2 - tpg->crop.left : 0;
2317 if (params->wss_width > tpg->crop.width)
2318 params->wss_width = tpg->crop.width;
2319 params->wss_width = tpg_hscale_div(tpg, plane: p, x: params->wss_width);
2320 params->wss_random_offset =
2321 params->twopixsize * get_random_u32_below(ceil: tpg->src_width / 2);
2322
2323 if (tpg->crop.left < tpg->border.left) {
2324 left_pillar_width = tpg->border.left - tpg->crop.left;
2325 if (left_pillar_width > tpg->crop.width)
2326 left_pillar_width = tpg->crop.width;
2327 left_pillar_width = tpg_hscale_div(tpg, plane: p, x: left_pillar_width);
2328 }
2329 params->left_pillar_width = left_pillar_width;
2330
2331 if (tpg->crop.left + tpg->crop.width >
2332 tpg->border.left + tpg->border.width) {
2333 right_pillar_start =
2334 tpg->border.left + tpg->border.width - tpg->crop.left;
2335 right_pillar_start =
2336 tpg_hscale_div(tpg, plane: p, x: right_pillar_start);
2337 if (right_pillar_start > params->img_width)
2338 right_pillar_start = params->img_width;
2339 }
2340 params->right_pillar_start = right_pillar_start;
2341
2342 params->sav_eav_f = tpg->field ==
2343 (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
2344}
2345
2346static void tpg_fill_plane_extras(const struct tpg_data *tpg,
2347 const struct tpg_draw_params *params,
2348 unsigned p, unsigned h, u8 *vbuf)
2349{
2350 unsigned twopixsize = params->twopixsize;
2351 unsigned img_width = params->img_width;
2352 unsigned frame_line = params->frame_line;
2353 const struct v4l2_rect *sq = &tpg->square;
2354 const struct v4l2_rect *b = &tpg->border;
2355 const struct v4l2_rect *c = &tpg->crop;
2356
2357 if (params->is_tv && !params->is_60hz &&
2358 frame_line == 0 && params->wss_width) {
2359 /*
2360 * Replace the first half of the top line of a 50 Hz frame
2361 * with random data to simulate a WSS signal.
2362 */
2363 u8 *wss = tpg->random_line[p] + params->wss_random_offset;
2364
2365 memcpy(vbuf, wss, params->wss_width);
2366 }
2367
2368 if (tpg->show_border && frame_line >= b->top &&
2369 frame_line < b->top + b->height) {
2370 unsigned bottom = b->top + b->height - 1;
2371 unsigned left = params->left_pillar_width;
2372 unsigned right = params->right_pillar_start;
2373
2374 if (frame_line == b->top || frame_line == b->top + 1 ||
2375 frame_line == bottom || frame_line == bottom - 1) {
2376 memcpy(vbuf + left, tpg->contrast_line[p],
2377 right - left);
2378 } else {
2379 if (b->left >= c->left &&
2380 b->left < c->left + c->width)
2381 memcpy(vbuf + left,
2382 tpg->contrast_line[p], twopixsize);
2383 if (b->left + b->width > c->left &&
2384 b->left + b->width <= c->left + c->width)
2385 memcpy(vbuf + right - twopixsize,
2386 tpg->contrast_line[p], twopixsize);
2387 }
2388 }
2389 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
2390 frame_line < b->top + b->height) {
2391 memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
2392 memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
2393 img_width - params->right_pillar_start);
2394 }
2395 if (tpg->show_square && frame_line >= sq->top &&
2396 frame_line < sq->top + sq->height &&
2397 sq->left < c->left + c->width &&
2398 sq->left + sq->width >= c->left) {
2399 unsigned left = sq->left;
2400 unsigned width = sq->width;
2401
2402 if (c->left > left) {
2403 width -= c->left - left;
2404 left = c->left;
2405 }
2406 if (c->left + c->width < left + width)
2407 width -= left + width - c->left - c->width;
2408 left -= c->left;
2409 left = tpg_hscale_div(tpg, plane: p, x: left);
2410 width = tpg_hscale_div(tpg, plane: p, x: width);
2411 memcpy(vbuf + left, tpg->contrast_line[p], width);
2412 }
2413 if (tpg->insert_sav) {
2414 unsigned offset = tpg_hdiv(tpg, plane: p, x: tpg->compose.width / 3);
2415 u8 *p = vbuf + offset;
2416 unsigned vact = 0, hact = 0;
2417
2418 p[0] = 0xff;
2419 p[1] = 0;
2420 p[2] = 0;
2421 p[3] = 0x80 | (params->sav_eav_f << 6) |
2422 (vact << 5) | (hact << 4) |
2423 ((hact ^ vact) << 3) |
2424 ((hact ^ params->sav_eav_f) << 2) |
2425 ((params->sav_eav_f ^ vact) << 1) |
2426 (hact ^ vact ^ params->sav_eav_f);
2427 }
2428 if (tpg->insert_eav) {
2429 unsigned offset = tpg_hdiv(tpg, plane: p, x: tpg->compose.width * 2 / 3);
2430 u8 *p = vbuf + offset;
2431 unsigned vact = 0, hact = 1;
2432
2433 p[0] = 0xff;
2434 p[1] = 0;
2435 p[2] = 0;
2436 p[3] = 0x80 | (params->sav_eav_f << 6) |
2437 (vact << 5) | (hact << 4) |
2438 ((hact ^ vact) << 3) |
2439 ((hact ^ params->sav_eav_f) << 2) |
2440 ((params->sav_eav_f ^ vact) << 1) |
2441 (hact ^ vact ^ params->sav_eav_f);
2442 }
2443 if (tpg->insert_hdmi_video_guard_band) {
2444 unsigned int i;
2445
2446 switch (tpg->fourcc) {
2447 case V4L2_PIX_FMT_BGR24:
2448 case V4L2_PIX_FMT_RGB24:
2449 for (i = 0; i < 3 * 4; i += 3) {
2450 vbuf[i] = 0xab;
2451 vbuf[i + 1] = 0x55;
2452 vbuf[i + 2] = 0xab;
2453 }
2454 break;
2455 case V4L2_PIX_FMT_RGB32:
2456 case V4L2_PIX_FMT_ARGB32:
2457 case V4L2_PIX_FMT_XRGB32:
2458 case V4L2_PIX_FMT_BGRX32:
2459 case V4L2_PIX_FMT_BGRA32:
2460 for (i = 0; i < 4 * 4; i += 4) {
2461 vbuf[i] = 0x00;
2462 vbuf[i + 1] = 0xab;
2463 vbuf[i + 2] = 0x55;
2464 vbuf[i + 3] = 0xab;
2465 }
2466 break;
2467 case V4L2_PIX_FMT_BGR32:
2468 case V4L2_PIX_FMT_XBGR32:
2469 case V4L2_PIX_FMT_ABGR32:
2470 case V4L2_PIX_FMT_RGBX32:
2471 case V4L2_PIX_FMT_RGBA32:
2472 for (i = 0; i < 4 * 4; i += 4) {
2473 vbuf[i] = 0xab;
2474 vbuf[i + 1] = 0x55;
2475 vbuf[i + 2] = 0xab;
2476 vbuf[i + 3] = 0x00;
2477 }
2478 break;
2479 }
2480 }
2481}
2482
2483static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
2484 const struct tpg_draw_params *params,
2485 unsigned p, unsigned h, u8 *vbuf)
2486{
2487 unsigned twopixsize = params->twopixsize;
2488 unsigned img_width = params->img_width;
2489 unsigned mv_hor_old = params->mv_hor_old;
2490 unsigned mv_hor_new = params->mv_hor_new;
2491 unsigned mv_vert_old = params->mv_vert_old;
2492 unsigned mv_vert_new = params->mv_vert_new;
2493 unsigned frame_line = params->frame_line;
2494 unsigned frame_line_next = params->frame_line_next;
2495 unsigned line_offset = tpg_hscale_div(tpg, plane: p, x: tpg->crop.left);
2496 bool even;
2497 bool fill_blank = false;
2498 unsigned pat_line_old;
2499 unsigned pat_line_new;
2500 u8 *linestart_older;
2501 u8 *linestart_newer;
2502 u8 *linestart_top;
2503 u8 *linestart_bottom;
2504
2505 even = !(frame_line & 1);
2506
2507 if (h >= params->hmax) {
2508 if (params->hmax == tpg->compose.height)
2509 return;
2510 if (!tpg->perc_fill_blank)
2511 return;
2512 fill_blank = true;
2513 }
2514
2515 if (tpg->vflip) {
2516 frame_line = tpg->src_height - frame_line - 1;
2517 frame_line_next = tpg->src_height - frame_line_next - 1;
2518 }
2519
2520 if (fill_blank) {
2521 linestart_older = tpg->contrast_line[p];
2522 linestart_newer = tpg->contrast_line[p];
2523 } else if (tpg->qual != TPG_QUAL_NOISE &&
2524 (frame_line < tpg->border.top ||
2525 frame_line >= tpg->border.top + tpg->border.height)) {
2526 linestart_older = tpg->black_line[p];
2527 linestart_newer = tpg->black_line[p];
2528 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
2529 linestart_older = tpg->random_line[p] +
2530 twopixsize * get_random_u32_below(ceil: tpg->src_width / 2);
2531 linestart_newer = tpg->random_line[p] +
2532 twopixsize * get_random_u32_below(ceil: tpg->src_width / 2);
2533 } else {
2534 unsigned frame_line_old =
2535 (frame_line + mv_vert_old) % tpg->src_height;
2536 unsigned frame_line_new =
2537 (frame_line + mv_vert_new) % tpg->src_height;
2538 unsigned pat_line_next_old;
2539 unsigned pat_line_next_new;
2540
2541 pat_line_old = tpg_get_pat_line(tpg, line: frame_line_old);
2542 pat_line_new = tpg_get_pat_line(tpg, line: frame_line_new);
2543 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
2544 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
2545
2546 if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
2547 int avg_pat;
2548
2549 /*
2550 * Now decide whether we need to use downsampled_lines[].
2551 * That's necessary if the two lines use different patterns.
2552 */
2553 pat_line_next_old = tpg_get_pat_line(tpg,
2554 line: (frame_line_next + mv_vert_old) % tpg->src_height);
2555 pat_line_next_new = tpg_get_pat_line(tpg,
2556 line: (frame_line_next + mv_vert_new) % tpg->src_height);
2557
2558 switch (tpg->field) {
2559 case V4L2_FIELD_INTERLACED:
2560 case V4L2_FIELD_INTERLACED_BT:
2561 case V4L2_FIELD_INTERLACED_TB:
2562 avg_pat = tpg_pattern_avg(tpg, pat1: pat_line_old, pat2: pat_line_new);
2563 if (avg_pat < 0)
2564 break;
2565 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
2566 linestart_newer = linestart_older;
2567 break;
2568 case V4L2_FIELD_NONE:
2569 case V4L2_FIELD_TOP:
2570 case V4L2_FIELD_BOTTOM:
2571 case V4L2_FIELD_SEQ_BT:
2572 case V4L2_FIELD_SEQ_TB:
2573 avg_pat = tpg_pattern_avg(tpg, pat1: pat_line_old, pat2: pat_line_next_old);
2574 if (avg_pat >= 0)
2575 linestart_older = tpg->downsampled_lines[avg_pat][p] +
2576 mv_hor_old;
2577 avg_pat = tpg_pattern_avg(tpg, pat1: pat_line_new, pat2: pat_line_next_new);
2578 if (avg_pat >= 0)
2579 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
2580 mv_hor_new;
2581 break;
2582 }
2583 }
2584 linestart_older += line_offset;
2585 linestart_newer += line_offset;
2586 }
2587 if (tpg->field_alternate) {
2588 linestart_top = linestart_bottom = linestart_older;
2589 } else if (params->is_60hz) {
2590 linestart_top = linestart_newer;
2591 linestart_bottom = linestart_older;
2592 } else {
2593 linestart_top = linestart_older;
2594 linestart_bottom = linestart_newer;
2595 }
2596
2597 switch (tpg->field) {
2598 case V4L2_FIELD_INTERLACED:
2599 case V4L2_FIELD_INTERLACED_TB:
2600 case V4L2_FIELD_SEQ_TB:
2601 case V4L2_FIELD_SEQ_BT:
2602 if (even)
2603 memcpy(vbuf, linestart_top, img_width);
2604 else
2605 memcpy(vbuf, linestart_bottom, img_width);
2606 break;
2607 case V4L2_FIELD_INTERLACED_BT:
2608 if (even)
2609 memcpy(vbuf, linestart_bottom, img_width);
2610 else
2611 memcpy(vbuf, linestart_top, img_width);
2612 break;
2613 case V4L2_FIELD_TOP:
2614 memcpy(vbuf, linestart_top, img_width);
2615 break;
2616 case V4L2_FIELD_BOTTOM:
2617 memcpy(vbuf, linestart_bottom, img_width);
2618 break;
2619 case V4L2_FIELD_NONE:
2620 default:
2621 memcpy(vbuf, linestart_older, img_width);
2622 break;
2623 }
2624}
2625
2626void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
2627 unsigned p, u8 *vbuf)
2628{
2629 struct tpg_draw_params params;
2630 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
2631
2632 /* Coarse scaling with Bresenham */
2633 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
2634 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
2635 unsigned src_y = 0;
2636 unsigned error = 0;
2637 unsigned h;
2638
2639 tpg_recalc(tpg);
2640
2641 params.is_tv = std;
2642 params.is_60hz = std & V4L2_STD_525_60;
2643 params.twopixsize = tpg->twopixelsize[p];
2644 params.img_width = tpg_hdiv(tpg, plane: p, x: tpg->compose.width);
2645 params.stride = tpg->bytesperline[p];
2646 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
2647
2648 tpg_fill_params_pattern(tpg, p, params: &params);
2649 tpg_fill_params_extras(tpg, p, params: &params);
2650
2651 vbuf += tpg_hdiv(tpg, plane: p, x: tpg->compose.left);
2652
2653 for (h = 0; h < tpg->compose.height; h++) {
2654 unsigned buf_line;
2655
2656 params.frame_line = tpg_calc_frameline(tpg, src_y, field: tpg->field);
2657 params.frame_line_next = params.frame_line;
2658 buf_line = tpg_calc_buffer_line(tpg, y: h, field: tpg->field);
2659 src_y += int_part;
2660 error += fract_part;
2661 if (error >= tpg->compose.height) {
2662 error -= tpg->compose.height;
2663 src_y++;
2664 }
2665
2666 /*
2667 * For line-interleaved formats determine the 'plane'
2668 * based on the buffer line.
2669 */
2670 if (tpg_g_interleaved(tpg))
2671 p = tpg_g_interleaved_plane(tpg, buf_line);
2672
2673 if (tpg->vdownsampling[p] > 1) {
2674 /*
2675 * When doing vertical downsampling the field setting
2676 * matters: for SEQ_BT/TB we downsample each field
2677 * separately (i.e. lines 0+2 are combined, as are
2678 * lines 1+3), for the other field settings we combine
2679 * odd and even lines. Doing that for SEQ_BT/TB would
2680 * be really weird.
2681 */
2682 if (tpg->field == V4L2_FIELD_SEQ_BT ||
2683 tpg->field == V4L2_FIELD_SEQ_TB) {
2684 unsigned next_src_y = src_y;
2685
2686 if ((h & 3) >= 2)
2687 continue;
2688 next_src_y += int_part;
2689 if (error + fract_part >= tpg->compose.height)
2690 next_src_y++;
2691 params.frame_line_next =
2692 tpg_calc_frameline(tpg, src_y: next_src_y, field: tpg->field);
2693 } else {
2694 if (h & 1)
2695 continue;
2696 params.frame_line_next =
2697 tpg_calc_frameline(tpg, src_y, field: tpg->field);
2698 }
2699
2700 buf_line /= tpg->vdownsampling[p];
2701 }
2702 tpg_fill_plane_pattern(tpg, params: &params, p, h,
2703 vbuf: vbuf + buf_line * params.stride);
2704 tpg_fill_plane_extras(tpg, params: &params, p, h,
2705 vbuf: vbuf + buf_line * params.stride);
2706 }
2707}
2708EXPORT_SYMBOL_GPL(tpg_fill_plane_buffer);
2709
2710void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
2711{
2712 unsigned offset = 0;
2713 unsigned i;
2714
2715 if (tpg->buffers > 1) {
2716 tpg_fill_plane_buffer(tpg, std, p, vbuf);
2717 return;
2718 }
2719
2720 for (i = 0; i < tpg_g_planes(tpg); i++) {
2721 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
2722 offset += tpg_calc_plane_size(tpg, plane: i);
2723 }
2724}
2725EXPORT_SYMBOL_GPL(tpg_fillbuffer);
2726
2727MODULE_DESCRIPTION("V4L2 Test Pattern Generator");
2728MODULE_AUTHOR("Hans Verkuil");
2729MODULE_LICENSE("GPL");
2730

source code of linux/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c