1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * v4l2-tpg.h - Test Pattern Generator |
4 | * |
5 | * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
6 | */ |
7 | |
8 | #ifndef _V4L2_TPG_H_ |
9 | #define _V4L2_TPG_H_ |
10 | |
11 | #include <linux/types.h> |
12 | #include <linux/errno.h> |
13 | #include <linux/random.h> |
14 | #include <linux/slab.h> |
15 | #include <linux/vmalloc.h> |
16 | #include <linux/videodev2.h> |
17 | |
18 | struct tpg_rbg_color8 { |
19 | unsigned char r, g, b; |
20 | }; |
21 | |
22 | struct tpg_rbg_color16 { |
23 | __u16 r, g, b; |
24 | }; |
25 | |
26 | enum tpg_color { |
27 | TPG_COLOR_CSC_WHITE, |
28 | TPG_COLOR_CSC_YELLOW, |
29 | TPG_COLOR_CSC_CYAN, |
30 | TPG_COLOR_CSC_GREEN, |
31 | TPG_COLOR_CSC_MAGENTA, |
32 | TPG_COLOR_CSC_RED, |
33 | TPG_COLOR_CSC_BLUE, |
34 | TPG_COLOR_CSC_BLACK, |
35 | TPG_COLOR_75_YELLOW, |
36 | TPG_COLOR_75_CYAN, |
37 | TPG_COLOR_75_GREEN, |
38 | TPG_COLOR_75_MAGENTA, |
39 | TPG_COLOR_75_RED, |
40 | TPG_COLOR_75_BLUE, |
41 | TPG_COLOR_100_WHITE, |
42 | TPG_COLOR_100_YELLOW, |
43 | TPG_COLOR_100_CYAN, |
44 | TPG_COLOR_100_GREEN, |
45 | TPG_COLOR_100_MAGENTA, |
46 | TPG_COLOR_100_RED, |
47 | TPG_COLOR_100_BLUE, |
48 | TPG_COLOR_100_BLACK, |
49 | TPG_COLOR_TEXTFG, |
50 | TPG_COLOR_TEXTBG, |
51 | TPG_COLOR_RANDOM, |
52 | TPG_COLOR_RAMP, |
53 | TPG_COLOR_MAX = TPG_COLOR_RAMP + 256 |
54 | }; |
55 | |
56 | extern const struct tpg_rbg_color8 tpg_colors[TPG_COLOR_MAX]; |
57 | extern const unsigned short tpg_rec709_to_linear[255 * 16 + 1]; |
58 | extern const unsigned short tpg_linear_to_rec709[255 * 16 + 1]; |
59 | extern const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1] |
60 | [V4L2_XFER_FUNC_SMPTE2084 + 1] |
61 | [TPG_COLOR_CSC_BLACK + 1]; |
62 | enum tpg_pattern { |
63 | TPG_PAT_75_COLORBAR, |
64 | TPG_PAT_100_COLORBAR, |
65 | TPG_PAT_CSC_COLORBAR, |
66 | TPG_PAT_100_HCOLORBAR, |
67 | TPG_PAT_100_COLORSQUARES, |
68 | TPG_PAT_BLACK, |
69 | TPG_PAT_WHITE, |
70 | TPG_PAT_RED, |
71 | TPG_PAT_GREEN, |
72 | TPG_PAT_BLUE, |
73 | TPG_PAT_CHECKERS_16X16, |
74 | TPG_PAT_CHECKERS_2X2, |
75 | TPG_PAT_CHECKERS_1X1, |
76 | TPG_PAT_COLOR_CHECKERS_2X2, |
77 | TPG_PAT_COLOR_CHECKERS_1X1, |
78 | TPG_PAT_ALTERNATING_HLINES, |
79 | TPG_PAT_ALTERNATING_VLINES, |
80 | TPG_PAT_CROSS_1_PIXEL, |
81 | TPG_PAT_CROSS_2_PIXELS, |
82 | TPG_PAT_CROSS_10_PIXELS, |
83 | TPG_PAT_GRAY_RAMP, |
84 | |
85 | /* Must be the last pattern */ |
86 | TPG_PAT_NOISE, |
87 | }; |
88 | |
89 | extern const char * const tpg_pattern_strings[]; |
90 | |
91 | enum tpg_quality { |
92 | TPG_QUAL_COLOR, |
93 | TPG_QUAL_GRAY, |
94 | TPG_QUAL_NOISE |
95 | }; |
96 | |
97 | enum tpg_video_aspect { |
98 | TPG_VIDEO_ASPECT_IMAGE, |
99 | TPG_VIDEO_ASPECT_4X3, |
100 | TPG_VIDEO_ASPECT_14X9_CENTRE, |
101 | TPG_VIDEO_ASPECT_16X9_CENTRE, |
102 | TPG_VIDEO_ASPECT_16X9_ANAMORPHIC, |
103 | }; |
104 | |
105 | enum tpg_pixel_aspect { |
106 | TPG_PIXEL_ASPECT_SQUARE, |
107 | TPG_PIXEL_ASPECT_NTSC, |
108 | TPG_PIXEL_ASPECT_PAL, |
109 | }; |
110 | |
111 | enum tpg_move_mode { |
112 | TPG_MOVE_NEG_FAST, |
113 | TPG_MOVE_NEG, |
114 | TPG_MOVE_NEG_SLOW, |
115 | TPG_MOVE_NONE, |
116 | TPG_MOVE_POS_SLOW, |
117 | TPG_MOVE_POS, |
118 | TPG_MOVE_POS_FAST, |
119 | }; |
120 | |
121 | enum tgp_color_enc { |
122 | TGP_COLOR_ENC_RGB, |
123 | TGP_COLOR_ENC_YCBCR, |
124 | TGP_COLOR_ENC_HSV, |
125 | TGP_COLOR_ENC_LUMA, |
126 | }; |
127 | |
128 | extern const char * const tpg_aspect_strings[]; |
129 | |
130 | #define TPG_MAX_PLANES 3 |
131 | #define TPG_MAX_PAT_LINES 8 |
132 | |
133 | struct tpg_data { |
134 | /* Source frame size */ |
135 | unsigned src_width, src_height; |
136 | /* Buffer height */ |
137 | unsigned buf_height; |
138 | /* Scaled output frame size */ |
139 | unsigned scaled_width; |
140 | u32 field; |
141 | bool field_alternate; |
142 | /* crop coordinates are frame-based */ |
143 | struct v4l2_rect crop; |
144 | /* compose coordinates are format-based */ |
145 | struct v4l2_rect compose; |
146 | /* border and square coordinates are frame-based */ |
147 | struct v4l2_rect border; |
148 | struct v4l2_rect square; |
149 | |
150 | /* Color-related fields */ |
151 | enum tpg_quality qual; |
152 | unsigned qual_offset; |
153 | u8 alpha_component; |
154 | bool alpha_red_only; |
155 | u8 brightness; |
156 | u8 contrast; |
157 | u8 saturation; |
158 | s16 hue; |
159 | u32 fourcc; |
160 | enum tgp_color_enc color_enc; |
161 | u32 colorspace; |
162 | u32 xfer_func; |
163 | u32 ycbcr_enc; |
164 | u32 hsv_enc; |
165 | /* |
166 | * Stores the actual transfer function, i.e. will never be |
167 | * V4L2_XFER_FUNC_DEFAULT. |
168 | */ |
169 | u32 real_xfer_func; |
170 | /* |
171 | * Stores the actual Y'CbCr encoding, i.e. will never be |
172 | * V4L2_YCBCR_ENC_DEFAULT. |
173 | */ |
174 | u32 real_hsv_enc; |
175 | u32 real_ycbcr_enc; |
176 | u32 quantization; |
177 | /* |
178 | * Stores the actual quantization, i.e. will never be |
179 | * V4L2_QUANTIZATION_DEFAULT. |
180 | */ |
181 | u32 real_quantization; |
182 | enum tpg_video_aspect vid_aspect; |
183 | enum tpg_pixel_aspect pix_aspect; |
184 | unsigned rgb_range; |
185 | unsigned real_rgb_range; |
186 | unsigned buffers; |
187 | unsigned planes; |
188 | bool interleaved; |
189 | u8 vdownsampling[TPG_MAX_PLANES]; |
190 | u8 hdownsampling[TPG_MAX_PLANES]; |
191 | /* |
192 | * horizontal positions must be ANDed with this value to enforce |
193 | * correct boundaries for packed YUYV values. |
194 | */ |
195 | unsigned hmask[TPG_MAX_PLANES]; |
196 | /* Used to store the colors in native format, either RGB or YUV */ |
197 | u8 colors[TPG_COLOR_MAX][3]; |
198 | u8 textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8]; |
199 | /* size in bytes for two pixels in each plane */ |
200 | unsigned twopixelsize[TPG_MAX_PLANES]; |
201 | unsigned bytesperline[TPG_MAX_PLANES]; |
202 | |
203 | /* Configuration */ |
204 | enum tpg_pattern pattern; |
205 | bool hflip; |
206 | bool vflip; |
207 | unsigned perc_fill; |
208 | bool perc_fill_blank; |
209 | bool show_border; |
210 | bool show_square; |
211 | bool insert_sav; |
212 | bool insert_eav; |
213 | bool insert_hdmi_video_guard_band; |
214 | |
215 | /* Test pattern movement */ |
216 | enum tpg_move_mode mv_hor_mode; |
217 | int mv_hor_count; |
218 | int mv_hor_step; |
219 | enum tpg_move_mode mv_vert_mode; |
220 | int mv_vert_count; |
221 | int mv_vert_step; |
222 | |
223 | bool recalc_colors; |
224 | bool recalc_lines; |
225 | bool recalc_square_border; |
226 | |
227 | /* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */ |
228 | unsigned max_line_width; |
229 | u8 *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; |
230 | u8 *downsampled_lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; |
231 | u8 *random_line[TPG_MAX_PLANES]; |
232 | u8 *contrast_line[TPG_MAX_PLANES]; |
233 | u8 *black_line[TPG_MAX_PLANES]; |
234 | }; |
235 | |
236 | void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h); |
237 | int tpg_alloc(struct tpg_data *tpg, unsigned max_w); |
238 | void tpg_free(struct tpg_data *tpg); |
239 | void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, |
240 | u32 field); |
241 | void tpg_log_status(struct tpg_data *tpg); |
242 | |
243 | void tpg_set_font(const u8 *f); |
244 | void tpg_gen_text(const struct tpg_data *tpg, |
245 | u8 *basep[TPG_MAX_PLANES][2], int y, int x, const char *text); |
246 | void tpg_calc_text_basep(struct tpg_data *tpg, |
247 | u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf); |
248 | unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line); |
249 | void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, |
250 | unsigned p, u8 *vbuf); |
251 | void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, |
252 | unsigned p, u8 *vbuf); |
253 | bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc); |
254 | void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, |
255 | const struct v4l2_rect *compose); |
256 | const char *tpg_g_color_order(const struct tpg_data *tpg); |
257 | |
258 | static inline void tpg_s_pattern(struct tpg_data *tpg, enum tpg_pattern pattern) |
259 | { |
260 | if (tpg->pattern == pattern) |
261 | return; |
262 | tpg->pattern = pattern; |
263 | tpg->recalc_colors = true; |
264 | } |
265 | |
266 | static inline void tpg_s_quality(struct tpg_data *tpg, |
267 | enum tpg_quality qual, unsigned qual_offset) |
268 | { |
269 | if (tpg->qual == qual && tpg->qual_offset == qual_offset) |
270 | return; |
271 | tpg->qual = qual; |
272 | tpg->qual_offset = qual_offset; |
273 | tpg->recalc_colors = true; |
274 | } |
275 | |
276 | static inline enum tpg_quality tpg_g_quality(const struct tpg_data *tpg) |
277 | { |
278 | return tpg->qual; |
279 | } |
280 | |
281 | static inline void tpg_s_alpha_component(struct tpg_data *tpg, |
282 | u8 alpha_component) |
283 | { |
284 | if (tpg->alpha_component == alpha_component) |
285 | return; |
286 | tpg->alpha_component = alpha_component; |
287 | tpg->recalc_colors = true; |
288 | } |
289 | |
290 | static inline void tpg_s_alpha_mode(struct tpg_data *tpg, |
291 | bool red_only) |
292 | { |
293 | if (tpg->alpha_red_only == red_only) |
294 | return; |
295 | tpg->alpha_red_only = red_only; |
296 | tpg->recalc_colors = true; |
297 | } |
298 | |
299 | static inline void tpg_s_brightness(struct tpg_data *tpg, |
300 | u8 brightness) |
301 | { |
302 | if (tpg->brightness == brightness) |
303 | return; |
304 | tpg->brightness = brightness; |
305 | tpg->recalc_colors = true; |
306 | } |
307 | |
308 | static inline void tpg_s_contrast(struct tpg_data *tpg, |
309 | u8 contrast) |
310 | { |
311 | if (tpg->contrast == contrast) |
312 | return; |
313 | tpg->contrast = contrast; |
314 | tpg->recalc_colors = true; |
315 | } |
316 | |
317 | static inline void tpg_s_saturation(struct tpg_data *tpg, |
318 | u8 saturation) |
319 | { |
320 | if (tpg->saturation == saturation) |
321 | return; |
322 | tpg->saturation = saturation; |
323 | tpg->recalc_colors = true; |
324 | } |
325 | |
326 | static inline void tpg_s_hue(struct tpg_data *tpg, |
327 | s16 hue) |
328 | { |
329 | hue = clamp_t(s16, hue, -128, 128); |
330 | if (tpg->hue == hue) |
331 | return; |
332 | tpg->hue = hue; |
333 | tpg->recalc_colors = true; |
334 | } |
335 | |
336 | static inline void tpg_s_rgb_range(struct tpg_data *tpg, |
337 | unsigned rgb_range) |
338 | { |
339 | if (tpg->rgb_range == rgb_range) |
340 | return; |
341 | tpg->rgb_range = rgb_range; |
342 | tpg->recalc_colors = true; |
343 | } |
344 | |
345 | static inline void tpg_s_real_rgb_range(struct tpg_data *tpg, |
346 | unsigned rgb_range) |
347 | { |
348 | if (tpg->real_rgb_range == rgb_range) |
349 | return; |
350 | tpg->real_rgb_range = rgb_range; |
351 | tpg->recalc_colors = true; |
352 | } |
353 | |
354 | static inline void tpg_s_colorspace(struct tpg_data *tpg, u32 colorspace) |
355 | { |
356 | if (tpg->colorspace == colorspace) |
357 | return; |
358 | tpg->colorspace = colorspace; |
359 | tpg->recalc_colors = true; |
360 | } |
361 | |
362 | static inline u32 tpg_g_colorspace(const struct tpg_data *tpg) |
363 | { |
364 | return tpg->colorspace; |
365 | } |
366 | |
367 | static inline void tpg_s_ycbcr_enc(struct tpg_data *tpg, u32 ycbcr_enc) |
368 | { |
369 | if (tpg->ycbcr_enc == ycbcr_enc) |
370 | return; |
371 | tpg->ycbcr_enc = ycbcr_enc; |
372 | tpg->recalc_colors = true; |
373 | } |
374 | |
375 | static inline u32 tpg_g_ycbcr_enc(const struct tpg_data *tpg) |
376 | { |
377 | return tpg->ycbcr_enc; |
378 | } |
379 | |
380 | static inline void tpg_s_hsv_enc(struct tpg_data *tpg, u32 hsv_enc) |
381 | { |
382 | if (tpg->hsv_enc == hsv_enc) |
383 | return; |
384 | tpg->hsv_enc = hsv_enc; |
385 | tpg->recalc_colors = true; |
386 | } |
387 | |
388 | static inline u32 tpg_g_hsv_enc(const struct tpg_data *tpg) |
389 | { |
390 | return tpg->hsv_enc; |
391 | } |
392 | |
393 | static inline void tpg_s_xfer_func(struct tpg_data *tpg, u32 xfer_func) |
394 | { |
395 | if (tpg->xfer_func == xfer_func) |
396 | return; |
397 | tpg->xfer_func = xfer_func; |
398 | tpg->recalc_colors = true; |
399 | } |
400 | |
401 | static inline u32 tpg_g_xfer_func(const struct tpg_data *tpg) |
402 | { |
403 | return tpg->xfer_func; |
404 | } |
405 | |
406 | static inline void tpg_s_quantization(struct tpg_data *tpg, u32 quantization) |
407 | { |
408 | if (tpg->quantization == quantization) |
409 | return; |
410 | tpg->quantization = quantization; |
411 | tpg->recalc_colors = true; |
412 | } |
413 | |
414 | static inline u32 tpg_g_quantization(const struct tpg_data *tpg) |
415 | { |
416 | return tpg->quantization; |
417 | } |
418 | |
419 | static inline unsigned tpg_g_buffers(const struct tpg_data *tpg) |
420 | { |
421 | return tpg->buffers; |
422 | } |
423 | |
424 | static inline unsigned tpg_g_planes(const struct tpg_data *tpg) |
425 | { |
426 | return tpg->interleaved ? 1 : tpg->planes; |
427 | } |
428 | |
429 | static inline bool tpg_g_interleaved(const struct tpg_data *tpg) |
430 | { |
431 | return tpg->interleaved; |
432 | } |
433 | |
434 | static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane) |
435 | { |
436 | return tpg->twopixelsize[plane]; |
437 | } |
438 | |
439 | static inline unsigned tpg_hdiv(const struct tpg_data *tpg, |
440 | unsigned plane, unsigned x) |
441 | { |
442 | return ((x / tpg->hdownsampling[plane]) & tpg->hmask[plane]) * |
443 | tpg->twopixelsize[plane] / 2; |
444 | } |
445 | |
446 | static inline unsigned tpg_hscale(const struct tpg_data *tpg, unsigned x) |
447 | { |
448 | return (x * tpg->scaled_width) / tpg->src_width; |
449 | } |
450 | |
451 | static inline unsigned tpg_hscale_div(const struct tpg_data *tpg, |
452 | unsigned plane, unsigned x) |
453 | { |
454 | return tpg_hdiv(tpg, plane, x: tpg_hscale(tpg, x)); |
455 | } |
456 | |
457 | static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane) |
458 | { |
459 | return tpg->bytesperline[plane]; |
460 | } |
461 | |
462 | static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl) |
463 | { |
464 | unsigned p; |
465 | |
466 | if (tpg->buffers > 1) { |
467 | tpg->bytesperline[plane] = bpl; |
468 | return; |
469 | } |
470 | |
471 | for (p = 0; p < tpg_g_planes(tpg); p++) { |
472 | unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; |
473 | |
474 | tpg->bytesperline[p] = plane_w / tpg->hdownsampling[p]; |
475 | } |
476 | if (tpg_g_interleaved(tpg)) |
477 | tpg->bytesperline[1] = tpg->bytesperline[0]; |
478 | } |
479 | |
480 | |
481 | static inline unsigned tpg_g_line_width(const struct tpg_data *tpg, unsigned plane) |
482 | { |
483 | unsigned w = 0; |
484 | unsigned p; |
485 | |
486 | if (tpg->buffers > 1) |
487 | return tpg_g_bytesperline(tpg, plane); |
488 | for (p = 0; p < tpg_g_planes(tpg); p++) { |
489 | unsigned plane_w = tpg_g_bytesperline(tpg, plane: p); |
490 | |
491 | w += plane_w / tpg->vdownsampling[p]; |
492 | } |
493 | return w; |
494 | } |
495 | |
496 | static inline unsigned tpg_calc_line_width(const struct tpg_data *tpg, |
497 | unsigned plane, unsigned bpl) |
498 | { |
499 | unsigned w = 0; |
500 | unsigned p; |
501 | |
502 | if (tpg->buffers > 1) |
503 | return bpl; |
504 | for (p = 0; p < tpg_g_planes(tpg); p++) { |
505 | unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; |
506 | |
507 | plane_w /= tpg->hdownsampling[p]; |
508 | w += plane_w / tpg->vdownsampling[p]; |
509 | } |
510 | return w; |
511 | } |
512 | |
513 | static inline unsigned tpg_calc_plane_size(const struct tpg_data *tpg, unsigned plane) |
514 | { |
515 | if (plane >= tpg_g_planes(tpg)) |
516 | return 0; |
517 | |
518 | return tpg_g_bytesperline(tpg, plane) * tpg->buf_height / |
519 | tpg->vdownsampling[plane]; |
520 | } |
521 | |
522 | static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h) |
523 | { |
524 | tpg->buf_height = h; |
525 | } |
526 | |
527 | static inline void tpg_s_field(struct tpg_data *tpg, unsigned field, bool alternate) |
528 | { |
529 | tpg->field = field; |
530 | tpg->field_alternate = alternate; |
531 | } |
532 | |
533 | static inline void tpg_s_perc_fill(struct tpg_data *tpg, |
534 | unsigned perc_fill) |
535 | { |
536 | tpg->perc_fill = perc_fill; |
537 | } |
538 | |
539 | static inline unsigned tpg_g_perc_fill(const struct tpg_data *tpg) |
540 | { |
541 | return tpg->perc_fill; |
542 | } |
543 | |
544 | static inline void tpg_s_perc_fill_blank(struct tpg_data *tpg, |
545 | bool perc_fill_blank) |
546 | { |
547 | tpg->perc_fill_blank = perc_fill_blank; |
548 | } |
549 | |
550 | static inline void tpg_s_video_aspect(struct tpg_data *tpg, |
551 | enum tpg_video_aspect vid_aspect) |
552 | { |
553 | if (tpg->vid_aspect == vid_aspect) |
554 | return; |
555 | tpg->vid_aspect = vid_aspect; |
556 | tpg->recalc_square_border = true; |
557 | } |
558 | |
559 | static inline enum tpg_video_aspect tpg_g_video_aspect(const struct tpg_data *tpg) |
560 | { |
561 | return tpg->vid_aspect; |
562 | } |
563 | |
564 | static inline void tpg_s_pixel_aspect(struct tpg_data *tpg, |
565 | enum tpg_pixel_aspect pix_aspect) |
566 | { |
567 | if (tpg->pix_aspect == pix_aspect) |
568 | return; |
569 | tpg->pix_aspect = pix_aspect; |
570 | tpg->recalc_square_border = true; |
571 | } |
572 | |
573 | static inline void tpg_s_show_border(struct tpg_data *tpg, |
574 | bool show_border) |
575 | { |
576 | tpg->show_border = show_border; |
577 | } |
578 | |
579 | static inline void tpg_s_show_square(struct tpg_data *tpg, |
580 | bool show_square) |
581 | { |
582 | tpg->show_square = show_square; |
583 | } |
584 | |
585 | static inline void tpg_s_insert_sav(struct tpg_data *tpg, bool insert_sav) |
586 | { |
587 | tpg->insert_sav = insert_sav; |
588 | } |
589 | |
590 | static inline void tpg_s_insert_eav(struct tpg_data *tpg, bool insert_eav) |
591 | { |
592 | tpg->insert_eav = insert_eav; |
593 | } |
594 | |
595 | /* |
596 | * This inserts 4 pixels of the RGB color 0xab55ab at the left hand side of the |
597 | * image. This is only done for 3 or 4 byte RGB pixel formats. This pixel value |
598 | * equals the Video Guard Band value as defined by HDMI (see section 5.2.2.1 |
599 | * in the HDMI 1.3 Specification) that preceeds the first actual pixel. If the |
600 | * HDMI receiver doesn't handle this correctly, then it might keep skipping |
601 | * these Video Guard Band patterns and end up with a shorter video line. So this |
602 | * is a nice pattern to test with. |
603 | */ |
604 | static inline void tpg_s_insert_hdmi_video_guard_band(struct tpg_data *tpg, |
605 | bool insert_hdmi_video_guard_band) |
606 | { |
607 | tpg->insert_hdmi_video_guard_band = insert_hdmi_video_guard_band; |
608 | } |
609 | |
610 | void tpg_update_mv_step(struct tpg_data *tpg); |
611 | |
612 | static inline void tpg_s_mv_hor_mode(struct tpg_data *tpg, |
613 | enum tpg_move_mode mv_hor_mode) |
614 | { |
615 | tpg->mv_hor_mode = mv_hor_mode; |
616 | tpg_update_mv_step(tpg); |
617 | } |
618 | |
619 | static inline void tpg_s_mv_vert_mode(struct tpg_data *tpg, |
620 | enum tpg_move_mode mv_vert_mode) |
621 | { |
622 | tpg->mv_vert_mode = mv_vert_mode; |
623 | tpg_update_mv_step(tpg); |
624 | } |
625 | |
626 | static inline void tpg_init_mv_count(struct tpg_data *tpg) |
627 | { |
628 | tpg->mv_hor_count = tpg->mv_vert_count = 0; |
629 | } |
630 | |
631 | static inline void tpg_update_mv_count(struct tpg_data *tpg, bool frame_is_field) |
632 | { |
633 | tpg->mv_hor_count += tpg->mv_hor_step * (frame_is_field ? 1 : 2); |
634 | tpg->mv_vert_count += tpg->mv_vert_step * (frame_is_field ? 1 : 2); |
635 | } |
636 | |
637 | static inline void tpg_s_hflip(struct tpg_data *tpg, bool hflip) |
638 | { |
639 | if (tpg->hflip == hflip) |
640 | return; |
641 | tpg->hflip = hflip; |
642 | tpg_update_mv_step(tpg); |
643 | tpg->recalc_lines = true; |
644 | } |
645 | |
646 | static inline bool tpg_g_hflip(const struct tpg_data *tpg) |
647 | { |
648 | return tpg->hflip; |
649 | } |
650 | |
651 | static inline void tpg_s_vflip(struct tpg_data *tpg, bool vflip) |
652 | { |
653 | tpg->vflip = vflip; |
654 | } |
655 | |
656 | static inline bool tpg_g_vflip(const struct tpg_data *tpg) |
657 | { |
658 | return tpg->vflip; |
659 | } |
660 | |
661 | static inline bool tpg_pattern_is_static(const struct tpg_data *tpg) |
662 | { |
663 | return tpg->pattern != TPG_PAT_NOISE && |
664 | tpg->mv_hor_mode == TPG_MOVE_NONE && |
665 | tpg->mv_vert_mode == TPG_MOVE_NONE; |
666 | } |
667 | |
668 | #endif |
669 | |