blob: 44d729f9c316390a871ca23892cbfb348144d2e8 [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
2-- Copyright (C) 2016 secunet Security Networks AG
3--
4-- This program is free software; you can redistribute it and/or modify
5-- it under the terms of the GNU General Public License as published by
Nico Huber125a29e2016-10-18 00:23:54 +02006-- the Free Software Foundation; either version 2 of the License, or
7-- (at your option) any later version.
Nico Huber83693c82016-10-08 22:17:55 +02008--
9-- This program is distributed in the hope that it will be useful,
10-- but WITHOUT ANY WARRANTY; without even the implied warranty of
11-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12-- GNU General Public License for more details.
13--
14
15with HW;
16
17with HW.Debug;
18with GNAT.Source_Info;
19
20use type HW.Byte;
21use type HW.Pos16;
22use type HW.Word16;
23
24package body HW.GFX.EDID is
25
26 function Checksum_Valid (Raw_EDID : Raw_EDID_Data) return Boolean
27 with
28 Pre => True
29 is
30 Sum : Byte := 16#00#;
31 begin
32 for I in Raw_EDID_Index loop
33 Sum := Sum + Raw_EDID (I);
34 end loop;
35 pragma Debug (Sum /= 16#00#, Debug.Put_Line
36 (GNAT.Source_Info.Enclosing_Entity & ": EDID checksum invalid!"));
37 return Sum = 16#00#;
38 end Checksum_Valid;
39
40 function Valid (Raw_EDID : Raw_EDID_Data) return Boolean
41 is
42 Header_Valid : Boolean;
43 begin
44 Header_Valid :=
45 Raw_EDID (0) = 16#00# and
46 Raw_EDID (1) = 16#ff# and
47 Raw_EDID (2) = 16#ff# and
48 Raw_EDID (3) = 16#ff# and
49 Raw_EDID (4) = 16#ff# and
50 Raw_EDID (5) = 16#ff# and
51 Raw_EDID (6) = 16#ff# and
52 Raw_EDID (7) = 16#00#;
53 pragma Debug (not Header_Valid, Debug.Put_Line
54 (GNAT.Source_Info.Enclosing_Entity & ": EDID header pattern mismatch!"));
55
56 return Header_Valid and then Checksum_Valid (Raw_EDID);
57 end Valid;
58
59 ----------------------------------------------------------------------------
60
61 REVISION : constant := 19;
62 INPUT : constant := 20;
63 INPUT_DIGITAL : constant := 1 * 2 ** 7;
64 INPUT_DIGITAL_DEPTH_SHIFT : constant := 4;
65 INPUT_DIGITAL_DEPTH_MASK : constant := 7 * 2 ** 4;
66 INPUT_DIGITAL_DEPTH_UNDEF : constant := 0 * 2 ** 4;
67 INPUT_DIGITAL_DEPTH_RESERVED : constant := 7 * 2 ** 4;
68
69 ----------------------------------------------------------------------------
70
Nico Huber393aa8a2016-10-21 14:18:53 +020071 function Compatible_Display
72 (Raw_EDID : Raw_EDID_Data;
73 Display : Display_Type)
74 return Boolean
75 is
76 begin
77 return (Display = VGA) = ((Raw_EDID (INPUT) and INPUT_DIGITAL) = 16#00#);
78 end Compatible_Display;
79
Nico Huber83693c82016-10-08 22:17:55 +020080 function Read_LE16
81 (Raw_EDID : Raw_EDID_Data;
82 Offset : Raw_EDID_Index)
83 return Word16
84 is
85 begin
86 return Shift_Left (Word16 (Raw_EDID (Offset + 1)), 8) or
87 Word16 (Raw_EDID (Offset));
88 end Read_LE16;
89
90 function Has_Preferred_Mode (Raw_EDID : Raw_EDID_Data) return Boolean
91 is
92 begin
93 return
94 Int64 (Read_LE16 (Raw_EDID, DESCRIPTOR_1)) * 10_000
95 in Frequency_Type and
96 ( Raw_EDID (DESCRIPTOR_1 + 2) /= 0 or
97 (Raw_EDID (DESCRIPTOR_1 + 4) and 16#f0#) /= 0) and
98 ( Raw_EDID (DESCRIPTOR_1 + 8) /= 0 or
99 (Raw_EDID (DESCRIPTOR_1 + 11) and 16#c0#) /= 0) and
100 ( Raw_EDID (DESCRIPTOR_1 + 9) /= 0 or
101 (Raw_EDID (DESCRIPTOR_1 + 11) and 16#30#) /= 0) and
102 ( Raw_EDID (DESCRIPTOR_1 + 3) /= 0 or
103 (Raw_EDID (DESCRIPTOR_1 + 4) and 16#0f#) /= 0) and
104 ( Raw_EDID (DESCRIPTOR_1 + 5) /= 0 or
105 (Raw_EDID (DESCRIPTOR_1 + 7) and 16#f0#) /= 0) and
106 ((Raw_EDID (DESCRIPTOR_1 + 10) and 16#f0#) /= 0 or
107 (Raw_EDID (DESCRIPTOR_1 + 11) and 16#0c#) /= 0) and
108 ((Raw_EDID (DESCRIPTOR_1 + 10) and 16#0f#) /= 0 or
109 (Raw_EDID (DESCRIPTOR_1 + 11) and 16#03#) /= 0) and
110 ( Raw_EDID (DESCRIPTOR_1 + 6) /= 0 or
111 (Raw_EDID (DESCRIPTOR_1 + 7) and 16#0f#) /= 0);
112 end Has_Preferred_Mode;
113
114 function Preferred_Mode (Raw_EDID : Raw_EDID_Data) return Mode_Type
115 is
116 Base : constant := DESCRIPTOR_1;
117 Mode : Mode_Type;
118
119 function Read_12
120 (Lower_8, Upper_4 : Raw_EDID_Index;
121 Shift : Natural)
122 return Word16
123 is
124 begin
125 return
126 Word16 (Raw_EDID (Lower_8)) or
127 (Shift_Left (Word16 (Raw_EDID (Upper_4)), Shift) and 16#0f00#);
128 end Read_12;
129
130 function Read_10
131 (Lower_8, Upper_2 : Raw_EDID_Index;
132 Shift : Natural)
133 return Word16
134 is
135 begin
136 return
137 Word16 (Raw_EDID (Lower_8)) or
138 (Shift_Left (Word16 (Raw_EDID (Upper_2)), Shift) and 16#0300#);
139 end Read_10;
140
141 function Read_6
142 (Lower_4 : Raw_EDID_Index;
143 Lower_Shift : Natural;
144 Upper_2 : Raw_EDID_Index;
145 Upper_Shift : Natural)
146 return Word8
147 is
148 begin
149 return
150 (Shift_Right (Word8 (Raw_EDID (Lower_4)), Lower_Shift) and 16#0f#)
151 or
152 (Shift_Left (Word8 (Raw_EDID (Upper_2)), Upper_Shift) and 16#30#);
153 end Read_6;
154 begin
155 Mode := Mode_Type'
156 (Dotclock => Pos64 (Read_LE16 (Raw_EDID, Base)) * 10_000,
157 H_Visible => Pos16 (Read_12 (Base + 2, Base + 4, 4)),
158 H_Sync_Begin => Pos16 (Read_10 (Base + 8, Base + 11, 2)),
159 H_Sync_End => Pos16 (Read_10 (Base + 9, Base + 11, 4)),
160 H_Total => Pos16 (Read_12 (Base + 3, Base + 4, 8)),
161 V_Visible => Pos16 (Read_12 (Base + 5, Base + 7, 4)),
162 V_Sync_Begin => Pos16 (Read_6 (Base + 10, 4, Base + 11, 2)),
163 V_Sync_End => Pos16 (Read_6 (Base + 10, 0, Base + 11, 4)),
164 V_Total => Pos16 (Read_12 (Base + 6, Base + 7, 8)),
165 H_Sync_Active_High => (Raw_EDID (Base + 17) and 16#02#) /= 0,
166 V_Sync_Active_High => (Raw_EDID (Base + 17) and 16#04#) /= 0,
167 BPC =>
168 (if Raw_EDID (REVISION) < 4 or
169 (Raw_EDID (INPUT) and INPUT_DIGITAL) = 16#00# or
170 (Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK) = INPUT_DIGITAL_DEPTH_UNDEF or
171 (Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK) = INPUT_DIGITAL_DEPTH_RESERVED
172 then
Nico Huber16f3dec2016-10-09 19:33:34 +0200173 Auto_BPC
Nico Huber83693c82016-10-08 22:17:55 +0200174 else
175 4 + 2 * Pos64 (Shift_Right
176 (Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK,
177 INPUT_DIGITAL_DEPTH_SHIFT))));
178
179 -- Calculate absolute values from EDID relative values.
180 Mode.H_Sync_Begin := Mode.H_Visible + Mode.H_Sync_Begin;
181 Mode.H_Sync_End := Mode.H_Sync_Begin + Mode.H_Sync_End;
182 Mode.H_Total := Mode.H_Visible + Mode.H_Total;
183 Mode.V_Sync_Begin := Mode.V_Visible + Mode.V_Sync_Begin;
184 Mode.V_Sync_End := Mode.V_Sync_Begin + Mode.V_Sync_End;
185 Mode.V_Total := Mode.V_Visible + Mode.V_Total;
186
187 return Mode;
188 end Preferred_Mode;
189
190end HW.GFX.EDID;