dp aux: Handle partially acked multi-byte I2C writes

There is another case when we have to keep querying the I2C status
after starting a write transaction: When some bytes were already acked,
we receive an I2C-ACK for them and the number of bytes ack'ed. So
re-write the loop such that it always continues until one of these
conditions occur:

* We receive an I2C-ACK without additional data: This means
  all remaining bytes have been ack'ed.

* The summed up number of transferred bytes reaches the
  number of written bytes.

* We get an I2C-Defer but have re-tried too often without
  getting additional ACKs.

* We get an I2C-NAK.

Change-Id: I794dc1587f56b81539d1d4796f754644172f89b7
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/libgfxinit/+/52826
Tested-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
diff --git a/common/hw-gfx-dp_aux_ch.adb b/common/hw-gfx-dp_aux_ch.adb
index 8bc0c58..5b4fde4 100644
--- a/common/hw-gfx-dp_aux_ch.adb
+++ b/common/hw-gfx-dp_aux_ch.adb
@@ -181,8 +181,12 @@
    is
       Request : DP_Defs.Aux_Request;
 
+      Xfered      : Natural := 0;
+      Tries       : Natural := 0;
+      Max_Defers  : constant := 7;
+
       Response : DP_Defs.Aux_Response;
-      Ignored_Response_Length : DP_Defs.Aux_Response_Length;
+      Response_Length : DP_Defs.Aux_Response_Length;
    begin
       Fill_Aux_Request
         (Request  => Request,
@@ -190,21 +194,34 @@
          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");
+
+      loop
          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,
+            Response_Length   => Response_Length,
             Success           => Success);
-         exit when not (Success and Is_I2C_Defer (Response));
+         exit when not Success;
 
-         -- Command was already AUX-acked. Thus, only query for
-         -- new status from now on until we get I2C-acked too.
+         if Is_I2C_Ack (Response) then
+            if Response_Length <= 1 then
+               Xfered := Length;
+            else
+               Xfered := Xfered + Natural'Min (Natural (Response (1)), Length - Xfered);
+               Tries := 0;
+            end if;
+            exit when Xfered = Length;
+         elsif Is_I2C_Defer (Response) then
+            exit when Tries >= Max_Defers;
+            Tries := Tries + 1;
+         else -- Nak
+            exit;
+         end if;
+
+         -- Command was already AUX-acked. Thus, only query for new
+         -- status from now on until we got all bytes I2C-acked too.
          Fill_Aux_Request
            (Request  => Request,
             Command  => (Command and DP_AUX_I2C_MOT) or DP_AUX_I2C_WR_STATUS_REQ,
@@ -212,7 +229,7 @@
             Length   => 0);
          Time.U_Delay (500);
       end loop;
-      Success := Success and then Is_I2C_Ack (Response);
+      Success := Success and then (Is_I2C_Ack (Response) and Xfered = Length);
    end I2C_Out_Packet;
 
    procedure I2C_In_Packet