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