gma adl: Add missing Alder Lake TC bits

Add some missing ADL-P handling and workarounds for TC ports.

* Ownership is handled in DDI_BUF_CTL (Need_TC_PHY_Ownership).
* Additional "Loadgen" selection is needed in DKL PHY
  configuration (Need_TC_Loadgen_Select).
* Explicit blocking of TC cold state is not needed (Block_TC_Cold).
* A workaround is needed to avoid PHYs hanging when switching from
  TBT mode to DP-alt/legacy mode (Need_TBT_DP_Alt_Switch_Wa).

This is based on work by several authors that was originally
squashed into another commit:
https://review.coreboot.org/c/libgfxinit/+/67801/

Change-Id: I32fd558c27f4f9658aea799f1b6c679be4d31feb
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/libgfxinit/+/507
Reviewed-by: Thomas Heijligen <src@posteo.de>
Tested-by: Ada SPARK <gnatbot@sourcearcade.org>
diff --git a/common/hw-gfx-gma-config.ads.template b/common/hw-gfx-gma-config.ads.template
index 5801bfe..43c43d5 100644
--- a/common/hw-gfx-gma-config.ads.template
+++ b/common/hw-gfx-gma-config.ads.template
@@ -352,6 +352,10 @@
 
    ----------- Type-C: ----------
    Has_Type_C_Ports              : <genbool> := Tigerlake_On;
+   Need_TC_PHY_Ownership         : <genbool> := AlderlakeP_On;
+   Need_TC_Loadgen_Select        : <genbool> := AlderlakeP_On;
+   Need_TBT_DP_Alt_Switch_Wa     : <genbool> := AlderlakeP_On;
+   Block_TC_Cold                 : <genbool> := Gen_Tigerlake;
 
    ----------- Rawclk -----------
    Need_Rawclk_Numerator         : <genbool> := Tigerlake_On;
diff --git a/common/tigerlake/hw-gfx-gma-connectors-tc.adb b/common/tigerlake/hw-gfx-gma-connectors-tc.adb
index 84eb4b0..ca87fff 100644
--- a/common/tigerlake/hw-gfx-gma-connectors-tc.adb
+++ b/common/tigerlake/hw-gfx-gma-connectors-tc.adb
@@ -28,7 +28,8 @@
       then Registers.HIP_INDEX_REG0
       else Registers.HIP_INDEX_REG1);
 
-   function HIP_INDEX_VAL (P : USBC_Port; Val : Word32) return Word32 is
+   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)));
 
    DKL_DP_MODE : constant Port_Regs_Array :=
@@ -39,7 +40,15 @@
       DDI_TC5 => Registers.DKL_DP_MODE_5,
       DDI_TC6 => Registers.DKL_DP_MODE_6);
 
-   function DP_PIN_ASSIGNMENT_SHIFT (P : USBC_Port) return Natural is
+   DKL_PCS_DW5 : constant Port_Regs_Array :=
+     (DDI_TC1 => Registers.DKL_PCS_DW5_1,
+      DDI_TC2 => Registers.DKL_PCS_DW5_2,
+      DDI_TC3 => Registers.DKL_PCS_DW5_3,
+      DDI_TC4 => Registers.DKL_PCS_DW5_4,
+      others  => Registers.Invalid_Register);
+
+   function DP_PIN_ASSIGNMENT_SHIFT (P : USBC_Port) return Natural
+   is
      (case P is
       when DDI_TC1 => 0,
       when DDI_TC2 => 4,
@@ -303,8 +312,9 @@
    ---------------------------------------------------------------------
 
    procedure Set_Vswing_And_Deemphasis
-      (Port      : USBC_Port;
-       Buf_Trans : Buffer_Trans)
+     (Port        : USBC_Port;
+      Buf_Trans   : Buffer_Trans;
+      HDMI        : Boolean := False)
    is
       -- Preshoot Coeff, Deemphasis Coeff, VSwing Control,
       DPcnt_Mask : constant Word32 := 16#3_ff07#;
@@ -313,6 +323,17 @@
          Shift_Left (Buf_Trans.Deemphasis_Control, 8) or
          Shift_Left (Buf_Trans.Preshoot_Control, 13);
       DKL_TX_DP20BITMODE : constant := 1 * 2 ** 2;
+
+      function DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1 (N : Word32) return Word32
+      is
+        (Shift_Left (N and 16#3#, 3));
+
+      function DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2 (N : Word32) return Word32
+      is
+        (Shift_Left (N and 16#3#, 5));
+
+      DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK : constant := 16#18#;
+      DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK : constant := 16#60#;
    begin
       for Lane in 0 .. 1 loop
          Set_HIP_For_Port (Port, Lane);
@@ -323,6 +344,31 @@
             (Vswing_Regs (Port).DKL_TX_DPCNTL1, DPcnt_Mask, DPcnt_Val);
          Registers.Unset_Mask
             (Vswing_Regs (Port).DKL_TX_DPCNTL2, DKL_TX_DP20BITMODE);
+
+         if Config.Need_TC_Loadgen_Select then
+            declare
+               Val : Word32;
+            begin
+               if HDMI then
+                  if Lane = 0 then
+                     Val := DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1 (0) or
+                            DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2 (2);
+                  else
+                     Val := DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1 (3) or
+                            DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2 (3);
+                  end if;
+               else
+                  Val := DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1 (0) or
+                         DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2 (0);
+               end if;
+
+               Registers.Unset_And_Set_Mask
+                 (Register   => Vswing_Regs (Port).DKL_TX_DPCNTL2,
+                  Mask_Unset => DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK or
+                                DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK,
+                  Mask_Set   => Val);
+            end;
+         end if;
       end loop;
 
    end Set_Vswing_And_Deemphasis;
@@ -334,6 +380,7 @@
       Link        : DP_Link;
       Train_Set   : DP_Info.Train_Set)
    is
+      DKL_PCS_DW5_CORE_SOFTRESET : constant := 1 * 2 ** 11;
       function To_Buf_Trans_Index
          (Set : DP_Info.Train_Set) return Buffer_Trans_Range
       is
@@ -395,13 +442,29 @@
 
       Set_Vswing_And_Deemphasis (Port, Buf_Trans);
 
+      -- Wa_1309179469: Taken from i915's adlp_tbt_to_dp_alt_switch_wa()
+      if Config.Need_TBT_DP_Alt_Switch_Wa and then
+         Port in Valid_TC_Port and then
+         not Was_Enabled
+      then
+         for Lane in 0 .. 1 loop
+            Set_HIP_For_Port (Port, Lane);
+            Registers.Unset_Mask
+              (Register => DKL_PCS_DW5 (Port),
+               Mask     => DKL_PCS_DW5_CORE_SOFTRESET);
+         end loop;
+      end if;
+
       Registers.Unset_And_Set_Mask
         (Register    => DDI_BUF_CTL (Port),
          Mask_Unset  => DDI_BUF_CTL_TRANS_SELECT_MASK or
                         DDI_BUF_CTL_PORT_REVERSAL or
                         DDI_BUF_CTL_PORT_WIDTH_MASK,
          Mask_Set    => DDI_BUF_CTL_BUFFER_ENABLE or
-                        DDI_BUF_CTL_PORT_WIDTH (Link.Lane_Count));
+                        DDI_BUF_CTL_PORT_WIDTH (Link.Lane_Count) or
+                        (if Config.Need_TC_PHY_Ownership
+                         then DDI_BUF_CTL_TC_PHY_OWNERSHIP else 0));
+
       Registers.Posting_Read (DDI_BUF_CTL (Port));
 
       if not Was_Enabled then
@@ -416,7 +479,7 @@
          Buffer_Trans_HDMI (Buffer_Trans_HDMI'Last);
    begin
       Program_DP_Mode (Port, HDMI_Lane_Count);
-      Set_Vswing_And_Deemphasis (Port, Buf_Trans);
+      Set_Vswing_And_Deemphasis (Port, Buf_Trans, HDMI => True);
 
       Registers.Unset_And_Set_Mask
            (Register    => DDI_BUF_CTL (Port),
diff --git a/common/tigerlake/hw-gfx-gma-connectors-tc.ads b/common/tigerlake/hw-gfx-gma-connectors-tc.ads
index 9e637d0..6bebc73 100644
--- a/common/tigerlake/hw-gfx-gma-connectors-tc.ads
+++ b/common/tigerlake/hw-gfx-gma-connectors-tc.ads
@@ -36,7 +36,8 @@
    -- 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;
+   type Port_Regs_Array is
+      array (USBC_Port) of Registers.Registers_Invalid_Index;
 
    DDI_BUF_CTL_BUFFER_ENABLE        : constant :=      1 * 2 ** 31;
    DDI_BUF_CTL_TRANS_SELECT_MASK    : constant :=  16#f# * 2 ** 24;
diff --git a/common/tigerlake/hw-gfx-gma-port_detect.adb b/common/tigerlake/hw-gfx-gma-port_detect.adb
index 9c8c27b..3e9c605 100644
--- a/common/tigerlake/hw-gfx-gma-port_detect.adb
+++ b/common/tigerlake/hw-gfx-gma-port_detect.adb
@@ -117,10 +117,12 @@
       -- In order to avoid keeping track of the state and constantly
       -- blocking and unblocking, we just block it once at the beginning
       -- and leave it that way.
-      Connectors.TC.TC_Cold_Request (Connectors.TC.Block, Success);
-      if not Success then
-         Debug.Put_Line ("Failed to block TCCOLD, Type-C will not work!");
-         return;
+      if Config.Block_TC_Cold then
+         Connectors.TC.TC_Cold_Request (Connectors.TC.Block, Success);
+         if not Success then
+            Debug.Put_Line ("Failed to block TCCOLD, Type-C will not work!");
+            return;
+         end if;
       end if;
    end Initialize;