gma adl: Implement TC ownership/connection handling

The ownership handling and hot-plug status moved from FIA registers
into DDI_BUF_CTL and new TCSS_DDI_STATUS registers.

Change-Id: I04c1341ceb7339ec4a06450b2d9ce07b27688904
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.sourcearcade.org/c/libgfxinit/+/506
Tested-by: Ada SPARK <gnatbot@sourcearcade.org>
Reviewed-by: Thomas Heijligen <src@posteo.de>
diff --git a/common/tigerlake/hw-gfx-gma-connectors-tc.adb b/common/tigerlake/hw-gfx-gma-connectors-tc.adb
index bd0e991..84eb4b0 100644
--- a/common/tigerlake/hw-gfx-gma-connectors-tc.adb
+++ b/common/tigerlake/hw-gfx-gma-connectors-tc.adb
@@ -31,7 +31,6 @@
    function HIP_INDEX_VAL (P : USBC_Port; Val : Word32) return Word32 is
      (Val * 2 ** (8 * ((GPU_Port'Pos (P) - GPU_Port'Pos (DDI_TC1)) mod 4)));
 
-   type Port_Regs_Array is array (USBC_Port) of Registers.Registers_Index;
    DKL_DP_MODE : constant Port_Regs_Array :=
      (DDI_TC1 => Registers.DKL_DP_MODE_1,
       DDI_TC2 => Registers.DKL_DP_MODE_2,
@@ -56,27 +55,6 @@
    TCCOLD_UNBLOCK_REQ       : constant := 16#01#;
    TCCOLD_BLOCK_RESULT_FAIL : constant := 16#01#;
 
-   DDI_BUF_CTL_BUFFER_ENABLE        : constant :=      1 * 2 ** 31;
-   DDI_BUF_CTL_TRANS_SELECT_MASK    : constant :=  16#f# * 2 ** 24;
-   DDI_BUF_CTL_PORT_REVERSAL        : constant :=      1 * 2 ** 16;
-   DDI_BUF_CTL_PORT_WIDTH_MASK      : constant :=      7 * 2 **  1;
-   DDI_BUF_CTL_PORT_WIDTH_1_LANE    : constant :=      0 * 2 **  1;
-   DDI_BUF_CTL_PORT_WIDTH_2_LANES   : constant :=      1 * 2 **  1;
-   DDI_BUF_CTL_PORT_WIDTH_4_LANES   : constant :=      3 * 2 **  1;
-   DDI_BUF_CTL_IDLE_STATUS          : constant :=      1 * 2 **  7;
-
-   DDI_BUF_CTL_PORT_WIDTH : constant array (DP_Lane_Count) of Word32 :=
-     (HW.GFX.DP_Lane_Count_1 => DDI_BUF_CTL_PORT_WIDTH_1_LANE,
-      HW.GFX.DP_Lane_Count_2 => DDI_BUF_CTL_PORT_WIDTH_2_LANES,
-      HW.GFX.DP_Lane_Count_4 => DDI_BUF_CTL_PORT_WIDTH_4_LANES);
-   DDI_BUF_CTL : constant Port_Regs_Array :=
-     (DDI_TC1  => Registers.DDI_BUF_CTL_USBC1,
-      DDI_TC2  => Registers.DDI_BUF_CTL_USBC2,
-      DDI_TC3  => Registers.DDI_BUF_CTL_USBC3,
-      DDI_TC4  => Registers.DDI_BUF_CTL_USBC4,
-      DDI_TC5  => Registers.DDI_BUF_CTL_USBC5,
-      DDI_TC6  => Registers.DDI_BUF_CTL_USBC6);
-
    type Buffer_Trans is record
       Vswing_Control     : Word32;
       Preshoot_Control   : Word32;
diff --git a/common/tigerlake/hw-gfx-gma-connectors-tc.ads b/common/tigerlake/hw-gfx-gma-connectors-tc.ads
index 25f30eb..9e637d0 100644
--- a/common/tigerlake/hw-gfx-gma-connectors-tc.ads
+++ b/common/tigerlake/hw-gfx-gma-connectors-tc.ads
@@ -36,6 +36,30 @@
    -- And so far, no SKU needs more.
    subtype Valid_TC_Port is USBC_Port range DDI_TC1 .. Config.Last_TC_Port;
 
+   type Port_Regs_Array is array (USBC_Port) of Registers.Registers_Index;
+
+   DDI_BUF_CTL_BUFFER_ENABLE        : constant :=      1 * 2 ** 31;
+   DDI_BUF_CTL_TRANS_SELECT_MASK    : constant :=  16#f# * 2 ** 24;
+   DDI_BUF_CTL_PORT_REVERSAL        : constant :=      1 * 2 ** 16;
+   DDI_BUF_CTL_PORT_WIDTH_MASK      : constant :=      7 * 2 **  1;
+   DDI_BUF_CTL_PORT_WIDTH_1_LANE    : constant :=      0 * 2 **  1;
+   DDI_BUF_CTL_PORT_WIDTH_2_LANES   : constant :=      1 * 2 **  1;
+   DDI_BUF_CTL_PORT_WIDTH_4_LANES   : constant :=      3 * 2 **  1;
+   DDI_BUF_CTL_IDLE_STATUS          : constant :=      1 * 2 **  7;
+   DDI_BUF_CTL_TC_PHY_OWNERSHIP     : constant :=      1 * 2 **  6;
+
+   DDI_BUF_CTL_PORT_WIDTH : constant array (DP_Lane_Count) of Word32 :=
+     (HW.GFX.DP_Lane_Count_1 => DDI_BUF_CTL_PORT_WIDTH_1_LANE,
+      HW.GFX.DP_Lane_Count_2 => DDI_BUF_CTL_PORT_WIDTH_2_LANES,
+      HW.GFX.DP_Lane_Count_4 => DDI_BUF_CTL_PORT_WIDTH_4_LANES);
+   DDI_BUF_CTL : constant Port_Regs_Array :=
+     (DDI_TC1  => Registers.DDI_BUF_CTL_USBC1,
+      DDI_TC2  => Registers.DDI_BUF_CTL_USBC2,
+      DDI_TC3  => Registers.DDI_BUF_CTL_USBC3,
+      DDI_TC4  => Registers.DDI_BUF_CTL_USBC4,
+      DDI_TC5  => Registers.DDI_BUF_CTL_USBC5,
+      DDI_TC6  => Registers.DDI_BUF_CTL_USBC6);
+
    type Fia_Regs_Record is record
       PORT_TX_DFLEXDPMLE1 : Registers.Registers_Index;
       PORT_TX_DFLEXDPSP   : Registers.Registers_Index;
diff --git a/common/tigerlake/xelpd/hw-gfx-gma-connectors-tc-ownership.adb b/common/tigerlake/xelpd/hw-gfx-gma-connectors-tc-ownership.adb
index 4e509ad..c3b1d2b 100644
--- a/common/tigerlake/xelpd/hw-gfx-gma-connectors-tc-ownership.adb
+++ b/common/tigerlake/xelpd/hw-gfx-gma-connectors-tc-ownership.adb
@@ -14,24 +14,78 @@
 
 with HW.GFX.GMA.Config;
 with HW.GFX.GMA.Registers;
+with HW.GFX.DP_Info;
+with HW.GFX.GMA.PCode;
 
 with HW.Debug;
 with GNAT.Source_Info;
 
+use type HW.Word64;
+
 package body HW.GFX.GMA.Connectors.TC.Ownership is
 
+   type Port_Regs_Array is array (Valid_TC_Port) of Registers.Registers_Index;
+
+   TCSS_DDI_STATUS : constant Port_Regs_Array :=
+      Port_Regs_Array'
+     (DDI_TC1 => Registers.TCSS_DDI_STATUS_1,
+      DDI_TC2 => Registers.TCSS_DDI_STATUS_2,
+      DDI_TC3 => Registers.TCSS_DDI_STATUS_3,
+      DDI_TC4 => Registers.TCSS_DDI_STATUS_4);
+
+   TCSS_DDI_STATUS_HPD_LIVE_STATUS_ALT : constant := 1 * 2 ** 0;
+   TCSS_DDI_STATUS_READY               : constant := 1 * 2 ** 2;
+
    procedure Claim
      (Port     : in     USBC_Port;
       DP_Alt   : in     Boolean;
       Success  :    out Boolean)
    is
    begin
-      Success := False;
+      pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+      if Port not in Valid_TC_Port then
+         Success := False;
+         return;
+      end if;
+
+      if not DP_Alt then
+         -- For legacy ports, this is supposed
+         -- to be initialized once during boot.
+         Registers.Wait_Set_Mask
+           (Register => TCSS_DDI_STATUS (Port),
+            Mask     => TCSS_DDI_STATUS_READY,
+            TOut_MS  => 100);
+      end if;
+
+      Registers.Is_Set_Mask
+        (Register => TCSS_DDI_STATUS (Port),
+         Mask     => TCSS_DDI_STATUS_READY,
+         Result   => Success);
+      if not Success then
+         pragma Debug (Debug.Put_Line ("DP PHY mode status not complete"));
+         return;
+      end if;
+
+      Registers.Set_Mask
+        (Register => DDI_BUF_CTL (Port),
+         Mask     => DDI_BUF_CTL_TC_PHY_OWNERSHIP);
    end Claim;
 
-   procedure Claimed (Port : USBC_Port; Is_Claimed : out Boolean) is
+   procedure Claimed (Port : USBC_Port; Is_Claimed : out Boolean)
+   with
+      Refined_Post => (if Is_Claimed then Port in Valid_TC_Port)
+   is
    begin
-      Is_Claimed := False;
+      if Port not in Valid_TC_Port then
+         Is_Claimed := False;
+         return;
+      end if;
+
+      Registers.Is_Set_Mask
+        (Register => DDI_BUF_CTL (Port),
+         Mask     => DDI_BUF_CTL_TC_PHY_OWNERSHIP,
+         Result   => Is_Claimed);
    end Claimed;
 
    ---------------------------------------------------------------------
@@ -42,10 +96,42 @@
       Lanes    : in     DP_Lane_Count;
       Success  :    out Boolean)
    is
+      Assigned_Lanes : DP_Lane_Count;
    begin
-      Success := False;
+      pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+      Claimed (Port, Success);
+      if not Success then
+         pragma Debug (Debug.Put_Line ("Tried to connect to unclaimed port."));
+         return;
+      end if;
+
+      if DP_Alt then
+         Registers.Is_Set_Mask
+           (Register => TCSS_DDI_STATUS (Port),
+            Mask     => TCSS_DDI_STATUS_HPD_LIVE_STATUS_ALT,
+            Result   => Success);
+         if not Success then
+            pragma Debug (Debug.Put_Line ("DP-Alt is not connected."));
+            return;
+         end if;
+
+         Get_Lane_Assignment_Count (Port, Assigned_Lanes);
+         Set_Lane_Count (Port, Assigned_Lanes);
+      else
+         Set_Lane_Count (Port, Lanes);
+      end if;
    end Connect;
 
-   procedure Disconnect (Port : USBC_Port) is null;
+   procedure Disconnect (Port : USBC_Port) is
+   begin
+      pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+      if Port in Valid_TC_Port then
+         Registers.Unset_Mask
+           (Register => DDI_BUF_CTL (Port),
+            Mask     => DDI_BUF_CTL_TC_PHY_OWNERSHIP);
+      end if;
+   end Disconnect;
 
 end HW.GFX.GMA.Connectors.TC.Ownership;