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;