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