1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * v4l2-ctl-modes.cpp - functions to calculate cvt and gtf mode timings.
4 *
5 * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights
6 * reserved.
7 */
8
9 #include "v4l2-ctl.h"
10
valid_params(int width,int height,int refresh_rate)11 static bool valid_params(int width, int height, int refresh_rate)
12 {
13 if (width <= 0) {
14 fprintf(stderr, "Invalid value %d for width\n", width);
15 return false;
16 }
17
18 if (height <= 0) {
19 fprintf(stderr, "Invalid value %d for height\n", height);
20 return false;
21 }
22
23 if (refresh_rate <= 0) {
24 fprintf(stderr, "Invalid value %d for refresh rate\n",
25 refresh_rate);
26 return false;
27 }
28 return true;
29 }
30
31 #define HV_FACTOR (1000)
32 #define CVT_MARGIN_PERCENT (18)
33 #define CVT_HSYNC_PERCENT (8)
34
35 /*
36 * CVT defines Based on
37 * Coordinated Video Timings Standard Ver 1.2 Feb 08, 2013
38 */
39
40 #define CVT_PXL_CLK_GRAN (250000) /* pixel clock granularity */
41 #define CVT_PXL_CLK_GRAN_RB_V2 (1000) /* granularity for reduced blanking v2*/
42
43 /* Normal blanking */
44 #define CVT_MIN_V_BPORCH (7) /* lines */
45 #define CVT_MIN_V_PORCH_RND (3) /* lines */
46 #define CVT_MIN_VSYNC_BP (550) /* time v_sync + back porch (us)*/
47
48 /* Normal blanking for CVT uses GTF
49 * to calculate horizontal blanking */
50 #define CVT_CELL_GRAN (8) /* character cell granularity */
51 #define CVT_M (600) /* blanking formula gradient */
52 #define CVT_C (40) /* blanking formula offset */
53 #define CVT_K (128) /* blanking formula scale factor */
54 #define CVT_J (20) /* blanking formula scale factor */
55
56 #define CVT_C_PRIME (((CVT_C - CVT_J) * CVT_K / 256) + CVT_J)
57 #define CVT_M_PRIME (CVT_K * CVT_M / 256)
58
59 /* Reduced Blanking */
60 #define CVT_RB_MIN_V_BPORCH (7) /* lines */
61 #define CVT_RB_V_FPORCH (3) /* lines */
62 #define CVT_RB_MIN_V_BLANK (460) /* us */
63 #define CVT_RB_H_SYNC (32) /* pixels */
64 #define CVT_RB_H_BPORCH (80) /* pixels */
65 #define CVT_RB_H_BLANK (160) /* pixels */
66
67 /* Reduce blanking Version 2 */
68 #define CVT_RB_V2_H_BLANK 80 /* pixels */
69 #define CVT_RB_MIN_V_FPORCH 3 /* lines */
70 #define CVT_RB_V2_MIN_V_FPORCH 1 /* lines */
71 #define CVT_RB_V_BPORCH 6 /* lines */
72
v_sync_from_aspect_ratio(int width,int height)73 static int v_sync_from_aspect_ratio(int width, int height)
74 {
75 if (((height * 4 / 3) / CVT_CELL_GRAN) * CVT_CELL_GRAN == width)
76 return 4;
77
78 if (((height * 16 / 9) / CVT_CELL_GRAN) * CVT_CELL_GRAN == width)
79 return 5;
80
81 if (((height * 16 / 10) / CVT_CELL_GRAN) * CVT_CELL_GRAN == width)
82 return 6;
83
84 if (((height * 5 / 4) / CVT_CELL_GRAN) * CVT_CELL_GRAN == width)
85 return 7;
86
87 if (((height * 15 / 9) / CVT_CELL_GRAN) * CVT_CELL_GRAN == width)
88 return 7;
89
90 /* custom aspect ratio */
91 fprintf(stderr, "Warning! Aspect ratio is not CVT Standard\n");
92 return 10;
93 }
94
95 /**
96 * calc_cvt_modeline - calculate modeline based on CVT algorithm
97 *
98 * This function is called to generate the timings according to CVT
99 * algorithm. Timing calculation is based on VESA(TM) Coordinated
100 * Video Timing Generator Rev 1.2 by Graham Loveridge May 28, 2013
101 * which can be downloaded from -
102 * http://www.vesa.org/vesa-standards/free-standards/
103 *
104 * Input Parameters:
105 * @image_width
106 * @image_height
107 * @refresh_rate
108 * @reduced_blanking: This value, if greater than 0, indicates that
109 * reduced blanking is to be used and value indicates the version.
110 * @interlaced: whether to compute an interlaced mode
111 * @reduced_fps: set the V4L2_DV_FL_REDUCED_FPS flag indicating that
112 * the fps should be reduced by a factor of 1000 / 1001
113 * @cvt: stores results of cvt timing calculation
114 *
115 * Returns:
116 * true, if cvt timings are calculated and filled in cvt modeline.
117 * false, for any error
118 */
119
calc_cvt_modeline(int image_width,int image_height,int refresh_rate,int reduced_blanking,bool interlaced,bool reduced_fps,struct v4l2_bt_timings * cvt)120 bool calc_cvt_modeline(int image_width, int image_height,
121 int refresh_rate, int reduced_blanking,
122 bool interlaced, bool reduced_fps,
123 struct v4l2_bt_timings *cvt)
124 {
125 int h_sync;
126 int v_sync;
127 int h_fp;
128 int h_bp;
129 int v_fp;
130 int v_bp;
131
132 int h_pixel;
133 int v_lines;
134 int h_pixel_rnd;
135 int v_lines_rnd;
136 int active_h_pixel;
137 int active_v_lines;
138 int total_h_pixel;
139 int total_v_lines;
140
141 int h_blank;
142 int v_blank;
143
144 int h_period;
145
146 int interlace;
147 int v_refresh;
148 int pixel_clock;
149 int clk_gran;
150 bool use_rb;
151 bool rb_v2;
152
153 if (!valid_params(image_width, image_height, refresh_rate))
154 return false;
155
156 use_rb = reduced_blanking > 0;
157 rb_v2 = reduced_blanking == 2;
158
159 clk_gran = rb_v2 ? CVT_PXL_CLK_GRAN_RB_V2 : CVT_PXL_CLK_GRAN;
160
161 h_pixel = image_width;
162 v_lines = image_height;
163
164 if (!refresh_rate)
165 v_refresh = 60;
166 else
167 v_refresh = refresh_rate;
168
169 if (v_refresh != 50 && v_refresh != 60 &&
170 v_refresh != 75 && v_refresh != 85)
171 fprintf(stderr, "Warning! Refresh rate is not CVT standard\n");
172
173 if (interlaced) {
174 interlace = 1;
175 v_lines_rnd = v_lines / 2;
176 v_refresh = v_refresh * 2;
177
178 if ((v_lines_rnd * 2) != v_lines)
179 fprintf(stderr,
180 "Warning! Vertical lines rounded to nearest integer\n");
181 } else {
182 interlace = 0;
183 v_lines_rnd = v_lines;
184 }
185
186 h_pixel_rnd = h_pixel - (h_pixel % CVT_CELL_GRAN);
187
188 if (h_pixel_rnd != h_pixel)
189 fprintf(stderr,
190 "Warning! Horizontal pixels rounded to nearest character cell\n");
191
192 active_h_pixel = h_pixel_rnd;
193 active_v_lines = v_lines_rnd;
194
195 v_sync = rb_v2 ? 8 : v_sync_from_aspect_ratio(h_pixel, v_lines);
196
197 if (!use_rb) {
198 int tmp1, tmp2;
199 int ideal_blank_duty_cycle;
200 int v_sync_bp;
201
202 /* estimate the horizontal period */
203 tmp1 = HV_FACTOR * 1000000 -
204 CVT_MIN_VSYNC_BP * HV_FACTOR * v_refresh;
205 tmp2 = (active_v_lines + CVT_MIN_V_PORCH_RND) * 2 + interlace;
206
207 h_period = tmp1 * 2 / (tmp2 * v_refresh);
208
209 tmp1 = CVT_MIN_VSYNC_BP * HV_FACTOR / h_period + 1;
210
211 if (tmp1 < (v_sync + CVT_MIN_V_PORCH_RND))
212 v_sync_bp = v_sync + CVT_MIN_V_PORCH_RND;
213 else
214 v_sync_bp = tmp1;
215
216 v_bp = v_sync_bp - v_sync;
217 v_fp = CVT_MIN_V_PORCH_RND;
218
219 ideal_blank_duty_cycle = (CVT_C_PRIME * HV_FACTOR) -
220 CVT_M_PRIME * h_period / 1000;
221
222 if (ideal_blank_duty_cycle < 20 * HV_FACTOR)
223 ideal_blank_duty_cycle = 20 * HV_FACTOR;
224
225 h_blank = active_h_pixel * static_cast<long long>(ideal_blank_duty_cycle) /
226 (100 * HV_FACTOR - ideal_blank_duty_cycle);
227 h_blank -= h_blank % (2 * CVT_CELL_GRAN);
228
229 v_blank = v_sync_bp + CVT_MIN_V_PORCH_RND;
230
231 total_h_pixel = active_h_pixel + h_blank;
232
233 h_sync = (total_h_pixel * CVT_HSYNC_PERCENT) / 100;
234 h_sync -= h_sync % CVT_CELL_GRAN;
235
236 h_bp = h_blank / 2;
237 h_fp = h_blank - h_bp - h_sync;
238
239 pixel_clock = (static_cast<long long>(total_h_pixel) * HV_FACTOR * 1000000)
240 / h_period;
241 pixel_clock -= pixel_clock % clk_gran;
242 } else {
243 /* Reduced blanking */
244
245 int vbi_lines;
246 int tmp1, tmp2;
247 int min_vbi_lines;
248
249 /* estimate horizontal period. */
250 tmp1 = HV_FACTOR * 1000000 -
251 CVT_RB_MIN_V_BLANK * HV_FACTOR * v_refresh;
252 tmp2 = active_v_lines;
253
254 h_period = tmp1 / (tmp2 * v_refresh);
255
256 vbi_lines = CVT_RB_MIN_V_BLANK * HV_FACTOR / h_period + 1;
257
258 if (rb_v2)
259 min_vbi_lines = CVT_RB_V2_MIN_V_FPORCH + v_sync + CVT_RB_V_BPORCH;
260 else
261 min_vbi_lines = CVT_RB_V_FPORCH + v_sync + CVT_MIN_V_BPORCH;
262
263 if (vbi_lines < min_vbi_lines)
264 vbi_lines = min_vbi_lines;
265
266 h_blank = rb_v2 ? CVT_RB_V2_H_BLANK : CVT_RB_H_BLANK;
267 v_blank = vbi_lines;
268
269 total_h_pixel = active_h_pixel + h_blank;
270 total_v_lines = active_v_lines + v_blank;
271
272 h_sync = CVT_RB_H_SYNC;
273
274 h_bp = h_blank / 2;
275 h_fp = h_blank - h_bp - h_sync;
276
277 if (rb_v2) {
278 v_bp = CVT_RB_V_BPORCH;
279 v_fp = v_blank - v_bp - v_sync;
280 } else {
281 v_fp = CVT_RB_V_FPORCH;
282 v_bp = v_blank - v_fp - v_sync;
283 }
284
285 pixel_clock = v_refresh * total_h_pixel *
286 (2 * total_v_lines + interlace) / 2;
287 pixel_clock -= pixel_clock % clk_gran;
288 }
289
290 cvt->standards = V4L2_DV_BT_STD_CVT;
291
292 cvt->width = h_pixel;
293 cvt->hfrontporch = h_fp;
294 cvt->hsync = h_sync;
295 cvt->hbackporch = h_bp;
296
297 cvt->height = v_lines;
298 cvt->vfrontporch = v_fp;
299 cvt->vsync = v_sync;
300 cvt->vbackporch = v_bp;
301
302 cvt->pixelclock = pixel_clock;
303 cvt->interlaced = interlaced == 1 ?
304 V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
305
306 if (cvt->interlaced == V4L2_DV_INTERLACED) {
307 cvt->il_vfrontporch = v_fp;
308 cvt->il_vsync = v_sync;
309 cvt->il_vbackporch = v_bp;
310 /* Add 1 to vbackporch of even field and set the half line
311 * flag (V4L2_DV_FL_HALF_LINE)
312 * For interlaced format, the half line flag indicates to the
313 * driver to add a half-line to the vfrontporch of the odd
314 * field and subtract a half-line from the vbackporch of the
315 * even field */
316 cvt->flags |= V4L2_DV_FL_HALF_LINE;
317 cvt->il_vbackporch += 1;
318 }
319 if (use_rb) {
320 cvt->polarities = V4L2_DV_HSYNC_POS_POL;
321 cvt->flags |= V4L2_DV_FL_REDUCED_BLANKING;
322 } else {
323 cvt->polarities = V4L2_DV_VSYNC_POS_POL;
324 }
325 if (rb_v2 && reduced_fps && v_refresh % 6 == 0)
326 cvt->flags |= V4L2_DV_FL_REDUCED_FPS;
327
328 return true;
329 }
330
331
332 /*
333 * GTF defines Based on Generalized Timing Formula Standard
334 * Version 1.1 September 2, 1999
335 */
336
337 #define GTF_MARGIN_PERCENT (18)
338 #define GTF_HSYNC_PERCENT (8)
339
340 #define GTF_PXL_CLK_GRAN (250000) /* pixel clock granularity */
341
342 #define GTF_V_SYNC_RQD (3) /* v sync required (lines) */
343 #define GTF_MIN_VSYNC_BP (550) /* min time vsync + back porch (us) */
344 #define GTF_MIN_PORCH (1) /* vertical front porch (lines) */
345 #define GTF_CELL_GRAN (8) /* character cell granularity */
346
347 /* Default */
348 #define GTF_D_M (600) /* blanking formula gradient */
349 #define GTF_D_C (40) /* blanking formula offset */
350 #define GTF_D_K (128) /* blanking formula scaling factor */
351 #define GTF_D_J (20) /* blanking formula scaling factor */
352 #define GTF_D_C_PRIME ((((GTF_D_C - GTF_D_J) * GTF_D_K) / 256) + GTF_D_J)
353 #define GTF_D_M_PRIME ((GTF_D_K * GTF_D_M) / 256)
354
355 /* Secondary */
356 #define GTF_S_M (3600) /* blanking formula gradient */
357 #define GTF_S_C (40) /* blanking formula offset */
358 #define GTF_S_K (128) /* blanking formula scaling factor */
359 #define GTF_S_J (35) /* blanking formula scaling factor */
360 #define GTF_S_C_PRIME ((((GTF_S_C - GTF_S_J) * GTF_S_K) / 256) + GTF_S_J)
361 #define GTF_S_M_PRIME ((GTF_S_K * GTF_S_M) / 256)
362
363 /**
364 * calc_gtf_modeline - calculate modeline based on GTF algorithm
365 *
366 * This function is called to generate the timings according to GTF
367 * algorithm. Timing calculation is based on VESA(TM) Generalized
368 * Timing Formula Standard Version 1.1 September 2, 1999
369 * which can be downloaded from -
370 * http://www.vesa.org/vesa-standards/free-standards/
371 *
372 * Input Parameters:
373 * @image_width
374 * @image_height
375 * @refresh_rate
376 * @reduced_blanking: This value, if greater than 0, indicates that
377 * reduced blanking is to be used.
378 * @interlaced: whether to compute an interlaced mode
379 * @gtf: stores results of gtf timing calculation
380 *
381 * Returns:
382 * true, if gtf timings are calculated and filled in gtf modeline.
383 * false, for any error.
384 */
385
calc_gtf_modeline(int image_width,int image_height,int refresh_rate,bool reduced_blanking,bool interlaced,struct v4l2_bt_timings * gtf)386 bool calc_gtf_modeline(int image_width, int image_height,
387 int refresh_rate, bool reduced_blanking,
388 bool interlaced, struct v4l2_bt_timings *gtf)
389 {
390 int h_sync;
391 int v_sync;
392 int h_fp;
393 int h_bp;
394 int v_fp;
395 int v_bp;
396
397 int h_pixel;
398 int v_lines;
399 int h_pixel_rnd;
400 int v_lines_rnd;
401 int active_h_pixel;
402 int active_v_lines;
403 int total_h_pixel;
404 int total_v_lines;
405
406 int h_blank;
407 int v_blank;
408
409 int h_period;
410 int h_period_est;
411
412 int interlace;
413 int v_refresh;
414 int v_refresh_est;
415 int pixel_clock;
416
417 int v_sync_bp;
418 int tmp1, tmp2;
419 int ideal_blank_duty_cycle;
420
421 if (!gtf) {
422 fprintf(stderr, "Null pointer to gtf modeline structure\n");
423 return false;
424 }
425
426 if (!valid_params(image_width, image_height, refresh_rate))
427 return false;
428
429 h_pixel = image_width;
430 v_lines = image_height;
431
432 if (!refresh_rate)
433 v_refresh = 60;
434 else
435 v_refresh = refresh_rate;
436
437 if (interlaced) {
438 interlace = 1;
439 v_lines_rnd = (v_lines + 1) / 2;
440 v_refresh = v_refresh * 2;
441 } else {
442 interlace = 0;
443 v_lines_rnd = v_lines;
444 }
445
446 h_pixel_rnd = (h_pixel + GTF_CELL_GRAN / 2);
447 h_pixel_rnd -= h_pixel_rnd % GTF_CELL_GRAN;
448
449 active_h_pixel = h_pixel_rnd;
450 active_v_lines = v_lines_rnd;
451
452 /* estimate the horizontal period */
453 tmp1 = HV_FACTOR * 1000000 -
454 GTF_MIN_VSYNC_BP * HV_FACTOR * v_refresh;
455 tmp2 = 2 * (active_v_lines + GTF_MIN_PORCH) + interlace;
456
457 h_period_est = 2 * tmp1 / (tmp2 * v_refresh);
458
459 v_sync_bp = GTF_MIN_VSYNC_BP * HV_FACTOR * 100 / h_period_est;
460 v_sync_bp = (v_sync_bp + 50) / 100;
461
462 v_sync = GTF_V_SYNC_RQD;
463 v_bp = v_sync_bp - v_sync;
464 v_fp = GTF_MIN_PORCH;
465
466 v_blank = v_sync + v_bp + v_fp;
467 total_v_lines = active_v_lines + v_blank;
468
469 v_refresh_est = (2 * HV_FACTOR * static_cast<long long>(1000000)) /
470 (h_period_est * (2 * total_v_lines + interlace) / HV_FACTOR);
471
472 h_period = (static_cast<long long>(h_period_est) * v_refresh_est) /
473 (v_refresh * HV_FACTOR);
474
475 if (!reduced_blanking)
476 ideal_blank_duty_cycle = (GTF_D_C_PRIME * HV_FACTOR) -
477 GTF_D_M_PRIME * h_period / 1000;
478 else
479 ideal_blank_duty_cycle = (GTF_S_C_PRIME * HV_FACTOR) -
480 GTF_S_M_PRIME * h_period / 1000;
481
482 h_blank = active_h_pixel * static_cast<long long>(ideal_blank_duty_cycle) /
483 (100 * HV_FACTOR - ideal_blank_duty_cycle);
484 h_blank = ((h_blank + GTF_CELL_GRAN) / (2 * GTF_CELL_GRAN))
485 * (2 * GTF_CELL_GRAN);
486 total_h_pixel = active_h_pixel + h_blank;
487
488 h_sync = (total_h_pixel * GTF_HSYNC_PERCENT) / 100;
489 h_sync = ((h_sync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN) * GTF_CELL_GRAN;
490
491 h_fp = h_blank / 2 - h_sync;
492 h_bp = h_fp + h_sync;
493
494 pixel_clock = (static_cast<long long>(total_h_pixel) * HV_FACTOR * 1000000)
495 / h_period;
496 /* Not sure if clock value needs to be truncated to multiple
497 * of 25000. The formula given in standard does not indicate
498 * truncation
499 * */
500 /*pixel_clock -= pixel_clock % GTF_PXL_CLK_GRAN;*/
501 gtf->standards = V4L2_DV_BT_STD_GTF;
502
503 gtf->width = h_pixel;
504 gtf->hfrontporch = h_fp;
505 gtf->hsync = h_sync;
506 gtf->hbackporch = h_bp;
507
508 gtf->height = v_lines;
509 gtf->vfrontporch = v_fp;
510 gtf->vsync = v_sync;
511 gtf->vbackporch = v_bp;
512
513 gtf->pixelclock = pixel_clock;
514 gtf->interlaced = interlaced == 1 ?
515 V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
516
517 if (gtf->interlaced == V4L2_DV_INTERLACED) {
518 gtf->il_vfrontporch = v_fp;
519 gtf->il_vsync = v_sync;
520 gtf->il_vbackporch = v_bp;
521 /* Add 1 to vbackporch of even field and set the half line
522 * flag (V4L2_DV_FL_HALF_LINE)
523 * For interlaced format, the half line flag indicates to the
524 * driver to add a half-line to the vfrontporch of the odd
525 * field and subtract a half-line from the vbackporch of the
526 * even field */
527 gtf->flags |= V4L2_DV_FL_HALF_LINE;
528 gtf->il_vbackporch += 1;
529 }
530 if (reduced_blanking) {
531 gtf->polarities = V4L2_DV_HSYNC_POS_POL;
532 gtf->flags |= V4L2_DV_FL_REDUCED_BLANKING;
533 } else
534 gtf->polarities = V4L2_DV_VSYNC_POS_POL;
535
536 return true;
537 }
538