gma tgl: Add connector programming
This patch adds support for enabling displays on both combo PHY ports
and Type-C ports over DP-Alt mode.
Verified eDP, HDMI (not Type-C), and DP Alt mode on google/delbin.
Change-Id: I908e8bef8451d21eecde9ce6defddc2b3df7f738
Signed-off-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.sourcearcade.org/c/libgfxinit/+/469
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: Nico Huber <nico.h@gmx.de>
diff --git a/common/tigerlake/hw-gfx-gma-connectors-combo_phy.adb b/common/tigerlake/hw-gfx-gma-connectors-combo_phy.adb
new file mode 100644
index 0000000..057f221
--- /dev/null
+++ b/common/tigerlake/hw-gfx-gma-connectors-combo_phy.adb
@@ -0,0 +1,569 @@
+--
+-- Copyright (C) 2022 Google, LLC
+--
+-- 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; either version 2 of the License, or
+-- (at your option) any later version.
+--
+-- 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.GFX.DP_Training;
+with HW.GFX.GMA.Config;
+with HW.GFX.GMA.DP_Aux_Ch;
+with HW.GFX.GMA.Registers;
+
+with HW.Debug;
+with GNAT.Source_Info;
+
+package body HW.GFX.GMA.Connectors.Combo_Phy is
+
+ 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 : constant array (Combo_Port) of Registers.Registers_Index :=
+ (DIGI_A => Registers.DDI_BUF_CTL_A,
+ DIGI_B => Registers.DDI_BUF_CTL_B,
+ DIGI_C => Registers.DDI_BUF_CTL_C);
+
+ 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);
+
+ type Port_Regs_Record is record
+ PORT_TX_DW5_LN0 : Registers.Registers_Index;
+ PORT_TX_DW5_GRP : Registers.Registers_Index;
+ PORT_TX_DW7_LN0 : Registers.Registers_Index;
+ PORT_TX_DW7_GRP : Registers.Registers_Index;
+ PORT_TX_DW2_LN0 : Registers.Registers_Index;
+ PORT_TX_DW2_GRP : Registers.Registers_Index;
+ PORT_TX_DW4_LN0 : Registers.Registers_Index;
+ PORT_TX_DW4_LN1 : Registers.Registers_Index;
+ PORT_TX_DW4_LN2 : Registers.Registers_Index;
+ PORT_TX_DW4_LN3 : Registers.Registers_Index;
+ PORT_TX_DW4_GRP : Registers.Registers_Index;
+ PORT_PCS_DW1_LN0 : Registers.Registers_Index;
+ PORT_PCS_DW1_GRP : Registers.Registers_Index;
+ PORT_CL_DW5 : Registers.Registers_Index;
+ PORT_CL_DW10 : Registers.Registers_Index;
+ DDI_BUF_CTL : Registers.Registers_Index;
+ end record;
+
+ Port_Regs : constant array (Combo_Port) of Port_Regs_Record :=
+ (DIGI_A =>
+ (Registers.PORT_TX_DW5_LN0_A, Registers.PORT_TX_DW5_GRP_A,
+ Registers.PORT_TX_DW7_LN0_A, Registers.PORT_TX_DW7_GRP_A,
+ Registers.PORT_TX_DW2_LN0_A, Registers.PORT_TX_DW2_GRP_A,
+ Registers.PORT_TX_DW4_LN0_A, Registers.PORT_TX_DW4_LN1_A,
+ Registers.PORT_TX_DW4_LN2_A, Registers.PORT_TX_DW4_LN3_A,
+ Registers.PORT_TX_DW4_GRP_A,
+ Registers.PORT_PCS_DW1_LN0_A, Registers.PORT_PCS_DW1_GRP_A,
+ Registers.PORT_CL_DW5_A,
+ Registers.PORT_CL_DW10_A,
+ Registers.DDI_BUF_CTL_A),
+ DIGI_B =>
+ (Registers.PORT_TX_DW5_LN0_B, Registers.PORT_TX_DW5_GRP_B,
+ Registers.PORT_TX_DW7_LN0_B, Registers.PORT_TX_DW7_GRP_B,
+ Registers.PORT_TX_DW2_LN0_B, Registers.PORT_TX_DW2_GRP_B,
+ Registers.PORT_TX_DW4_LN0_B, Registers.PORT_TX_DW4_LN1_B,
+ Registers.PORT_TX_DW4_LN2_B, Registers.PORT_TX_DW4_LN3_B,
+ Registers.PORT_TX_DW4_GRP_B,
+ Registers.PORT_PCS_DW1_LN0_B, Registers.PORT_PCS_DW1_GRP_B,
+ Registers.PORT_CL_DW5_B,
+ Registers.PORT_CL_DW10_B,
+ Registers.DDI_BUF_CTL_B),
+ DIGI_C =>
+ (Registers.PORT_TX_DW5_LN0_C, Registers.PORT_TX_DW5_GRP_C,
+ Registers.PORT_TX_DW7_LN0_C, Registers.PORT_TX_DW7_GRP_C,
+ Registers.PORT_TX_DW2_LN0_C, Registers.PORT_TX_DW2_GRP_C,
+ Registers.PORT_TX_DW4_LN0_C, Registers.PORT_TX_DW4_LN1_C,
+ Registers.PORT_TX_DW4_LN2_C, Registers.PORT_TX_DW4_LN3_C,
+ Registers.PORT_TX_DW4_GRP_C,
+ Registers.PORT_PCS_DW1_LN0_C, Registers.PORT_PCS_DW1_GRP_C,
+ Registers.PORT_CL_DW5_C,
+ Registers.PORT_CL_DW10_C,
+ Registers.DDI_BUF_CTL_C));
+
+ type Lanes is (LN0, LN1, LN2, LN3);
+ function PORT_TX_DW4 (Lane : Lanes; Port : Combo_Port)
+ return Registers.Registers_Index
+ is (case Lane is
+ when LN0 => Port_Regs (Port).PORT_TX_DW4_LN0,
+ when LN1 => Port_Regs (Port).PORT_TX_DW4_LN1,
+ when LN2 => Port_Regs (Port).PORT_TX_DW4_LN2,
+ when LN3 => Port_Regs (Port).PORT_TX_DW4_LN3);
+
+ PORT_PCS_DW1_LN0_COMMON_KEEPER : constant := 1 * 2 ** 26;
+
+ type Post_Cursor is new Natural range 0 .. 63;
+ function PORT_TX_DW4_POST_CURSOR1 (P : Post_Cursor) return Word32 is
+ (Shift_Left (Word32 (P), 12));
+
+ type Cursor_Coeff is new Natural range 0 .. 63;
+ function PORT_TX_DW4_CURSOR_COEFF (C : Cursor_Coeff) return Word32 is
+ (Word32 (C));
+
+ type N_Scalar is new Natural range 0 .. 127;
+ function PORT_TX_DW7_N_SCALAR (N : N_Scalar) return Word32 is
+ (Shift_Left (Word32 (N), 24));
+
+ type Swing_Select is new Natural range 0 .. 15;
+ function PORT_TX_SWING_SEL_UPPER (S : Swing_Select) return Word32 is
+ (Shift_Left (Shift_Right (Word32(S), 3), 15));
+ function PORT_TX_SWING_SEL_LOWER (S : Swing_Select) return Word32 is
+ (Shift_Left (Word32(S), 11));
+
+ type Buffer_Trans is record
+ DW2_SWING_SEL : Swing_Select;
+ DW7_N_SCALAR : N_Scalar;
+ DW4_CURSOR_COEFF : Cursor_Coeff;
+ DW4_POST_CURSOR1 : Post_Cursor;
+ end record;
+
+ type Buffer_Trans_HDMI_Range is new Natural range 0 .. 6;
+ Buffer_Trans_HDMI : constant array (Buffer_Trans_HDMI_Range) of Buffer_Trans :=
+ ((16#A#, 16#60#, 16#3F#, 16#00#),
+ (16#B#, 16#73#, 16#36#, 16#09#),
+ (16#6#, 16#7F#, 16#31#, 16#0E#),
+ (16#B#, 16#73#, 16#3F#, 16#00#),
+ (16#6#, 16#7F#, 16#37#, 16#08#),
+ (16#6#, 16#7F#, 16#3F#, 16#00#),
+ (16#6#, 16#7F#, 16#35#, 16#0A#));
+
+ type Buffer_Trans_DP_Range is new Natural range 0 .. 9;
+ type Buffer_Trans_DP_Array is array (Buffer_Trans_DP_Range) of Buffer_Trans;
+
+ TGL_Buffer_Trans_DP_HBR : constant Buffer_Trans_DP_Array :=
+ ((16#a#, 16#32#, 16#3f#, 16#00#),
+ (16#a#, 16#4f#, 16#37#, 16#08#),
+ (16#c#, 16#71#, 16#2f#, 16#10#),
+ (16#6#, 16#7d#, 16#2b#, 16#14#),
+ (16#a#, 16#4c#, 16#3f#, 16#00#),
+ (16#c#, 16#73#, 16#34#, 16#0b#),
+ (16#6#, 16#7f#, 16#2f#, 16#10#),
+ (16#c#, 16#6c#, 16#3c#, 16#03#),
+ (16#6#, 16#7f#, 16#35#, 16#0a#),
+ (16#6#, 16#7f#, 16#3f#, 16#00#));
+
+ TGL_Buffer_Trans_DP_HBR2 : constant Buffer_Trans_DP_Array :=
+ ((16#a#, 16#35#, 16#3f#, 16#00#),
+ (16#a#, 16#4f#, 16#37#, 16#08#),
+ (16#c#, 16#63#, 16#2f#, 16#10#),
+ (16#6#, 16#7f#, 16#2b#, 16#14#),
+ (16#a#, 16#47#, 16#3f#, 16#00#),
+ (16#c#, 16#63#, 16#34#, 16#0b#),
+ (16#6#, 16#7f#, 16#2f#, 16#10#),
+ (16#c#, 16#61#, 16#3c#, 16#03#),
+ (16#6#, 16#7b#, 16#35#, 16#0a#),
+ (16#6#, 16#7f#, 16#3f#, 16#00#));
+
+ TGL_Buffer_Trans_DP_HBR2_U_Y : constant Buffer_Trans_DP_Array :=
+ ((16#a#, 16#35#, 16#3f#, 16#00#),
+ (16#a#, 16#4f#, 16#36#, 16#09#),
+ (16#c#, 16#60#, 16#32#, 16#0d#),
+ (16#c#, 16#7f#, 16#2d#, 16#12#),
+ (16#c#, 16#47#, 16#3f#, 16#00#),
+ (16#c#, 16#6f#, 16#36#, 16#09#),
+ (16#6#, 16#7d#, 16#32#, 16#0d#),
+ (16#6#, 16#60#, 16#3c#, 16#03#),
+ (16#6#, 16#7f#, 16#34#, 16#0b#),
+ (16#6#, 16#7f#, 16#3f#, 16#00#));
+
+ TGL_Buffer_Trans_DP_HBR2_EDP_HBR3 : constant Buffer_Trans_DP_Array :=
+ ((16#a#, 16#35#, 16#3f#, 16#00#),
+ (16#a#, 16#4f#, 16#37#, 16#08#),
+ (16#c#, 16#71#, 16#2f#, 16#10#),
+ (16#6#, 16#7f#, 16#2b#, 16#14#),
+ (16#a#, 16#4c#, 16#3f#, 16#00#),
+ (16#c#, 16#73#, 16#34#, 16#0b#),
+ (16#6#, 16#7f#, 16#2f#, 16#10#),
+ (16#c#, 16#6c#, 16#3c#, 16#03#),
+ (16#6#, 16#7f#, 16#35#, 16#0a#),
+ (16#6#, 16#7f#, 16#3f#, 16#00#));
+
+ TGL_Buffer_Trans_EDP_HBR2 : constant Buffer_Trans_DP_Array :=
+ ((16#0#, 16#7F#, 16#3F#, 16#00#),
+ (16#8#, 16#7F#, 16#38#, 16#07#),
+ (16#1#, 16#7F#, 16#33#, 16#0C#),
+ (16#9#, 16#7F#, 16#31#, 16#0E#),
+ (16#8#, 16#7F#, 16#3F#, 16#00#),
+ (16#1#, 16#7F#, 16#38#, 16#07#),
+ (16#9#, 16#7F#, 16#35#, 16#0A#),
+ (16#1#, 16#7F#, 16#3F#, 16#00#),
+ (16#9#, 16#7F#, 16#38#, 16#07#),
+ (16#9#, 16#7F#, 16#3F#, 16#00#));
+
+ ADL_Buffer_Trans_EDP_HBR3 : constant Buffer_Trans_DP_Array :=
+ ((16#a#, 16#35#, 16#3f#, 16#00#),
+ (16#a#, 16#4f#, 16#37#, 16#08#),
+ (16#c#, 16#71#, 16#30#, 16#0f#),
+ (16#6#, 16#7f#, 16#2b#, 16#14#),
+ (16#a#, 16#4c#, 16#3f#, 16#00#),
+ (16#c#, 16#73#, 16#34#, 16#0b#),
+ (16#6#, 16#7f#, 16#30#, 16#0f#),
+ (16#c#, 16#63#, 16#3f#, 16#00#),
+ (16#6#, 16#7f#, 16#38#, 16#07#),
+ (16#6#, 16#7f#, 16#3f#, 16#00#));
+
+ ADL_Buffer_Trans_EDP_HBR2 : constant Buffer_Trans_DP_Array :=
+ ((16#4#, 16#50#, 16#38#, 16#07#),
+ (16#4#, 16#58#, 16#35#, 16#0a#),
+ (16#4#, 16#60#, 16#34#, 16#0b#),
+ (16#4#, 16#6a#, 16#32#, 16#0d#),
+ (16#4#, 16#5e#, 16#38#, 16#07#),
+ (16#4#, 16#61#, 16#36#, 16#09#),
+ (16#4#, 16#6b#, 16#34#, 16#0b#),
+ (16#4#, 16#69#, 16#39#, 16#06#),
+ (16#4#, 16#73#, 16#37#, 16#08#),
+ (16#4#, 16#7a#, 16#38#, 16#07#));
+
+ ADL_Buffer_Trans_DP_HBR3 : constant Buffer_Trans_DP_Array :=
+ ((16#a#, 16#35#, 16#3f#, 16#00#),
+ (16#a#, 16#4f#, 16#37#, 16#08#),
+ (16#c#, 16#71#, 16#30#, 16#0f#),
+ (16#6#, 16#7f#, 16#2b#, 16#14#),
+ (16#a#, 16#4c#, 16#3f#, 16#00#),
+ (16#c#, 16#73#, 16#34#, 16#0b#),
+ (16#6#, 16#7f#, 16#30#, 16#0f#),
+ (16#c#, 16#63#, 16#3f#, 16#00#),
+ (16#6#, 16#7f#, 16#38#, 16#07#),
+ (16#6#, 16#7f#, 16#3f#, 16#00#));
+
+ ADL_Buffer_Trans_DP_HBR : constant Buffer_Trans_DP_Array :=
+ ((16#a#, 16#35#, 16#3f#, 16#00#),
+ (16#a#, 16#4f#, 16#37#, 16#08#),
+ (16#c#, 16#71#, 16#31#, 16#0e#),
+ (16#6#, 16#7f#, 16#2c#, 16#13#),
+ (16#a#, 16#4c#, 16#3f#, 16#00#),
+ (16#c#, 16#73#, 16#34#, 16#0b#),
+ (16#6#, 16#7f#, 16#2f#, 16#10#),
+ (16#c#, 16#7c#, 16#3c#, 16#03#),
+ (16#6#, 16#7f#, 16#35#, 16#0a#),
+ (16#6#, 16#7f#, 16#3f#, 16#00#));
+
+ PORT_CL_DW10_PWR_DOWN_LN_MASK : constant := 16#f# * 2 ** 4;
+ PORT_CL_DW10_PWR_UP_ALL : constant := 0 * 2 ** 4;
+ PORT_CL_DW10_PWR_DOWN_LN_3_2 : constant := 16#c# * 2 ** 4;
+ PORT_CL_DW10_PWR_DOWN_LN_3_2_1 : constant := 16#e# * 2 ** 4;
+ PORT_CL_DW10_PWR_DOWN_LN_1_0 : constant := 16#3# * 2 ** 4;
+ PORT_CL_DW10_PWR_DOWN_LN_2_1_0 : constant := 16#7# * 2 ** 4;
+
+ EDP4K2K_MODE_OVRD_EN : constant := 1 * 2 ** 2;
+ EDP4K2K_MODE_OVRD_OPTIMIZED : constant := 1 * 2 ** 3;
+
+ ---------------------------------------------------------------------
+
+ procedure Set_Vswing_And_Deemphasis
+ (Port : Combo_Port;
+ Buf_Trans : Buffer_Trans;
+ Display : Display_Type;
+ Lane_Count : DP_Lane_Count)
+ is
+ type Training_Values is (Training_Enable, Training_Disable);
+
+ PORT_TX_DW5_TX_TRAINING_EN : constant := 1 * 2 ** 31;
+ PORT_TX_DW5_SCALING_MODE_SEL_MASK : constant := 7 * 2 ** 18;
+ PORT_TX_DW5_RTERM_SELECT_MASK : constant := 7 * 2 ** 3;
+ PORT_TX_DW5_TAP2_DISABLE : constant := 1 * 2 ** 30;
+ PORT_TX_DW5_TAP3_DISABLE : constant := 1 * 2 ** 29;
+ PORT_TX_DW5_CURSOR_PROGRAM : constant := 1 * 2 ** 26;
+ PORT_TX_DW5_COEFF_POLARITY : constant := 1 * 2 ** 25;
+
+ PORT_TX_DW2_RCOMP_SCALAR_MASK : constant := 16#ff# * 2 ** 0;
+ PORT_TX_DW2_SWING_SEL_LOWER_MASK : constant := 7 * 2 ** 11;
+ PORT_TX_DW2_SWING_SEL_UPPER : constant := 1 * 2 ** 15;
+
+ PORT_TX_DW4_LOADGEN_SELECT : constant := 1 * 2 ** 31;
+ PORT_TX_DW4_POST_CURSOR2_MASK : constant := 16#3f# * 2 ** 6;
+ PORT_TX_DW4_POST_CURSOR1_MASK : constant := 16#3f# * 2 ** 12;
+ PORT_TX_DW4_CURSOR_COEFF_MASK : constant := 16#3f# * 2 ** 0;
+
+ PORT_TX_DW7_N_SCALAR_MASK : constant := 16#7f# * 2 ** 24;
+
+ type Scaling_Mode is new Natural range 0 .. 7;
+ function PORT_TX_DW5_SCALING_MODE_SEL (S : Scaling_Mode) return Word32 is
+ (Shift_Left (Word32 (S), 18));
+
+ type Rterm_Select is new Natural range 0 .. 7;
+ function PORT_TX_DW5_RTERM_SELECT (R : Rterm_Select) return Word32 is
+ (Shift_Left (Word32 (R), 3));
+
+ type Rcomp_Scalar is new Natural range 0 .. 255;
+ function PORT_TX_DW2_RCOMP_SCALAR (R : Rcomp_Scalar) return Word32 is
+ (Word32 (R));
+
+ procedure Set_Tx_Training (Port : Combo_Port; Training : Training_Values) is
+ DW5 : Word32;
+ begin
+ Registers.Read (Port_Regs (Port).PORT_TX_DW5_LN0, DW5);
+ Registers.Write
+ (Register => Port_Regs (Port).PORT_TX_DW5_GRP,
+ Value => (if Training = Training_Enable
+ then DW5 or PORT_TX_DW5_TX_TRAINING_EN
+ else DW5 and not PORT_TX_DW5_TX_TRAINING_EN));
+ end Set_Tx_Training;
+
+ Tmp : Word32;
+ PORT_CL_DW5_SUS_CLOCK_CONFIG : constant := 3 * 2 ** 0;
+ begin
+ -- Enable common keeper for DP/eDP only
+ Registers.Read (Port_Regs (Port).PORT_PCS_DW1_LN0, Tmp);
+ Registers.Write
+ (Port_Regs (Port).PORT_PCS_DW1_GRP,
+ (if Display = DP
+ then Tmp or PORT_PCS_DW1_LN0_COMMON_KEEPER
+ else Tmp and not PORT_PCS_DW1_LN0_COMMON_KEEPER));
+
+ -- Program loadgen select (group access is not allowed since each lane may
+ -- have a unique value.
+ -- <= 6GHz, 4 lanes (0, 1, 1, 1)
+ -- <= 6GHz, 1,2 lanes (0, 1, 1, 0)
+ -- > 6GHz, any lanes (0, 0, 0, 0)
+ for Lane in Lanes loop
+ if (Lane_Count = DP_Lane_Count_4 and Lane /= LN0) or
+ (Lane_Count /= DP_Lane_Count_4 and (Lane = LN1 or Lane = LN2))
+ then
+ Registers.Set_Mask (PORT_TX_DW4 (Lane, Port),
+ PORT_TX_DW4_LOADGEN_SELECT);
+ else
+ Registers.Unset_Mask (PORT_TX_DW4 (Lane, Port),
+ PORT_TX_DW4_LOADGEN_SELECT);
+ end if;
+ end loop;
+
+ Registers.Set_Mask
+ (Register => Port_Regs (Port).PORT_CL_DW5,
+ Mask => PORT_CL_DW5_SUS_CLOCK_CONFIG);
+
+ -- In order to change swing values, training must be disabled
+ Set_Tx_Training (Port, Training_Disable);
+
+ if Display = DP then
+ Registers.Unset_Mask
+ (Register => Port_Regs (Port).PORT_CL_DW10,
+ Mask => EDP4K2K_MODE_OVRD_EN or EDP4K2K_MODE_OVRD_OPTIMIZED);
+ end if;
+
+ Registers.Read (Port_Regs (Port).PORT_TX_DW5_LN0, Tmp);
+ Tmp := Tmp and not
+ (PORT_TX_DW5_SCALING_MODE_SEL_MASK or
+ PORT_TX_DW5_RTERM_SELECT_MASK or
+ PORT_TX_DW5_TAP2_DISABLE or
+ PORT_TX_DW5_TAP3_DISABLE or
+ PORT_TX_DW5_CURSOR_PROGRAM or
+ PORT_TX_DW5_COEFF_POLARITY);
+ Tmp := Tmp or
+ PORT_TX_DW5_SCALING_MODE_SEL (2) or
+ PORT_TX_DW5_RTERM_SELECT (6) or
+ PORT_TX_DW5_TAP3_DISABLE;
+ Registers.Write (Port_Regs (Port).PORT_TX_DW5_GRP, Tmp);
+
+ Registers.Read (Port_Regs (Port).PORT_TX_DW2_LN0, Tmp);
+ Tmp := Tmp and not
+ (PORT_TX_DW2_RCOMP_SCALAR_MASK or
+ PORT_TX_DW2_SWING_SEL_LOWER_MASK or
+ PORT_TX_DW2_SWING_SEL_UPPER);
+ Tmp := Tmp or PORT_TX_SWING_SEL_UPPER (Buf_Trans.DW2_SWING_SEL);
+ Tmp := Tmp or PORT_TX_SWING_SEL_LOWER (Buf_Trans.DW2_SWING_SEL);
+ Tmp := Tmp or PORT_TX_DW2_RCOMP_SCALAR (16#98#);
+ Registers.Write (Port_Regs (Port).PORT_TX_DW2_GRP, Tmp);
+
+ -- Cannot write to GRP, because it would overwrite individual loadgen bits
+ for Lane in Lanes loop
+ Registers.Read (PORT_TX_DW4 (Lane, Port), Tmp);
+ Tmp := Tmp and not
+ (PORT_TX_DW4_POST_CURSOR2_MASK or
+ PORT_TX_DW4_POST_CURSOR1_MASK or
+ PORT_TX_DW4_CURSOR_COEFF_MASK);
+ Tmp := Tmp or PORT_TX_DW4_POST_CURSOR1 (Buf_Trans.DW4_POST_CURSOR1);
+ Tmp := Tmp or PORT_TX_DW4_CURSOR_COEFF (Buf_Trans.DW4_CURSOR_COEFF);
+ Registers.Write (PORT_TX_DW4 (Lane, Port), Tmp);
+ end loop;
+
+ Registers.Read (Port_Regs (Port).PORT_TX_DW7_LN0, Tmp);
+ Tmp := Tmp and not PORT_TX_DW7_N_SCALAR_MASK;
+ Tmp := Tmp or PORT_TX_DW7_N_SCALAR (Buf_Trans.DW7_N_SCALAR);
+ Registers.Write (Port_Regs (Port).PORT_TX_DW7_GRP, Tmp);
+
+ -- To trigger an update of swing values, set training enable
+ Set_Tx_Training (Port, Training_Enable);
+ end Set_Vswing_And_Deemphasis;
+
+ ---------------------------------------------------------------------
+
+ procedure Power_Up_Lanes
+ (Port : Combo_Port;
+ Lane_Count : DP_Lane_Count)
+ is
+ Lane_Mask : constant Word32 :=
+ (case Lane_Count is
+ -- if Lane_Reversal then PWR_DOWN_LN_2_1_0
+ -- else PORT_CL_DW10_PWR_DOWN_LN_3_2_1
+ when DP_Lane_Count_1 => PORT_CL_DW10_PWR_DOWN_LN_3_2_1,
+ -- if Lane_Reversal then PWR_DOWN_1_0
+ -- else PORT_CL_DW10_PWR_DOWN_LN_3_2
+ when DP_Lane_Count_2 => PORT_CL_DW10_PWR_DOWN_LN_3_2,
+ when others => PORT_CL_DW10_PWR_UP_ALL);
+ begin
+ Registers.Unset_And_Set_Mask
+ (Register => Port_Regs (Port).PORT_CL_DW10,
+ Mask_Unset => PORT_CL_DW10_PWR_DOWN_LN_MASK,
+ Mask_Set => Lane_Mask);
+ end Power_Up_Lanes;
+
+ ---------------------------------------------------------------------
+
+ procedure Set_Signal_Levels
+ (Port : Combo_Port;
+ eDP : Boolean;
+ Link : DP_Link;
+ Train_Set : DP_Info.Train_Set)
+ is
+ function Get_Buf_Trans_Table
+ (eDP : Boolean) return Buffer_Trans_DP_Array is
+ begin
+ if Config.Has_TGL_Buffer_Translations then
+ if eDP then
+ if Link.Bandwidth > DP_Bandwidth_5_4 then
+ return TGL_Buffer_Trans_DP_HBR2_EDP_HBR3;
+ else
+ return TGL_Buffer_Trans_DP_HBR;
+ end if;
+ else
+ if Link.Bandwidth > DP_Bandwidth_2_7 then
+ if Config.Is_LP then
+ return TGL_Buffer_Trans_DP_HBR2_U_Y;
+ else
+ return TGL_Buffer_Trans_DP_HBR2;
+ end if;
+ else
+ return TGL_Buffer_Trans_DP_HBR;
+ end if;
+ end if;
+ else
+ if eDP then
+ if Link.Bandwidth > DP_Bandwidth_5_4 then
+ return ADL_Buffer_Trans_EDP_HBR3;
+ else
+ return ADL_Buffer_Trans_DP_HBR; -- EDP_HBR2 ?
+ end if;
+ else
+ if Link.Bandwidth > DP_Bandwidth_2_7 then
+ return ADL_Buffer_Trans_DP_HBR3;
+ else
+ return ADL_Buffer_Trans_DP_HBR;
+ end if;
+ end if;
+ end if;
+ end Get_Buf_Trans_Table;
+
+ function To_Buf_Trans_Index
+ (Set : DP_Info.Train_Set) return Buffer_Trans_DP_Range
+ is
+ begin
+ case Set.Voltage_Swing is
+ when DP_Info.VS_Level_0 =>
+ case Set.Pre_Emph is
+ when DP_Info.Emph_Level_0 => return 0;
+ when DP_Info.Emph_Level_1 => return 1;
+ when DP_Info.Emph_Level_2 => return 2;
+ when DP_Info.Emph_Level_3 => return 3;
+ end case;
+ when DP_Info.VS_Level_1 =>
+ case Set.Pre_Emph is
+ when DP_Info.Emph_Level_0 => return 4;
+ when DP_Info.Emph_Level_1 => return 5;
+ when DP_Info.Emph_Level_2 => return 6;
+ when others => return 0;
+ end case;
+ when DP_Info.VS_Level_2 =>
+ case Set.Pre_Emph is
+ when DP_Info.Emph_Level_0 => return 7;
+ when DP_Info.Emph_Level_1 => return 8;
+ when others => return 0;
+ end case;
+ when DP_Info.VS_Level_3 =>
+ case Set.Pre_Emph is
+ when DP_Info.Emph_Level_0 => return 9;
+ when others => return 0;
+ end case;
+ end case;
+ end To_Buf_Trans_Index;
+
+ Was_Enabled : Boolean;
+ Buf_Trans : Buffer_Trans;
+ Entry_Index : constant Buffer_Trans_DP_Range :=
+ To_Buf_Trans_Index (Train_Set);
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ Registers.Is_Set_Mask
+ (Register => Port_Regs (Port).DDI_BUF_CTL,
+ Mask => DDI_BUF_CTL_BUFFER_ENABLE,
+ Result => Was_Enabled);
+
+ Buf_Trans := Get_Buf_Trans_Table (eDP) (Entry_Index);
+
+ Set_Vswing_And_Deemphasis
+ (Port => Port,
+ Buf_Trans => Buf_Trans,
+ Display => DP,
+ Lane_Count => Link.Lane_Count);
+
+ if not Was_Enabled then
+ Power_Up_Lanes (Port, Link.Lane_Count);
+ end if;
+
+ Registers.Unset_And_Set_Mask
+ (Register => Port_Regs (Port).DDI_BUF_CTL,
+ 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));
+ Registers.Posting_Read (Port_Regs (Port).DDI_BUF_CTL);
+
+ if not Was_Enabled then
+ Registers.Wait_Unset_Mask (Port_Regs (Port).DDI_BUF_CTL, DDI_BUF_CTL_IDLE_STATUS);
+ end if;
+ end Set_Signal_Levels;
+
+ ---------------------------------------------------------------------
+
+ procedure Enable_HDMI (Port : Combo_Port)
+ is
+ HDMI_Lane_Count : constant DP_Lane_Count := DP_Lane_Count_4;
+ begin
+ Set_Vswing_And_Deemphasis
+ (Port => Port,
+ Buf_Trans => Buffer_Trans_HDMI (Buffer_Trans_HDMI'First),
+ Display => HDMI,
+ Lane_Count => HDMI_Lane_Count);
+
+ Power_Up_Lanes (Port, HDMI_Lane_Count);
+
+ 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);
+
+ Registers.Wait_Unset_Mask
+ (Register => DDI_BUF_CTL (Port),
+ Mask => DDI_BUF_CTL_IDLE_STATUS,
+ TOut_MS => 1);
+ end Enable_HDMI;
+
+end HW.GFX.GMA.Connectors.Combo_Phy;