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