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;