• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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