• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006-2012 Red Hat, Inc.
3  * Copyright 2018-2021 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
4  *
5  * Originally imported from edid-decode.
6  */
7 
8 #include <math.h>
9 
10 #include <libdisplay-info/cvt.h>
11 
12 /**
13  * The size of the top and bottom overscan margin as a percentage of the active
14  * vertical image.
15  */
16 #define MARGIN_PERC 1.8
17 #define MIN_VSYNC_BP 550.0
18 #define MIN_V_PORCH 3
19 /**
20  * Minimum vertical backporch for CVT and CVT RBv1.
21  */
22 #define MIN_V_BPORCH 7
23 /**
24  * Fixed vertical backporch for CVT RBv2 and RBv3.
25  */
26 #define FIXED_V_BPORCH 6
27 #define C_PRIME 30.0
28 #define M_PRIME 300.0
29 /**
30  * Minimum VBlank period (in µs) for RB timings.
31  */
32 #define RB_MIN_VBLANK 460.0
33 
34 void
di_cvt_compute(struct di_cvt_timing * t,const struct di_cvt_options * options)35 di_cvt_compute(struct di_cvt_timing *t, const struct di_cvt_options *options)
36 {
37 	enum di_cvt_reduced_blanking_version rb = options->red_blank_ver;
38 	double cell_gran, h_pixels_rnd, v_lines_rnd, hor_margin, vert_margin,
39 	       interlace, total_active_pixels, v_field_rate_rqd, clock_step,
40 	       h_blank, rb_v_fporch, refresh_multiplier, rb_min_vblank, h_sync,
41 	       v_sync, pixel_freq, v_blank, v_sync_bp, additional_hblank,
42 	       h_period_est, ideal_duty_cycle, total_pixels, vbi_lines,
43 	       rb_v_bporch, rb_min_vbi, total_v_lines, freq, h_front_porch,
44 	       v_back_porch, act_h_freq;
45 
46 	cell_gran = rb == DI_CVT_REDUCED_BLANKING_V2 ? 1 : 8;
47 	h_pixels_rnd = floor(options->h_pixels / cell_gran) * cell_gran;
48 	v_lines_rnd = options->int_rqd ? floor(options->v_lines / 2.0) : options->v_lines;
49 	hor_margin = options->margins_rqd
50 		     ? floor((h_pixels_rnd * MARGIN_PERC / 100.0) / cell_gran) * cell_gran
51 		     : 0;
52 	vert_margin = options->margins_rqd
53 		      ? floor(MARGIN_PERC / 100.0 * v_lines_rnd)
54 		      : 0;
55 	interlace = options->int_rqd ? 0.5 : 0;
56 	total_active_pixels = h_pixels_rnd + hor_margin * 2;
57 	v_field_rate_rqd = options->int_rqd
58 			   ? options->ip_freq_rqd * 2
59 			   : options->ip_freq_rqd;
60 	clock_step = rb >= DI_CVT_REDUCED_BLANKING_V2 ? 0.001 : 0.25;
61 	h_blank = rb == DI_CVT_REDUCED_BLANKING_V1 ? 160 : 80;
62 	rb_v_fporch = rb == DI_CVT_REDUCED_BLANKING_V1 ? 3 : 1;
63 	refresh_multiplier = (rb == DI_CVT_REDUCED_BLANKING_V2 && options->video_opt) ? 1000.0 / 1001.0 : 1;
64 	rb_min_vblank = rb == DI_CVT_REDUCED_BLANKING_V3 ? options->vblank : RB_MIN_VBLANK;
65 	if (rb_min_vblank < RB_MIN_VBLANK)
66 		rb_min_vblank = RB_MIN_VBLANK;
67 	h_sync = 32;
68 
69 	if (rb == DI_CVT_REDUCED_BLANKING_V3) {
70 		additional_hblank = options->additional_hblank;
71 		if (additional_hblank < 0)
72 			additional_hblank = 0;
73 		else if (additional_hblank > 120)
74 			additional_hblank = 120;
75 		h_blank += additional_hblank;
76 	}
77 
78 	/* Determine VSync Width from aspect ratio */
79 	if ((options->v_lines * 4 / 3) == options->h_pixels)
80 		v_sync = 4;
81 	else if ((options->v_lines * 16 / 9) == options->h_pixels)
82 		v_sync = 5;
83 	else if ((options->v_lines * 16 / 10) == options->h_pixels)
84 		v_sync = 6;
85 	else if (!(options->v_lines % 4) && ((options->v_lines * 5 / 4) == options->h_pixels))
86 		v_sync = 7;
87 	else if ((options->v_lines * 15 / 9) == options->h_pixels)
88 		v_sync = 7;
89 	else /* Custom */
90 		v_sync = 10;
91 
92 	if (rb >= DI_CVT_REDUCED_BLANKING_V2)
93 		v_sync = 8;
94 
95 	if (rb == DI_CVT_REDUCED_BLANKING_NONE) {
96 		h_period_est = (1.0 / v_field_rate_rqd - MIN_VSYNC_BP / 1000000.0) /
97 			(v_lines_rnd + vert_margin * 2 + MIN_V_PORCH + interlace) * 1000000.0;
98 		v_sync_bp = floor(MIN_VSYNC_BP / h_period_est) + 1;
99 		if (v_sync_bp < v_sync + MIN_V_BPORCH)
100 			v_sync_bp = v_sync + MIN_V_BPORCH;
101 		v_blank = v_sync_bp + MIN_V_PORCH;
102 		total_v_lines = v_lines_rnd + vert_margin * 2 + v_sync_bp +
103 				interlace + MIN_V_PORCH;
104 		ideal_duty_cycle = C_PRIME - M_PRIME * h_period_est / 1000.0;
105 		if (ideal_duty_cycle < 20)
106 			ideal_duty_cycle = 20;
107 		h_blank = floor(total_active_pixels * ideal_duty_cycle /
108 				(100.0 - ideal_duty_cycle) /
109 				(2 * cell_gran)) * 2 * cell_gran;
110 		total_pixels = total_active_pixels + h_blank;
111 		h_sync = floor(total_pixels * 0.08 / cell_gran) * cell_gran;
112 		pixel_freq = floor(total_pixels / h_period_est / clock_step) * clock_step;
113 	} else {
114 		h_period_est = (1000000.0 / v_field_rate_rqd - rb_min_vblank) /
115 					(v_lines_rnd + vert_margin * 2);
116 		vbi_lines = floor(rb_min_vblank / h_period_est) + 1;
117 		rb_v_bporch = rb == DI_CVT_REDUCED_BLANKING_V1 ? MIN_V_BPORCH : FIXED_V_BPORCH;
118 		rb_min_vbi = rb_v_fporch + v_sync + rb_v_bporch;
119 		v_blank = vbi_lines < rb_min_vbi ? rb_min_vbi : vbi_lines;
120 		total_v_lines = v_blank + v_lines_rnd + vert_margin * 2 + interlace;
121 		if (rb == DI_CVT_REDUCED_BLANKING_V3 && options->early_vsync_rqd)
122 			rb_v_bporch = floor(vbi_lines / 2.0);
123 		if (rb == DI_CVT_REDUCED_BLANKING_V1)
124 			v_sync_bp = v_blank - rb_v_fporch;
125 		else
126 			v_sync_bp = v_sync + rb_v_bporch;
127 		total_pixels = h_blank + total_active_pixels;
128 		freq = v_field_rate_rqd * total_v_lines * total_pixels * refresh_multiplier;
129 		if (rb == DI_CVT_REDUCED_BLANKING_V3)
130 			pixel_freq = ceil(freq / 1000000.0 / clock_step) * clock_step;
131 		else
132 			pixel_freq = floor(freq / 1000000.0 / clock_step) * clock_step;
133 	}
134 
135 	if (rb >= DI_CVT_REDUCED_BLANKING_V2)
136 		h_front_porch = 8;
137 	else
138 		h_front_porch = (h_blank / 2.0) - h_sync;
139 
140 	v_back_porch = v_sync_bp - v_sync;
141 	act_h_freq = 1000 * pixel_freq / total_pixels;
142 
143 	*t = (struct di_cvt_timing){
144 		.act_pixel_freq = pixel_freq,
145 		.total_active_pixels = total_active_pixels,
146 		.v_lines_rnd = v_lines_rnd,
147 		.h_front_porch = h_front_porch,
148 		.h_sync = h_sync,
149 		.h_back_porch = h_blank - h_front_porch - h_sync,
150 		.v_front_porch = v_blank - v_back_porch - v_sync,
151 		.v_back_porch = v_back_porch,
152 		.v_sync = v_sync,
153 		.act_frame_rate = 1000 * act_h_freq / total_v_lines,
154 	};
155 }
156