edid-decode: downgrade missing display product name to warning
[edid-decode.git] / calc-ovt.cpp
blob47113d39a7441acd80bcab8ecdb09f2a84c34a4b
1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright 2021 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5 * Author: Hans Verkuil <hverkuil-cisco@xs4all.nl>
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <math.h>
11 #include <time.h>
12 #include <numeric>
14 #include "edid-decode.h"
16 #define MinVblankDuration 460
17 #define MinVsyncLeadingEdge 400
18 #define MinClockRate420 590000000
19 #define PixelFactor420 2
20 #define MinHblank444 80
21 #define MinHblank420 128
22 #define PixelClockGranularity 1000
23 #define MinHtotalGranularity 8
24 #define MaxChunkRate 650000000
25 #define AudioPacketRate 195000
26 #define AudioPacketSize 32
27 #define LineOverhead 32
29 static unsigned roundup_to_power_of_two(unsigned v)
31 unsigned shift = 1;
32 unsigned mask = 0;
34 if (!v || v > 0x80000000) {
35 fprintf(stderr, "roundup_to_power_of_two: invalid input %u.\n", v);
36 exit(1);
39 v--;
40 do {
41 mask = v >> shift;
42 v |= mask;
43 shift <<= 1;
44 } while (mask);
45 return v + 1;
48 static unsigned greatest_power_of_two_divider(unsigned x)
50 return x & ~(x - 1);
53 timings edid_state::calc_ovt_mode(unsigned Hactive, unsigned Vactive,
54 unsigned Hratio, unsigned Vratio,
55 unsigned Vrate)
57 timings t = {};
59 t.hact = Hactive;
60 t.vact = Vactive;
61 t.hratio = Hratio;
62 t.vratio = Vratio;
64 unsigned MaxVrate = Vrate;
65 unsigned VtotalGranularity = 1;
67 // Step 1
68 switch (Vrate) {
69 case 24: case 25: case 30:
70 MaxVrate = 30;
71 VtotalGranularity = 20;
72 break;
73 case 48: case 50: case 60:
74 MaxVrate = 60;
75 VtotalGranularity = 20;
76 break;
77 case 100: case 120:
78 MaxVrate = 120;
79 VtotalGranularity = 5;
80 break;
81 case 200: case 240:
82 MaxVrate = 240;
83 VtotalGranularity = 5;
84 break;
85 case 300: case 360:
86 MaxVrate = 360;
87 VtotalGranularity = 5;
88 break;
89 case 400: case 480:
90 MaxVrate = 480;
91 VtotalGranularity = 5;
92 break;
95 // Step 2
96 double MaxActiveTime = (1000000.0 / MaxVrate) - MinVblankDuration;
97 double MinLineTime = MaxActiveTime / Vactive;
98 unsigned MinVblank = ceil(MinVblankDuration / MinLineTime);
99 unsigned MinVtotal = Vactive + MinVblank;
101 if (MinVtotal % VtotalGranularity)
102 MinVtotal += VtotalGranularity - (MinVtotal % VtotalGranularity);
104 // Step 3
105 unsigned MinLineRate = MaxVrate * MinVtotal;
106 unsigned MaxAudioPacketsPerLine = ceil((double)AudioPacketRate / MinLineRate);
108 // Step 4
109 unsigned MinHtotal = Hactive +
110 max(MinHblank444, LineOverhead + AudioPacketSize * MaxAudioPacketsPerLine);
111 double MinPixelClockRate = (double)MaxVrate * MinHtotal * MinVtotal;
112 double HCalcGranularity = roundup_to_power_of_two(ceil(MinPixelClockRate / MaxChunkRate));
113 unsigned HtotalGranularity = max(MinHtotalGranularity, HCalcGranularity);
115 if (MinHtotal % HtotalGranularity)
116 MinHtotal += HtotalGranularity - (MinHtotal % HtotalGranularity);
118 unsigned ResolutionGranularity = PixelClockGranularity /
119 gcd(PixelClockGranularity, MaxVrate);
120 unsigned Htotal = 0;
121 unsigned Vtotal = 0;
122 unsigned long long PixelClockRate = 0;
124 for (;;) {
125 // Step 5
126 unsigned long long RMin = 0;
127 unsigned V = MinVtotal;
129 for (;;) {
130 unsigned H = MinHtotal;
131 unsigned long long R = H * V;
132 if (RMin && R > RMin)
133 break;
134 while (R % ResolutionGranularity ||
135 MaxVrate * R / greatest_power_of_two_divider(H) > MaxChunkRate) {
136 H += HtotalGranularity;
137 R = H * V;
139 if (!RMin || R < RMin) {
140 Htotal = H;
141 Vtotal = V;
142 RMin = R;
144 V += VtotalGranularity;
146 PixelClockRate = MaxVrate * RMin;
148 // Step 6
149 MinHtotal = Hactive + max(MinHblank420, PixelFactor420 *
150 (LineOverhead + AudioPacketSize * MaxAudioPacketsPerLine));
151 if (PixelClockRate >= MinClockRate420 &&
152 Htotal < MinHtotal)
153 continue;
154 break;
157 // Step 7
158 Vtotal = Vtotal * MaxVrate / Vrate;
160 // Step 8
161 unsigned Vblank = Vtotal - Vactive;
162 unsigned VsyncPosition = ceil((double)MinVsyncLeadingEdge * PixelClockRate / (1000000.0 * Htotal));
163 t.vfp = Vblank - VsyncPosition;
165 t.vsync = 8;
166 t.vbp = Vblank - t.vfp - t.vsync;
167 t.pos_pol_vsync = true;
168 unsigned Hblank = Htotal - Hactive;
169 t.hsync = 32;
170 t.hbp = 32;
171 t.hfp = Hblank - t.hsync - t.hbp;
172 t.pos_pol_hsync = true;
173 t.pixclk_khz = PixelClockRate / 1000;
174 if (!t.hratio || !t.vratio)
175 calc_ratio(&t);
176 return t;