Initial upstream commit
The history contained unlicensed code so everything got squashed, sorry.
Change-Id: I9f5775208f9df6fb29074bf3bc498f68cb17b3a0
Signed-off-by: Nico Huber <nico.huber@secunet.com>
diff --git a/common/hw-gfx-edid.adb b/common/hw-gfx-edid.adb
new file mode 100644
index 0000000..da60d54
--- /dev/null
+++ b/common/hw-gfx-edid.adb
@@ -0,0 +1,180 @@
+--
+-- Copyright (C) 2016 secunet Security Networks AG
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+
+with HW;
+
+with HW.Debug;
+with GNAT.Source_Info;
+
+use type HW.Byte;
+use type HW.Pos16;
+use type HW.Word16;
+
+package body HW.GFX.EDID is
+
+ function Checksum_Valid (Raw_EDID : Raw_EDID_Data) return Boolean
+ with
+ Pre => True
+ is
+ Sum : Byte := 16#00#;
+ begin
+ for I in Raw_EDID_Index loop
+ Sum := Sum + Raw_EDID (I);
+ end loop;
+ pragma Debug (Sum /= 16#00#, Debug.Put_Line
+ (GNAT.Source_Info.Enclosing_Entity & ": EDID checksum invalid!"));
+ return Sum = 16#00#;
+ end Checksum_Valid;
+
+ function Valid (Raw_EDID : Raw_EDID_Data) return Boolean
+ is
+ Header_Valid : Boolean;
+ begin
+ Header_Valid :=
+ Raw_EDID (0) = 16#00# and
+ Raw_EDID (1) = 16#ff# and
+ Raw_EDID (2) = 16#ff# and
+ Raw_EDID (3) = 16#ff# and
+ Raw_EDID (4) = 16#ff# and
+ Raw_EDID (5) = 16#ff# and
+ Raw_EDID (6) = 16#ff# and
+ Raw_EDID (7) = 16#00#;
+ pragma Debug (not Header_Valid, Debug.Put_Line
+ (GNAT.Source_Info.Enclosing_Entity & ": EDID header pattern mismatch!"));
+
+ return Header_Valid and then Checksum_Valid (Raw_EDID);
+ end Valid;
+
+ ----------------------------------------------------------------------------
+
+ REVISION : constant := 19;
+ INPUT : constant := 20;
+ INPUT_DIGITAL : constant := 1 * 2 ** 7;
+ INPUT_DIGITAL_DEPTH_SHIFT : constant := 4;
+ INPUT_DIGITAL_DEPTH_MASK : constant := 7 * 2 ** 4;
+ INPUT_DIGITAL_DEPTH_UNDEF : constant := 0 * 2 ** 4;
+ INPUT_DIGITAL_DEPTH_RESERVED : constant := 7 * 2 ** 4;
+
+ ----------------------------------------------------------------------------
+
+ function Read_LE16
+ (Raw_EDID : Raw_EDID_Data;
+ Offset : Raw_EDID_Index)
+ return Word16
+ is
+ begin
+ return Shift_Left (Word16 (Raw_EDID (Offset + 1)), 8) or
+ Word16 (Raw_EDID (Offset));
+ end Read_LE16;
+
+ function Has_Preferred_Mode (Raw_EDID : Raw_EDID_Data) return Boolean
+ is
+ begin
+ return
+ Int64 (Read_LE16 (Raw_EDID, DESCRIPTOR_1)) * 10_000
+ in Frequency_Type and
+ ( Raw_EDID (DESCRIPTOR_1 + 2) /= 0 or
+ (Raw_EDID (DESCRIPTOR_1 + 4) and 16#f0#) /= 0) and
+ ( Raw_EDID (DESCRIPTOR_1 + 8) /= 0 or
+ (Raw_EDID (DESCRIPTOR_1 + 11) and 16#c0#) /= 0) and
+ ( Raw_EDID (DESCRIPTOR_1 + 9) /= 0 or
+ (Raw_EDID (DESCRIPTOR_1 + 11) and 16#30#) /= 0) and
+ ( Raw_EDID (DESCRIPTOR_1 + 3) /= 0 or
+ (Raw_EDID (DESCRIPTOR_1 + 4) and 16#0f#) /= 0) and
+ ( Raw_EDID (DESCRIPTOR_1 + 5) /= 0 or
+ (Raw_EDID (DESCRIPTOR_1 + 7) and 16#f0#) /= 0) and
+ ((Raw_EDID (DESCRIPTOR_1 + 10) and 16#f0#) /= 0 or
+ (Raw_EDID (DESCRIPTOR_1 + 11) and 16#0c#) /= 0) and
+ ((Raw_EDID (DESCRIPTOR_1 + 10) and 16#0f#) /= 0 or
+ (Raw_EDID (DESCRIPTOR_1 + 11) and 16#03#) /= 0) and
+ ( Raw_EDID (DESCRIPTOR_1 + 6) /= 0 or
+ (Raw_EDID (DESCRIPTOR_1 + 7) and 16#0f#) /= 0);
+ end Has_Preferred_Mode;
+
+ function Preferred_Mode (Raw_EDID : Raw_EDID_Data) return Mode_Type
+ is
+ Base : constant := DESCRIPTOR_1;
+ Mode : Mode_Type;
+
+ function Read_12
+ (Lower_8, Upper_4 : Raw_EDID_Index;
+ Shift : Natural)
+ return Word16
+ is
+ begin
+ return
+ Word16 (Raw_EDID (Lower_8)) or
+ (Shift_Left (Word16 (Raw_EDID (Upper_4)), Shift) and 16#0f00#);
+ end Read_12;
+
+ function Read_10
+ (Lower_8, Upper_2 : Raw_EDID_Index;
+ Shift : Natural)
+ return Word16
+ is
+ begin
+ return
+ Word16 (Raw_EDID (Lower_8)) or
+ (Shift_Left (Word16 (Raw_EDID (Upper_2)), Shift) and 16#0300#);
+ end Read_10;
+
+ function Read_6
+ (Lower_4 : Raw_EDID_Index;
+ Lower_Shift : Natural;
+ Upper_2 : Raw_EDID_Index;
+ Upper_Shift : Natural)
+ return Word8
+ is
+ begin
+ return
+ (Shift_Right (Word8 (Raw_EDID (Lower_4)), Lower_Shift) and 16#0f#)
+ or
+ (Shift_Left (Word8 (Raw_EDID (Upper_2)), Upper_Shift) and 16#30#);
+ end Read_6;
+ begin
+ Mode := Mode_Type'
+ (Dotclock => Pos64 (Read_LE16 (Raw_EDID, Base)) * 10_000,
+ H_Visible => Pos16 (Read_12 (Base + 2, Base + 4, 4)),
+ H_Sync_Begin => Pos16 (Read_10 (Base + 8, Base + 11, 2)),
+ H_Sync_End => Pos16 (Read_10 (Base + 9, Base + 11, 4)),
+ H_Total => Pos16 (Read_12 (Base + 3, Base + 4, 8)),
+ V_Visible => Pos16 (Read_12 (Base + 5, Base + 7, 4)),
+ V_Sync_Begin => Pos16 (Read_6 (Base + 10, 4, Base + 11, 2)),
+ V_Sync_End => Pos16 (Read_6 (Base + 10, 0, Base + 11, 4)),
+ V_Total => Pos16 (Read_12 (Base + 6, Base + 7, 8)),
+ H_Sync_Active_High => (Raw_EDID (Base + 17) and 16#02#) /= 0,
+ V_Sync_Active_High => (Raw_EDID (Base + 17) and 16#04#) /= 0,
+ BPC =>
+ (if Raw_EDID (REVISION) < 4 or
+ (Raw_EDID (INPUT) and INPUT_DIGITAL) = 16#00# or
+ (Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK) = INPUT_DIGITAL_DEPTH_UNDEF or
+ (Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK) = INPUT_DIGITAL_DEPTH_RESERVED
+ then
+ 0
+ else
+ 4 + 2 * Pos64 (Shift_Right
+ (Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK,
+ INPUT_DIGITAL_DEPTH_SHIFT))));
+
+ -- Calculate absolute values from EDID relative values.
+ Mode.H_Sync_Begin := Mode.H_Visible + Mode.H_Sync_Begin;
+ Mode.H_Sync_End := Mode.H_Sync_Begin + Mode.H_Sync_End;
+ Mode.H_Total := Mode.H_Visible + Mode.H_Total;
+ Mode.V_Sync_Begin := Mode.V_Visible + Mode.V_Sync_Begin;
+ Mode.V_Sync_End := Mode.V_Sync_Begin + Mode.V_Sync_End;
+ Mode.V_Total := Mode.V_Visible + Mode.V_Total;
+
+ return Mode;
+ end Preferred_Mode;
+
+end HW.GFX.EDID;