xref: /aosp_15_r20/external/libkmsxx/kms++/src/mode_cvt.cpp (revision f0687c8a10b3e371dbe09214db6664e37c283cca)
1*f0687c8aSRaman Tenneti // Supports CVT 1.2 reduced blanking modes v1 and v2
2*f0687c8aSRaman Tenneti 
3*f0687c8aSRaman Tenneti #include <kms++/kms++.h>
4*f0687c8aSRaman Tenneti #include <cmath>
5*f0687c8aSRaman Tenneti 
6*f0687c8aSRaman Tenneti using namespace std;
7*f0687c8aSRaman Tenneti 
8*f0687c8aSRaman Tenneti namespace kms
9*f0687c8aSRaman Tenneti {
10*f0687c8aSRaman Tenneti static float CELL_GRAN = 8;
11*f0687c8aSRaman Tenneti static float CELL_GRAN_RND = round(CELL_GRAN);
12*f0687c8aSRaman Tenneti 
13*f0687c8aSRaman Tenneti struct CVTConsts {
14*f0687c8aSRaman Tenneti 	float CLOCK_STEP;
15*f0687c8aSRaman Tenneti 	float MIN_V_BPORCH;
16*f0687c8aSRaman Tenneti 	float RB_H_BLANK;
17*f0687c8aSRaman Tenneti 	float RB_H_FPORCH;
18*f0687c8aSRaman Tenneti 	float RB_H_SYNC;
19*f0687c8aSRaman Tenneti 	float RB_H_BPORCH;
20*f0687c8aSRaman Tenneti 	float RB_MIN_V_BLANK;
21*f0687c8aSRaman Tenneti 	float RB_V_FPORCH;
22*f0687c8aSRaman Tenneti 	float REFRESH_MULTIPLIER;
23*f0687c8aSRaman Tenneti };
24*f0687c8aSRaman Tenneti 
25*f0687c8aSRaman Tenneti static const CVTConsts cvt_consts_v1 = {
26*f0687c8aSRaman Tenneti 	.CLOCK_STEP = 0.25, // Fixed
27*f0687c8aSRaman Tenneti 	.MIN_V_BPORCH = 6, // Min
28*f0687c8aSRaman Tenneti 	.RB_H_BLANK = 160, // Fixed
29*f0687c8aSRaman Tenneti 	.RB_H_FPORCH = 48, // Fixed
30*f0687c8aSRaman Tenneti 	.RB_H_SYNC = 32, // Fixed
31*f0687c8aSRaman Tenneti 	.RB_H_BPORCH = 80, // Fixed
32*f0687c8aSRaman Tenneti 	.RB_MIN_V_BLANK = 460, // Min
33*f0687c8aSRaman Tenneti 	.RB_V_FPORCH = 3, // Fixed
34*f0687c8aSRaman Tenneti 	.REFRESH_MULTIPLIER = 1, // Fixed
35*f0687c8aSRaman Tenneti };
36*f0687c8aSRaman Tenneti 
37*f0687c8aSRaman Tenneti static const CVTConsts cvt_consts_v2 = {
38*f0687c8aSRaman Tenneti 	.CLOCK_STEP = 0.001, // Fixed
39*f0687c8aSRaman Tenneti 	.MIN_V_BPORCH = 6, // Fixed
40*f0687c8aSRaman Tenneti 	.RB_H_BLANK = 80, // Fixed
41*f0687c8aSRaman Tenneti 	.RB_H_FPORCH = 8, // Fixed
42*f0687c8aSRaman Tenneti 	.RB_H_SYNC = 32, // Fixed
43*f0687c8aSRaman Tenneti 	.RB_H_BPORCH = 40, // Fixed
44*f0687c8aSRaman Tenneti 	.RB_MIN_V_BLANK = 460, // Min
45*f0687c8aSRaman Tenneti 	.RB_V_FPORCH = 1, // Min
46*f0687c8aSRaman Tenneti 	.REFRESH_MULTIPLIER = 1, // or 1000/1001
47*f0687c8aSRaman Tenneti };
48*f0687c8aSRaman Tenneti 
videomode_from_cvt(uint32_t hact,uint32_t vact,uint32_t refresh,bool ilace,bool reduced_v2,bool video_optimized)49*f0687c8aSRaman Tenneti Videomode videomode_from_cvt(uint32_t hact, uint32_t vact, uint32_t refresh, bool ilace, bool reduced_v2, bool video_optimized)
50*f0687c8aSRaman Tenneti {
51*f0687c8aSRaman Tenneti 	CVTConsts c = reduced_v2 ? cvt_consts_v2 : cvt_consts_v1;
52*f0687c8aSRaman Tenneti 
53*f0687c8aSRaman Tenneti 	if (video_optimized)
54*f0687c8aSRaman Tenneti 		c.REFRESH_MULTIPLIER = 1000.0 / 1001.0;
55*f0687c8aSRaman Tenneti 
56*f0687c8aSRaman Tenneti 	bool INT_RQD = ilace;
57*f0687c8aSRaman Tenneti 
58*f0687c8aSRaman Tenneti 	float H_PIXELS = hact;
59*f0687c8aSRaman Tenneti 	float V_LINES = vact;
60*f0687c8aSRaman Tenneti 	float IP_FREQ_RQD = refresh ? refresh : 60;
61*f0687c8aSRaman Tenneti 	if (ilace)
62*f0687c8aSRaman Tenneti 		IP_FREQ_RQD /= 2;
63*f0687c8aSRaman Tenneti 
64*f0687c8aSRaman Tenneti 	float V_SYNC_RND;
65*f0687c8aSRaman Tenneti 
66*f0687c8aSRaman Tenneti 	if (reduced_v2) {
67*f0687c8aSRaman Tenneti 		V_SYNC_RND = 8;
68*f0687c8aSRaman Tenneti 	} else {
69*f0687c8aSRaman Tenneti 		if (hact * 3 == vact * 4)
70*f0687c8aSRaman Tenneti 			V_SYNC_RND = 4;
71*f0687c8aSRaman Tenneti 		else if (hact * 9 == vact * 16)
72*f0687c8aSRaman Tenneti 			V_SYNC_RND = 5;
73*f0687c8aSRaman Tenneti 		else if (hact * 10 == vact * 16)
74*f0687c8aSRaman Tenneti 			V_SYNC_RND = 6;
75*f0687c8aSRaman Tenneti 		else if (hact == 1280 && (vact == 1024 || vact == 768))
76*f0687c8aSRaman Tenneti 			V_SYNC_RND = 7;
77*f0687c8aSRaman Tenneti 		else
78*f0687c8aSRaman Tenneti 			V_SYNC_RND = 10;
79*f0687c8aSRaman Tenneti 	}
80*f0687c8aSRaman Tenneti 
81*f0687c8aSRaman Tenneti 	// 5.2.1
82*f0687c8aSRaman Tenneti 	float V_FIELD_RATE_RQD = INT_RQD ? IP_FREQ_RQD * 2 : IP_FREQ_RQD;
83*f0687c8aSRaman Tenneti 
84*f0687c8aSRaman Tenneti 	// 5.2.2
85*f0687c8aSRaman Tenneti 	float H_PIXELS_RND = floor(H_PIXELS / CELL_GRAN_RND) * CELL_GRAN_RND;
86*f0687c8aSRaman Tenneti 
87*f0687c8aSRaman Tenneti 	// 5.2.3
88*f0687c8aSRaman Tenneti 	float LEFT_MARGIN = 0;
89*f0687c8aSRaman Tenneti 	float RIGHT_MARGIN = 0;
90*f0687c8aSRaman Tenneti 
91*f0687c8aSRaman Tenneti 	// 5.2.4
92*f0687c8aSRaman Tenneti 	float TOTAL_ACTIVE_PIXELS = H_PIXELS_RND + LEFT_MARGIN + RIGHT_MARGIN;
93*f0687c8aSRaman Tenneti 
94*f0687c8aSRaman Tenneti 	// 5.2.5
95*f0687c8aSRaman Tenneti 	float V_LINES_RND = INT_RQD ? floor(V_LINES / 2) : floor(V_LINES);
96*f0687c8aSRaman Tenneti 
97*f0687c8aSRaman Tenneti 	// 5.2.6
98*f0687c8aSRaman Tenneti 	float TOP_MARGIN = 0;
99*f0687c8aSRaman Tenneti 	float BOT_MARGIN = 0;
100*f0687c8aSRaman Tenneti 
101*f0687c8aSRaman Tenneti 	// 5.2.7
102*f0687c8aSRaman Tenneti 	float INTERLACE = INT_RQD ? 0.5 : 0;
103*f0687c8aSRaman Tenneti 
104*f0687c8aSRaman Tenneti 	// 5.4.8
105*f0687c8aSRaman Tenneti 	float H_PERIOD_EST = ((1000000 / V_FIELD_RATE_RQD) - c.RB_MIN_V_BLANK) / (V_LINES_RND + TOP_MARGIN + BOT_MARGIN);
106*f0687c8aSRaman Tenneti 
107*f0687c8aSRaman Tenneti 	// 5.4.9
108*f0687c8aSRaman Tenneti 	float VBI_LINES = floor(c.RB_MIN_V_BLANK / H_PERIOD_EST) + 1;
109*f0687c8aSRaman Tenneti 
110*f0687c8aSRaman Tenneti 	// 5.4.10
111*f0687c8aSRaman Tenneti 	float RB_MIN_VBI = c.RB_V_FPORCH + V_SYNC_RND + c.MIN_V_BPORCH;
112*f0687c8aSRaman Tenneti 	float ACT_VBI_LINES = VBI_LINES < RB_MIN_VBI ? RB_MIN_VBI : VBI_LINES;
113*f0687c8aSRaman Tenneti 
114*f0687c8aSRaman Tenneti 	// 5.4.11
115*f0687c8aSRaman Tenneti 	float TOTAL_V_LINES = ACT_VBI_LINES + V_LINES_RND + TOP_MARGIN + BOT_MARGIN + INTERLACE;
116*f0687c8aSRaman Tenneti 
117*f0687c8aSRaman Tenneti 	// 5.4.12
118*f0687c8aSRaman Tenneti 	float TOTAL_PIXELS = c.RB_H_BLANK + TOTAL_ACTIVE_PIXELS;
119*f0687c8aSRaman Tenneti 
120*f0687c8aSRaman Tenneti 	// 5.4.13
121*f0687c8aSRaman Tenneti 	float ACT_PIXEL_FREQ = c.CLOCK_STEP * floor((V_FIELD_RATE_RQD * TOTAL_V_LINES * TOTAL_PIXELS / 1000000 * c.REFRESH_MULTIPLIER) / c.CLOCK_STEP);
122*f0687c8aSRaman Tenneti 
123*f0687c8aSRaman Tenneti 	// 5.4.14
124*f0687c8aSRaman Tenneti 	//float ACT_H_FREQ = 1000 * ACT_PIXEL_FREQ / TOTAL_PIXELS;
125*f0687c8aSRaman Tenneti 
126*f0687c8aSRaman Tenneti 	// 5.4.15
127*f0687c8aSRaman Tenneti 	//float ACT_FIELD_RATE = 1000 * ACT_H_FREQ / TOTAL_V_LINES;
128*f0687c8aSRaman Tenneti 
129*f0687c8aSRaman Tenneti 	// 5.4.16
130*f0687c8aSRaman Tenneti 	//float ACT_FRAME_RATE = INT_RQD ? ACT_FIELD_RATE / 2 : ACT_FIELD_RATE;
131*f0687c8aSRaman Tenneti 
132*f0687c8aSRaman Tenneti 	// 3.4.3.7 Adjust vfp
133*f0687c8aSRaman Tenneti 	if (reduced_v2)
134*f0687c8aSRaman Tenneti 		c.RB_V_FPORCH = ACT_VBI_LINES - V_SYNC_RND - c.MIN_V_BPORCH;
135*f0687c8aSRaman Tenneti 
136*f0687c8aSRaman Tenneti 	Videomode mode;
137*f0687c8aSRaman Tenneti 
138*f0687c8aSRaman Tenneti 	mode = videomode_from_timings(ACT_PIXEL_FREQ * 1000,
139*f0687c8aSRaman Tenneti 				      H_PIXELS_RND, c.RB_H_FPORCH, c.RB_H_SYNC, c.RB_H_BPORCH,
140*f0687c8aSRaman Tenneti 				      V_LINES_RND * (INT_RQD ? 2 : 1), c.RB_V_FPORCH, V_SYNC_RND, ACT_VBI_LINES - V_SYNC_RND - c.RB_V_FPORCH);
141*f0687c8aSRaman Tenneti 
142*f0687c8aSRaman Tenneti 	mode.set_hsync(SyncPolarity::Positive);
143*f0687c8aSRaman Tenneti 	mode.set_vsync(SyncPolarity::Negative);
144*f0687c8aSRaman Tenneti 
145*f0687c8aSRaman Tenneti 	mode.set_interlace(INT_RQD);
146*f0687c8aSRaman Tenneti 
147*f0687c8aSRaman Tenneti 	return mode;
148*f0687c8aSRaman Tenneti }
149*f0687c8aSRaman Tenneti 
150*f0687c8aSRaman Tenneti } // namespace kms
151