blob: 64b86a99cb9dd2dcfe2eb9d91618c1bcef80d6fb [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
71 function Read_LE16
72 (Raw_EDID : Raw_EDID_Data;
73 Offset : Raw_EDID_Index)
74 return Word16
75 is
76 begin
77 return Shift_Left (Word16 (Raw_EDID (Offset + 1)), 8) or
78 Word16 (Raw_EDID (Offset));
79 end Read_LE16;
80
81 function Has_Preferred_Mode (Raw_EDID : Raw_EDID_Data) return Boolean
82 is
83 begin
84 return
85 Int64 (Read_LE16 (Raw_EDID, DESCRIPTOR_1)) * 10_000
86 in Frequency_Type and
87 ( Raw_EDID (DESCRIPTOR_1 + 2) /= 0 or
88 (Raw_EDID (DESCRIPTOR_1 + 4) and 16#f0#) /= 0) and
89 ( Raw_EDID (DESCRIPTOR_1 + 8) /= 0 or
90 (Raw_EDID (DESCRIPTOR_1 + 11) and 16#c0#) /= 0) and
91 ( Raw_EDID (DESCRIPTOR_1 + 9) /= 0 or
92 (Raw_EDID (DESCRIPTOR_1 + 11) and 16#30#) /= 0) and
93 ( Raw_EDID (DESCRIPTOR_1 + 3) /= 0 or
94 (Raw_EDID (DESCRIPTOR_1 + 4) and 16#0f#) /= 0) and
95 ( Raw_EDID (DESCRIPTOR_1 + 5) /= 0 or
96 (Raw_EDID (DESCRIPTOR_1 + 7) and 16#f0#) /= 0) and
97 ((Raw_EDID (DESCRIPTOR_1 + 10) and 16#f0#) /= 0 or
98 (Raw_EDID (DESCRIPTOR_1 + 11) and 16#0c#) /= 0) and
99 ((Raw_EDID (DESCRIPTOR_1 + 10) and 16#0f#) /= 0 or
100 (Raw_EDID (DESCRIPTOR_1 + 11) and 16#03#) /= 0) and
101 ( Raw_EDID (DESCRIPTOR_1 + 6) /= 0 or
102 (Raw_EDID (DESCRIPTOR_1 + 7) and 16#0f#) /= 0);
103 end Has_Preferred_Mode;
104
105 function Preferred_Mode (Raw_EDID : Raw_EDID_Data) return Mode_Type
106 is
107 Base : constant := DESCRIPTOR_1;
108 Mode : Mode_Type;
109
110 function Read_12
111 (Lower_8, Upper_4 : Raw_EDID_Index;
112 Shift : Natural)
113 return Word16
114 is
115 begin
116 return
117 Word16 (Raw_EDID (Lower_8)) or
118 (Shift_Left (Word16 (Raw_EDID (Upper_4)), Shift) and 16#0f00#);
119 end Read_12;
120
121 function Read_10
122 (Lower_8, Upper_2 : Raw_EDID_Index;
123 Shift : Natural)
124 return Word16
125 is
126 begin
127 return
128 Word16 (Raw_EDID (Lower_8)) or
129 (Shift_Left (Word16 (Raw_EDID (Upper_2)), Shift) and 16#0300#);
130 end Read_10;
131
132 function Read_6
133 (Lower_4 : Raw_EDID_Index;
134 Lower_Shift : Natural;
135 Upper_2 : Raw_EDID_Index;
136 Upper_Shift : Natural)
137 return Word8
138 is
139 begin
140 return
141 (Shift_Right (Word8 (Raw_EDID (Lower_4)), Lower_Shift) and 16#0f#)
142 or
143 (Shift_Left (Word8 (Raw_EDID (Upper_2)), Upper_Shift) and 16#30#);
144 end Read_6;
145 begin
146 Mode := Mode_Type'
147 (Dotclock => Pos64 (Read_LE16 (Raw_EDID, Base)) * 10_000,
148 H_Visible => Pos16 (Read_12 (Base + 2, Base + 4, 4)),
149 H_Sync_Begin => Pos16 (Read_10 (Base + 8, Base + 11, 2)),
150 H_Sync_End => Pos16 (Read_10 (Base + 9, Base + 11, 4)),
151 H_Total => Pos16 (Read_12 (Base + 3, Base + 4, 8)),
152 V_Visible => Pos16 (Read_12 (Base + 5, Base + 7, 4)),
153 V_Sync_Begin => Pos16 (Read_6 (Base + 10, 4, Base + 11, 2)),
154 V_Sync_End => Pos16 (Read_6 (Base + 10, 0, Base + 11, 4)),
155 V_Total => Pos16 (Read_12 (Base + 6, Base + 7, 8)),
156 H_Sync_Active_High => (Raw_EDID (Base + 17) and 16#02#) /= 0,
157 V_Sync_Active_High => (Raw_EDID (Base + 17) and 16#04#) /= 0,
158 BPC =>
159 (if Raw_EDID (REVISION) < 4 or
160 (Raw_EDID (INPUT) and INPUT_DIGITAL) = 16#00# or
161 (Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK) = INPUT_DIGITAL_DEPTH_UNDEF or
162 (Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK) = INPUT_DIGITAL_DEPTH_RESERVED
163 then
Nico Huber16f3dec2016-10-09 19:33:34 +0200164 Auto_BPC
Nico Huber83693c82016-10-08 22:17:55 +0200165 else
166 4 + 2 * Pos64 (Shift_Right
167 (Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK,
168 INPUT_DIGITAL_DEPTH_SHIFT))));
169
170 -- Calculate absolute values from EDID relative values.
171 Mode.H_Sync_Begin := Mode.H_Visible + Mode.H_Sync_Begin;
172 Mode.H_Sync_End := Mode.H_Sync_Begin + Mode.H_Sync_End;
173 Mode.H_Total := Mode.H_Visible + Mode.H_Total;
174 Mode.V_Sync_Begin := Mode.V_Visible + Mode.V_Sync_Begin;
175 Mode.V_Sync_End := Mode.V_Sync_Begin + Mode.V_Sync_End;
176 Mode.V_Total := Mode.V_Visible + Mode.V_Total;
177
178 return Mode;
179 end Preferred_Mode;
180
181end HW.GFX.EDID;