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-dp_aux_ch.adb b/common/hw-gfx-dp_aux_ch.adb
new file mode 100644
index 0000000..2f8b982
--- /dev/null
+++ b/common/hw-gfx-dp_aux_ch.adb
@@ -0,0 +1,392 @@
+--
+-- Copyright (C) 2015-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.Time;
+with HW.GFX.DP_Defs;
+
+use type HW.Word8;
+use type HW.GFX.DP_Defs.Aux_Message_Command;
+
+package body HW.GFX.DP_Aux_Ch is
+
+   DP_AUX_I2C_WRITE           : constant := 16#0#;
+   DP_AUX_I2C_READ            : constant := 16#1#;
+   DP_AUX_I2C_WR_STATUS_REQ   : constant := 16#2#;
+   DP_AUX_I2C_MOT             : constant := 16#4#;
+   DP_AUX_NATIVE_WRITE        : constant := 16#8#;
+   DP_AUX_NATIVE_READ         : constant := 16#9#;
+
+   procedure Fill_Aux_Request
+     (Request  :    out DP_Defs.Aux_Request;
+      Command  : in     DP_Defs.Aux_Message_Command;
+      Address  : in     DP_Defs.Aux_Message_Address;
+      Length   : in     DP_Defs.Aux_Payload_Length)
+   is
+   begin
+      Request :=
+        (0      => Shift_Left (Word8 (Command), 4) or
+                   Word8 (Shift_Right (Word32 (Address), 16)),
+         1      => Word8 (Shift_Right (Word32 (Address),  8) and 16#ff#),
+         2      => Word8 (Shift_Right (Word32 (Address),  0) and 16#ff#),
+         3      => Word8 (Length) - 1,
+         others => 0);  -- Don't care
+   end Fill_Aux_Request;
+
+   function Is_Empty (Request : DP_Defs.Aux_Request) return Boolean is
+   begin
+      return Request (3) = 16#ff#;
+   end Is_Empty;
+
+   function Is_Aux_Ack (Response : DP_Defs.Aux_Response) return Boolean
+   with
+      Depends => (Is_Aux_Ack'Result => Response)
+   is
+   begin
+      return (Response (0) and 16#30#) = 16#00#;
+   end Is_Aux_Ack;
+
+   function Is_Aux_Defer (Response : DP_Defs.Aux_Response) return Boolean is
+   begin
+      return (Response (0) and 16#30#) = 16#20#;
+   end Is_Aux_Defer;
+
+   function Is_I2C_Ack (Response : DP_Defs.Aux_Response) return Boolean
+   with
+      Depends => (Is_I2C_Ack'Result => Response)
+   is
+   begin
+      return (Response (0) and 16#c0#) = 16#00#;
+   end Is_I2C_Ack;
+
+   function Is_I2C_Defer (Response : DP_Defs.Aux_Response) return Boolean is
+   begin
+      return (Response (0) and 16#c0#) = 16#80#;
+   end Is_I2C_Defer;
+
+   ----------------------------------------------------------------------------
+
+   procedure Do_Aux_Request
+     (Port              : in     T;
+      Request           : in     DP_Defs.Aux_Request;
+      Request_Length    : in     DP_Defs.Aux_Request_Length;
+      Response          :    out DP_Defs.Aux_Response;
+      Response_Length   :    out DP_Defs.Aux_Response_Length;
+      Success           :    out Boolean)
+   is
+   begin
+      for Try in Positive range 1 .. 32 loop
+         Aux_Request
+           (Port              => Port,
+            Request           => Request,
+            Request_Length    => Request_Length,
+            Response          => Response,
+            Response_Length   => Response_Length,
+            Success           => Success);
+
+         exit when not (Success and Is_Aux_Defer (Response));
+         Time.U_Delay (500);
+      end loop;
+
+      Success := Success and then Is_Aux_Ack (Response);
+   end Do_Aux_Request;
+
+   ----------------------------------------------------------------------------
+
+   procedure Aux_Read
+     (Port     : in     T;
+      Address  : in     DP_Defs.Aux_Message_Address;
+      Length   : in out DP_Defs.Aux_Payload_Length;
+      Data     :    out DP_Defs.Aux_Payload;
+      Success  :    out Boolean)
+   is
+      Request : DP_Defs.Aux_Request;
+      Response : DP_Defs.Aux_Response;
+      Response_Length : DP_Defs.Aux_Response_Length;
+   begin
+      Data := (others => 0);  -- Initialize
+
+      Fill_Aux_Request
+        (Request  => Request,
+         Command  => DP_AUX_NATIVE_READ,
+         Address  => Address,
+         Length   => Length);
+
+      Do_Aux_Request
+        (Port              => Port,
+         Request           => Request,
+         Request_Length    => 4,
+         Response          => Response,
+         Response_Length   => Response_Length,
+         Success           => Success);
+
+      Success := Success and then Response_Length > 1;
+      if Success then
+         pragma Assert (Response_Length > 1);
+         Length := Response_Length - 1;
+         Data (0 .. Length - 1) :=  Response (1 .. Length);
+      end if;
+   end Aux_Read;
+
+   procedure Aux_Write
+     (Port     : in     T;
+      Address  : in     DP_Defs.Aux_Message_Address;
+      Length   : in     DP_Defs.Aux_Payload_Length;
+      Data     : in     DP_Defs.Aux_Payload;
+      Success  :    out Boolean)
+   is
+      Request : DP_Defs.Aux_Request;
+
+      Ignored_Response        : DP_Defs.Aux_Response;
+      Ignored_Response_Length : DP_Defs.Aux_Response_Length;
+   begin
+      Fill_Aux_Request
+        (Request  => Request,
+         Command  => DP_AUX_NATIVE_WRITE,
+         Address  => Address,
+         Length   => Length);
+      Request (4 .. Length + 4 - 1) := Data (0 .. Length - 1);
+
+      pragma Warnings (GNATprove, Off,
+                       "unused assignment to ""Ignored_Response*""",
+                       Reason => "No response expected here");
+      Do_Aux_Request
+        (Port              => Port,
+         Request           => Request,
+         Request_Length    => 4 + Length,
+         Response          => Ignored_Response,
+         Response_Length   => Ignored_Response_Length,
+         Success           => Success);
+   end Aux_Write;
+
+   ----------------------------------------------------------------------------
+
+   procedure I2C_Out_Packet
+     (Port              : in     T;
+      Command           : in     DP_Defs.Aux_Message_Command;
+      Address           : in     DP_Defs.Aux_Message_Address;
+      Length            : in     DP_Defs.Aux_Payload_Length;
+      Data              : in     DP_Defs.Aux_Payload;
+      Success           :    out Boolean)
+   is
+      Request : DP_Defs.Aux_Request;
+
+      Response : DP_Defs.Aux_Response;
+      Ignored_Response_Length : DP_Defs.Aux_Response_Length;
+   begin
+      Fill_Aux_Request
+        (Request  => Request,
+         Command  => Command,
+         Address  => Address,
+         Length   => Length);
+      Request (4 .. Length + 4 - 1) := Data (0 .. Length - 1);
+      for Try in Positive range 1 .. 7 loop
+         pragma Warnings (GNATprove, Off,
+                          "unused assignment to ""Ignored_Response_Length""",
+                          Reason => "No response expected here");
+         Do_Aux_Request
+           (Port              => Port,
+            Request           => Request,
+            Request_Length    => (if Is_Empty (Request) then 3 else 4 + Length),
+            Response          => Response,
+            Response_Length   => Ignored_Response_Length,
+            Success           => Success);
+         exit when not (Success and Is_I2C_Defer (Response));
+
+         -- Command was already AUX-acked. Thus, only query for
+         -- new status from now on until we get I2C-acked too.
+         Fill_Aux_Request
+           (Request  => Request,
+            Command  => (Command and DP_AUX_I2C_MOT) or DP_AUX_I2C_WR_STATUS_REQ,
+            Address  => Address,
+            Length   => 0);
+         Time.U_Delay (500);
+      end loop;
+      Success := Success and then Is_I2C_Ack (Response);
+   end I2C_Out_Packet;
+
+   procedure I2C_In_Packet
+     (Port              : in     T;
+      Command           : in     DP_Defs.Aux_Message_Command;
+      Address           : in     DP_Defs.Aux_Message_Address;
+      Length            : in     DP_Defs.Aux_Payload_Length;
+      Response          :    out DP_Defs.Aux_Response;
+      Response_Length   :    out DP_Defs.Aux_Response_Length;
+      Success           :    out Boolean)
+   is
+      Request : DP_Defs.Aux_Request;
+   begin
+      Fill_Aux_Request
+        (Request  => Request,
+         Command  => Command,
+         Address  => Address,
+         Length   => Length);
+      for Try in Positive range 1 .. 7 loop
+         Do_Aux_Request
+           (Port              => Port,
+            Request           => Request,
+            Request_Length    => (if Is_Empty (Request) then 3 else 4),
+            Response          => Response,
+            Response_Length   => Response_Length,
+            Success           => Success);
+         exit when not (Success and Is_I2C_Defer (Response));
+
+         Time.U_Delay (500);
+      end loop;
+      Success := Success and then Is_I2C_Ack (Response);
+   end I2C_In_Packet;
+
+   procedure I2C_Empty_Packet
+     (Port              : in     T;
+      Command           : in     DP_Defs.Aux_Message_Command;
+      Address           : in     DP_Defs.Aux_Message_Address;
+      Success           :    out Boolean)
+   is
+      Ignored_Response        : DP_Defs.Aux_Response;
+      Ignored_Response_Length : DP_Defs.Aux_Response_Length;
+   begin
+      pragma Warnings (GNATprove, Off,
+                       "unused assignment to ""Ignored_Response*""",
+                       Reason => "No response expected here");
+      I2C_In_Packet
+        (Port              => Port,
+         Command           => Command,
+         Address           => Address,
+         Length            => 0,
+         Response          => Ignored_Response,
+         Response_Length   => Ignored_Response_Length,
+         Success           => Success);
+   end I2C_Empty_Packet;
+
+   ----------------------------------------------------------------------------
+
+   procedure Do_I2C_Write
+     (Port     : in     T;
+      Address  : in     I2C.Transfer_Address;
+      Length   : in     DP_Defs.Aux_Payload_Length;
+      Data     : in     DP_Defs.Aux_Payload;
+      Success  :    out Boolean)
+   is
+      Ignored_Success : Boolean;
+   begin
+      -- I2C address "start" packet
+      I2C_Empty_Packet
+        (Port     => Port,
+         Command  => DP_AUX_I2C_WRITE or DP_AUX_I2C_MOT,
+         Address  => DP_Defs.Aux_Message_Address (Address),
+         Success  => Success);
+
+      if Success then
+         I2C_Out_Packet
+           (Port              => Port,
+            Command           => DP_AUX_I2C_WRITE or DP_AUX_I2C_MOT,
+            Address           => DP_Defs.Aux_Message_Address (Address),
+            Length            => Length,
+            Data              => Data,
+            Success           => Success);
+
+         pragma Warnings
+           (GNATprove, Off, "unused assignment to ""Ignored_Success""",
+            Reason => "Doesn't matter as long as the transfer itself succeeds");
+         -- I2C address "stop" packet
+         I2C_Empty_Packet
+           (Port     => Port,
+            Command  => DP_AUX_I2C_WRITE,
+            Address  => DP_Defs.Aux_Message_Address (Address),
+            Success  => Ignored_Success);
+      end if;
+   end Do_I2C_Write;
+
+   procedure Do_I2C_Read
+     (Port     : in     T;
+      Address  : in     I2C.Transfer_Address;
+      Length   : in out I2C.Transfer_Length;
+      Data     : in out I2C.Transfer_Data;
+      Success  :    out Boolean)
+   is
+      Xfered   : Natural := 0;
+      Chunk    : DP_Defs.Aux_Payload_Length := DP_Defs.Aux_Payload_Length'Last;
+
+      Tries       : Natural := 0;
+      Max_Tries   : constant := 4;
+
+      Response : DP_Defs.Aux_Response;
+      Response_Length : DP_Defs.Aux_Response_Length;
+
+      Ignored_Success : Boolean;
+   begin
+      -- I2C address "start" packet
+      I2C_Empty_Packet
+        (Port     => Port,
+         Command  => DP_AUX_I2C_READ or DP_AUX_I2C_MOT,
+         Address  => DP_Defs.Aux_Message_Address (Address),
+         Success  => Success);
+
+      while Success and then (Xfered < Length and Tries < Max_Tries) loop
+         I2C_In_Packet
+           (Port              => Port,
+            Command           => DP_AUX_I2C_READ or DP_AUX_I2C_MOT,
+            Address           => DP_Defs.Aux_Message_Address (Address),
+            Length            => Natural'Min (Chunk, Length - Xfered),
+            Response          => Response,
+            Response_Length   => Response_Length,
+            Success           => Success);
+
+         if Success and then Response_Length >= 2 then
+            Chunk := Natural'Min (Response_Length - 1, Length - Xfered);
+            Data (Xfered .. Xfered + Chunk - 1) := Response (1 .. Chunk);
+            Xfered := Xfered + Chunk;
+            Tries := 0;
+         else
+            Tries := Tries + 1;
+         end if;
+         pragma Loop_Invariant (Xfered <= Length);
+      end loop;
+
+      if Success then
+         pragma Warnings
+           (GNATprove, Off, "unused assignment to ""Ignored_Success""",
+            Reason => "Doesn't matter as long as the transfer itself succeeds");
+         -- I2C address "stop" packet
+         I2C_Empty_Packet
+           (Port     => Port,
+            Command  => DP_AUX_I2C_READ,
+            Address  => DP_Defs.Aux_Message_Address (Address),
+            Success  => Ignored_Success);
+      end if;
+
+      Success := Success and then Tries < Max_Tries;
+      Length := Xfered;
+   end Do_I2C_Read;
+
+   ----------------------------------------------------------------------------
+
+   procedure I2C_Read
+     (Port     : in     T;
+      Address  : in     I2C.Transfer_Address;
+      Length   : in out I2C.Transfer_Length;
+      Data     :    out I2C.Transfer_Data;
+      Success  :    out Boolean)
+   is
+      Index_Payload : DP_Defs.Aux_Payload;
+   begin
+      Data := (others => 16#00#);
+
+      Index_Payload := (others => 16#00#);   -- send index 0
+      Do_I2C_Write (Port, Address, 1, Index_Payload, Success);
+
+      if Success then
+         Do_I2C_Read (Port, Address, Length, Data, Success);
+      end if;
+   end I2C_Read;
+
+end HW.GFX.DP_Aux_Ch;