Attention is currently required from: Nico Huber, Tim Wawrzynczak.

Dinesh Gehlot would like Nico Huber and Tim Wawrzynczak to review this change.

View Change

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>
---
M common/hw-gfx-gma-config.ads.template
M common/hw-gfx-gma.adb
M common/hw-gfx-gma.ads
M common/tigerlake/Makefile.inc
A common/tigerlake/hw-gfx-gma-connectors-combo_phy.adb
A common/tigerlake/hw-gfx-gma-connectors-combo_phy.ads
A common/tigerlake/hw-gfx-gma-connectors-tc.adb
A common/tigerlake/hw-gfx-gma-connectors-tc.ads
M common/tigerlake/hw-gfx-gma-connectors.adb
M common/tigerlake/hw-gfx-gma-power_and_clocks.adb
10 files changed, 1,625 insertions(+), 16 deletions(-)

git pull ssh://review.coreboot.org:29418/libgfxinit refs/changes/44/82144/1
diff --git a/common/hw-gfx-gma-config.ads.template b/common/hw-gfx-gma-config.ads.template
index e168144..b56086f 100644
--- a/common/hw-gfx-gma-config.ads.template
+++ b/common/hw-gfx-gma-config.ads.template
@@ -312,6 +312,9 @@
----------- Rawclk -----------
Need_Rawclk_Numerator : <genbool> := Tigerlake_On;

+ ----------- Combo Phy --------
+ Has_TGL_Buffer_Translations : <tglbool> := CPU_Tigerlake;
+
----------------------------------------------------------------------------

Max_Pipe : <ilkvar> Pipe_Index :=
diff --git a/common/hw-gfx-gma.adb b/common/hw-gfx-gma.adb
index 6331020..2f58da3 100644
--- a/common/hw-gfx-gma.adb
+++ b/common/hw-gfx-gma.adb
@@ -652,12 +652,15 @@
(GNATprove, Off, """Registers.Register_State"" * is not modified*",
Reason => "Power_Up_VGA is only effective in certain configurations.");
pragma Warnings
+ (GNATprove, Off, """PCode.Mailbox_Ready"" * is not modified*",
+ Reason => "Pcode is only used in certain configurations.");
+ pragma Warnings
(GNATprove, Off, "no check message justified*", Reason => "see below");
procedure Power_Up_VGA
with
Refined_Global =>
(Input => (Cur_Configs, Config.Variable, Time.State),
- In_Out => (Registers.Register_State),
+ In_Out => (Registers.Register_State, PCode.Mailbox_Ready),
Proof_In => (Initialized))
is
Fake_Config : constant Pipe_Configs :=
@@ -677,6 +680,8 @@
pragma Annotate
(GNATprove, Intentional, "unused global",
"Power_Up_VGA is only effective in certain configurations.");
+ pragma Warnings
+ (GNATprove, On, """PCode.Mailbox_Ready"" * is not modified*");
pragma Warnings (GNATprove, On, "no check message justified*");
pragma Warnings
(GNATprove, On, """Registers.Register_State"" * is not modified*");
diff --git a/common/hw-gfx-gma.ads b/common/hw-gfx-gma.ads
index 8ef2247..2752cfa 100644
--- a/common/hw-gfx-gma.ads
+++ b/common/hw-gfx-gma.ads
@@ -145,8 +145,8 @@
procedure Power_Up_VGA
with
Global =>
- (Input => (State, Time.State),
- In_Out => (Device_State),
+ (Input => (Time.State),
+ In_Out => (Device_State, State),
Proof_In => (Init_State)),
Pre => Is_Initialized;

diff --git a/common/tigerlake/Makefile.inc b/common/tigerlake/Makefile.inc
index 86ed920..b76f2fe 100644
--- a/common/tigerlake/Makefile.inc
+++ b/common/tigerlake/Makefile.inc
@@ -3,6 +3,10 @@
gfxinit-y += hw-gfx-gma-power_and_clocks.adb
gfxinit-y += hw-gfx-gma-power_and_clocks.ads
gfxinit-y += hw-gfx-gma-connectors.adb
+gfxinit-y += hw-gfx-gma-connectors-tc.adb
+gfxinit-y += hw-gfx-gma-connectors-tc.ads
+gfxinit-y += hw-gfx-gma-connectors-combo_phy.adb
+gfxinit-y += hw-gfx-gma-connectors-combo_phy.ads
gfxinit-y += hw-gfx-gma-port_detect.adb
gfxinit-y += hw-gfx-gma-plls.adb
gfxinit-y += hw-gfx-gma-plls.ads
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..4f28a22
--- /dev/null
+++ b/common/tigerlake/hw-gfx-gma-connectors-combo_phy.adb
@@ -0,0 +1,586 @@
+--
+-- 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;
+
+ type Combo_Port_Regs is array (Combo_Port) of Registers.Registers_Index;
+ DDI_BUF_CTL : constant Combo_Port_Regs :=
+ Combo_Port_Regs'
+ (DIGI_A => Registers.DDI_BUF_CTL_A,
+ DIGI_B => Registers.DDI_BUF_CTL_B,
+ DIGI_C => Registers.DDI_BUF_CTL_C);
+
+ type DDI_BUF_CTL_PORT_WIDTH_T is array (HW.GFX.DP_Lane_Count) of Word32;
+ DDI_BUF_CTL_PORT_WIDTH : constant DDI_BUF_CTL_PORT_WIDTH_T :=
+ DDI_BUF_CTL_PORT_WIDTH_T'
+ (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;
+
+ type Port_Regs_Array is array (Combo_Port) of Port_Regs_Record;
+ Port_Regs : constant Port_Regs_Array :=
+ Port_Regs_Array'
+ (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);
+ type Lanes_Range is new Natural range 1 .. 4;
+ 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;
+ type Buffer_Trans_HDMI_Array is array (Buffer_Trans_HDMI_Range) of Buffer_Trans;
+ Buffer_Trans_HDMI : constant Buffer_Trans_HDMI_Array :=
+ Buffer_Trans_HDMI_Array'(
+ (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 :=
+ 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 :=
+ 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 :=
+ 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 :=
+ 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 :=
+ 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 :=
+ 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 :=
+ 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 :=
+ 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 :=
+ 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 : Lanes_Range)
+ 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 = 4 and Lane /= LN0) or
+ (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 : Lanes_Range)
+ 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 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 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,
+ Buf_Trans,
+ DP,
+ Lanes_Range (Lane_Count_As_Integer (Link.Lane_Count)));
+
+ if not Was_Enabled then
+ Power_Up_Lanes (Port, Lanes_Range (Lane_Count_As_Integer (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 := 4;
+ begin
+ Set_Vswing_And_Deemphasis
+ (Port,
+ Buffer_Trans_HDMI (Buffer_Trans_HDMI'First),
+ HDMI,
+ 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);
+ end Enable_HDMI;
+
+end HW.GFX.GMA.Connectors.Combo_Phy;
diff --git a/common/tigerlake/hw-gfx-gma-connectors-combo_phy.ads b/common/tigerlake/hw-gfx-gma-connectors-combo_phy.ads
new file mode 100644
index 0000000..b5347a2
--- /dev/null
+++ b/common/tigerlake/hw-gfx-gma-connectors-combo_phy.ads
@@ -0,0 +1,27 @@
+--
+-- 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.GMA.DP_Info;
+
+private package HW.GFX.GMA.Connectors.Combo_Phy is
+
+ procedure Set_Signal_Levels
+ (Port : Combo_Port;
+ eDP : Boolean;
+ Link : DP_Link;
+ Train_Set : DP_Info.Train_Set);
+
+ procedure Enable_HDMI (Port : Combo_Port);
+
+end HW.GFX.GMA.Connectors.Combo_Phy;
diff --git a/common/tigerlake/hw-gfx-gma-connectors-tc.adb b/common/tigerlake/hw-gfx-gma-connectors-tc.adb
new file mode 100644
index 0000000..976c5f2
--- /dev/null
+++ b/common/tigerlake/hw-gfx-gma-connectors-tc.adb
@@ -0,0 +1,592 @@
+--
+-- 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.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 is
+
+ function HIP_INDEX_REG (P : USBC_Port) return Registers.Registers_Index
+ is (if P <= DDI_TC4
+ then Registers.HIP_INDEX_REG0
+ else Registers.HIP_INDEX_REG1);
+
+ function HIP_INDEX_VAL (P : USBC_Port; Val : Word32) return Word32 is
+ (case P is
+ when DDI_TC1 | DDI_TC3 | DDI_TC5 => Val * 2 ** 0,
+ when DDI_TC2 | DDI_TC4 | DDI_TC6 => Val * 2 ** 8);
+
+ type Port_Regs_Array is array (USBC_Port) of Registers.Registers_Index;
+ DKL_DP_MODE : constant Port_Regs_Array :=
+ Port_Regs_Array'
+ (DDI_TC1 => Registers.DKL_DP_MODE_1,
+ DDI_TC2 => Registers.DKL_DP_MODE_2,
+ DDI_TC3 => Registers.DKL_DP_MODE_3,
+ DDI_TC4 => Registers.DKL_DP_MODE_4,
+ 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
+ (case P is
+ when DDI_TC1 => 0,
+ when DDI_TC2 => 4,
+ when DDI_TC3 => 8,
+ when DDI_TC4 => 12,
+ when DDI_TC5 => 16,
+ when DDI_TC6 => 20);
+
+ DP_PIN_ASSIGNMENT_MASK : constant := 16#f#;
+
+ TGL_PCODE_TCCOLD : constant := 16#26#;
+ TCCOLD_BLOCK_REQ : constant := 16#00#;
+ TCCOLD_UNBLOCK_REQ : constant := 16#01#;
+ TCCOLD_BLOCK_RESULT_FAIL : constant := 16#01#;
+
+ type Fia_Regs_Record is record
+ PORT_TX_DFLEXDPMLE1 : Registers.Registers_Index;
+ PORT_TX_DFLEXDPSP : Registers.Registers_Index;
+ PORT_TX_DFLEXDPPMS : Registers.Registers_Index;
+ PORT_TX_DFLEXDPCSSS : Registers.Registers_Index;
+ PORT_TX_DFLEXPA1 : Registers.Registers_Index;
+ end record;
+
+ type Fia_Regs_Array is array (USBC_Port) of Fia_Regs_Record;
+ Fia_Regs : constant Fia_Regs_Array :=
+ Fia_Regs_Array'
+ (DDI_TC1 =>
+ (Registers.PORT_TX_DFLEXDPMLE1_FIA1,
+ Registers.PORT_TX_DFLEXDPSP_FIA1,
+ Registers.PORT_TX_DFLEXDPPMS_FIA1,
+ Registers.PORT_TX_DFLEXDPCSSS_FIA1,
+ Registers.PORT_TX_DFLEXPA1_FIA1),
+ DDI_TC2 =>
+ (Registers.PORT_TX_DFLEXDPMLE1_FIA1,
+ Registers.PORT_TX_DFLEXDPSP_FIA1,
+ Registers.PORT_TX_DFLEXDPPMS_FIA1,
+ Registers.PORT_TX_DFLEXDPCSSS_FIA1,
+ Registers.PORT_TX_DFLEXPA1_FIA1),
+ DDI_TC3 =>
+ (Registers.PORT_TX_DFLEXDPMLE1_FIA2,
+ Registers.PORT_TX_DFLEXDPSP_FIA2,
+ Registers.PORT_TX_DFLEXDPPMS_FIA2,
+ Registers.PORT_TX_DFLEXDPCSSS_FIA2,
+ Registers.PORT_TX_DFLEXPA1_FIA2),
+ DDI_TC4 =>
+ (Registers.PORT_TX_DFLEXDPMLE1_FIA2,
+ Registers.PORT_TX_DFLEXDPSP_FIA2,
+ Registers.PORT_TX_DFLEXDPPMS_FIA2,
+ Registers.PORT_TX_DFLEXDPCSSS_FIA2,
+ Registers.PORT_TX_DFLEXPA1_FIA2),
+ DDI_TC5 =>
+ (Registers.PORT_TX_DFLEXDPMLE1_FIA3,
+ Registers.PORT_TX_DFLEXDPSP_FIA3,
+ Registers.PORT_TX_DFLEXDPPMS_FIA3,
+ Registers.PORT_TX_DFLEXDPCSSS_FIA3,
+ Registers.PORT_TX_DFLEXPA1_FIA3),
+ DDI_TC6 =>
+ (Registers.PORT_TX_DFLEXDPMLE1_FIA3,
+ Registers.PORT_TX_DFLEXDPSP_FIA3,
+ Registers.PORT_TX_DFLEXDPPMS_FIA3,
+ Registers.PORT_TX_DFLEXDPCSSS_FIA3,
+ Registers.PORT_TX_DFLEXPA1_FIA3));
+
+ function Fia_Index (Port : USBC_Port) return natural
+ is (case Port is
+ when DDI_TC1 | DDI_TC3 | DDI_TC5 => 0,
+ when DDI_TC2 | DDI_TC4 | DDI_TC6 => 1);
+
+ function DFLEXDPMLE1_DPMLETC_MASK (Port : USBC_Port) return Word32 is
+ (Shift_Left (15, 4 * Fia_Index (Port)));
+ function DFLEXDPMLE1_DPMLETC_ML0 (Port : USBC_Port) return Word32 is
+ (Shift_Left (1, 4 * Fia_Index (Port)));
+ function DFLEXDPMLE1_DPMLETC_ML1_0 (Port : USBC_Port) return Word32 is
+ (Shift_Left (3, 4 * Fia_Index (Port)));
+ function DFLEXDPMLE1_DPMLETC_ML3 (Port : USBC_Port) return Word32 is
+ (Shift_Left (8, 4 * Fia_Index (Port)));
+ function DFLEXDPMLE1_DPMLETC_ML3_2 (Port : USBC_Port) return Word32 is
+ (Shift_Left (12, 4 * Fia_Index (Port)));
+ function DFLEXDPMLE1_DPMLETC_ML3_0 (Port : USBC_Port) return Word32 is
+ (Shift_Left (15, 4 * Fia_Index (Port)));
+ function DP_PHY_MODE_STATUS_COMPLETE (Port : USBC_Port) return Word32 is
+ (Shift_Left (1, Fia_Index (Port)));
+ function DP_PHY_MODE_STATUS_NOT_SAFE (Port : USBC_Port) return Word32 is
+ (Shift_Left (1, Fia_Index (Port)));
+ function TC_LIVE_STATE_TC (Port : USBC_Port) return Word32 is
+ (Shift_Left (1, Fia_Index (Port) * 8 + 5));
+ function DP_LANE_ASSIGNMENT_MASK (Port : USBC_Port) return Word32 is
+ (Shift_Left (16#f#, Fia_Index (Port) * 8));
+ function DP_LANE_ASSIGNMENT_SHIFT (Port : USBC_Port) return natural is
+ (Fia_Index (Port) * 8);
+
+ 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;
+
+ type DDI_BUF_CTL_PORT_WIDTH_T is array (HW.GFX.DP_Lane_Count) of Word32;
+ DDI_BUF_CTL_PORT_WIDTH : constant DDI_BUF_CTL_PORT_WIDTH_T :=
+ DDI_BUF_CTL_PORT_WIDTH_T'
+ (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 :=
+ 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;
+ Deemphasis_Control : Word32;
+ end record;
+
+ type Buffer_Trans_Range is new natural range 0 .. 9;
+ type Buffer_Trans_Array is array (Buffer_Trans_Range) of Buffer_Trans;
+ TGL_Buffer_Trans_DP_HBR2 : constant Buffer_Trans_Array :=
+ Buffer_Trans_Array'(
+ (16#7#, 16#0#, 16#00#),
+ (16#5#, 16#0#, 16#05#),
+ (16#2#, 16#0#, 16#0B#),
+ (16#0#, 16#0#, 16#19#),
+ (16#5#, 16#0#, 16#00#),
+ (16#2#, 16#0#, 16#08#),
+ (16#0#, 16#0#, 16#14#),
+ (16#2#, 16#0#, 16#00#),
+ (16#0#, 16#0#, 16#0B#),
+ (16#0#, 16#0#, 16#00#));
+ TGL_Buffer_Trans_DP_HBR : constant Buffer_Trans_Array :=
+ Buffer_Trans_Array'(
+ (16#7#, 16#0#, 16#00#),
+ (16#5#, 16#0#, 16#05#),
+ (16#2#, 16#0#, 16#0B#),
+ (16#0#, 16#0#, 16#18#),
+ (16#5#, 16#0#, 16#00#),
+ (16#2#, 16#0#, 16#08#),
+ (16#0#, 16#0#, 16#14#),
+ (16#2#, 16#0#, 16#00#),
+ (16#0#, 16#0#, 16#0B#),
+ (16#0#, 16#0#, 16#00#));
+ Buffer_Trans_HDMI : constant Buffer_Trans_Array :=
+ Buffer_Trans_Array'(
+ (16#7#, 16#0#, 16#0#),
+ (16#6#, 16#0#, 16#0#),
+ (16#4#, 16#0#, 16#0#),
+ (16#2#, 16#0#, 16#0#),
+ (16#0#, 16#0#, 16#0#),
+ (16#0#, 16#0#, 16#5#),
+ (16#0#, 16#0#, 16#6#),
+ (16#0#, 16#0#, 16#7#),
+ (16#0#, 16#0#, 16#8#),
+ (16#0#, 16#0#, 16#A#));
+ ADL_Buffer_Trans_DP_HBR2 : constant Buffer_Trans_Array :=
+ Buffer_Trans_Array'(
+ (16#7#, 16#0#, 16#00#),
+ (16#5#, 16#0#, 16#04#),
+ (16#2#, 16#0#, 16#0a#),
+ (16#0#, 16#0#, 16#18#),
+ (16#5#, 16#0#, 16#00#),
+ (16#2#, 16#0#, 16#06#),
+ (16#0#, 16#0#, 16#14#),
+ (16#2#, 16#0#, 16#00#),
+ (16#0#, 16#0#, 16#09#),
+ (16#0#, 16#0#, 16#00#));
+ ADL_Buffer_Trans_DP_HBR : constant Buffer_Trans_Array :=
+ Buffer_Trans_Array'(
+ (16#7#, 16#0#, 16#01#),
+ (16#5#, 16#0#, 16#06#),
+ (16#2#, 16#0#, 16#0b#),
+ (16#0#, 16#0#, 16#17#),
+ (16#5#, 16#0#, 16#00#),
+ (16#2#, 16#0#, 16#08#),
+ (16#0#, 16#0#, 16#14#),
+ (16#2#, 16#0#, 16#00#),
+ (16#0#, 16#0#, 16#0b#),
+ (16#0#, 16#0#, 16#00#));
+
+ type Vswing_Regs_Record is record
+ DKL_TX_PMD_LANE_SUS : Registers.Registers_Index;
+ DKL_TX_DPCNTL0 : Registers.Registers_Index;
+ DKL_TX_DPCNTL1 : Registers.Registers_Index;
+ DKL_TX_DPCNTL2 : Registers.Registers_Index;
+ end record;
+
+ type Vswing_Regs_Array is array (USBC_Port) of Vswing_Regs_Record;
+ Vswing_Regs : constant Vswing_Regs_Array :=
+ Vswing_Regs_Array'
+ (DDI_TC1 =>
+ (Registers.DKL_TX_PMD_LANE_SUS_1,
+ Registers.DKL_TX_DPCNTL0_1,
+ Registers.DKL_TX_DPCNTL1_1,
+ Registers.DKL_TX_DPCNTL2_1),
+ DDI_TC2 =>
+ (Registers.DKL_TX_PMD_LANE_SUS_2,
+ Registers.DKL_TX_DPCNTL0_2,
+ Registers.DKL_TX_DPCNTL1_2,
+ Registers.DKL_TX_DPCNTL2_2),
+ DDI_TC3 =>
+ (Registers.DKL_TX_PMD_LANE_SUS_3,
+ Registers.DKL_TX_DPCNTL0_3,
+ Registers.DKL_TX_DPCNTL1_3,
+ Registers.DKL_TX_DPCNTL2_3),
+ DDI_TC4 =>
+ (Registers.DKL_TX_PMD_LANE_SUS_4,
+ Registers.DKL_TX_DPCNTL0_4,
+ Registers.DKL_TX_DPCNTL1_4,
+ Registers.DKL_TX_DPCNTL2_4),
+ DDI_TC5 =>
+ (Registers.DKL_TX_PMD_LANE_SUS_5,
+ Registers.DKL_TX_DPCNTL0_5,
+ Registers.DKL_TX_DPCNTL1_5,
+ Registers.DKL_TX_DPCNTL2_5),
+ DDI_TC6 =>
+ (Registers.DKL_TX_PMD_LANE_SUS_6,
+ Registers.DKL_TX_DPCNTL0_6,
+ Registers.DKL_TX_DPCNTL1_6,
+ Registers.DKL_TX_DPCNTL2_6));
+
+ procedure Set_HIP_For_Port (P : USBC_Port; N : Natural) is
+ begin
+ Registers.Write (HIP_INDEX_REG (P), HIP_INDEX_VAL (P, Word32 (N)));
+ end Set_HIP_For_Port;
+
+ subtype Pin_Assignment_Type is natural range 0 .. 6;
+ procedure Get_Pin_Assignment
+ (P : in USBC_Port;
+ Assignment : out Pin_Assignment_Type)
+ is
+ Tmp : Word32;
+ A : Word32;
+ begin
+ Registers.Read (Fia_Regs (P).PORT_TX_DFLEXPA1, Tmp);
+ A := Shift_Right (Tmp, DP_PIN_ASSIGNMENT_SHIFT (P));
+ A := A and DP_PIN_ASSIGNMENT_MASK;
+
+ if natural (A) in Pin_Assignment_Type then
+ Assignment := Pin_Assignment_Type (A);
+ else
+ Assignment := Pin_Assignment_Type'First;
+ end if;
+ end Get_Pin_Assignment;
+
+ ---------------------------------------------------------------------
+
+ procedure Program_DP_Mode (P : USBC_Port; Lane_Count : Natural)
+ is
+ MG_DP_MODE_CFG_DP_X1_MODE : constant := 1 * 2 ** 6;
+ MG_DP_MODE_CFG_DP_X2_MODE : constant := 1 * 2 ** 7;
+ DP_X_MODE_MASK : constant Word32 :=
+ MG_DP_MODE_CFG_DP_X1_MODE or MG_DP_MODE_CFG_DP_X2_MODE;
+ Assignment : Pin_Assignment_Type;
+ Ln0, Ln1 : Word32;
+ begin
+ Set_HIP_For_Port (P, 0);
+ Registers.Read (DKL_DP_MODE (P), Ln0);
+ Set_HIP_For_Port (P, 1);
+ Registers.Read (DKL_DP_MODE (P), Ln1);
+
+ Ln0 := Ln0 and not DP_X_MODE_MASK;
+ Ln1 := Ln1 and not DP_X_MODE_MASK;
+
+ Get_Pin_Assignment (P, Assignment);
+ case Assignment is
+ when 0 =>
+ if Lane_Count = 1 then
+ Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X1_MODE;
+ else
+ Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X2_MODE;
+ Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X2_MODE;
+ end if;
+ when 1 =>
+ if Lane_Count = 4 then
+ Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X2_MODE;
+ Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X2_MODE;
+ end if;
+ when 2 =>
+ if Lane_Count = 2 then
+ Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X2_MODE;
+ Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X2_MODE;
+ end if;
+ when 3 | 4 | 5 | 6 =>
+ if Lane_Count = 1 then
+ Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X1_MODE;
+ Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X1_MODE;
+ else
+ Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X2_MODE;
+ Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X2_MODE;
+ end if;
+ end case;
+
+ Set_HIP_For_Port (P, 0);
+ Registers.Unset_And_Set_Mask (DKL_DP_MODE (P), DP_X_MODE_MASK, Ln0);
+ Set_HIP_For_Port (P, 1);
+ Registers.Unset_And_Set_Mask (DKL_DP_MODE (P), DP_X_MODE_MASK, Ln1);
+ end Program_DP_Mode;
+
+ ---------------------------------------------------------------------
+
+ procedure TC_Cold_Request
+ (Request : in TC_Cold_Request_Type;
+ Success : out Boolean)
+ is
+ Result : Word64;
+ begin
+ for Try in 1 .. 3 loop
+ PCode.Mailbox_Read
+ (MBox => TGL_PCODE_TCCOLD,
+ Command => (if Request = Block
+ then TCCOLD_BLOCK_REQ
+ else TCCOLD_UNBLOCK_REQ),
+ Wait_Ready => True,
+ Reply => Result,
+ Success => Success);
+
+ if Success then
+ Success := (Result and TCCOLD_BLOCK_RESULT_FAIL) = 0;
+ end if;
+
+ exit when Success;
+
+ -- Wait 1 millisecond and try again
+ Time.U_Delay (1_000);
+ end loop;
+ end TC_Cold_Request;
+
+ ---------------------------------------------------------------------
+
+ procedure Set_Lane_Count (Port : USBC_Port; Lanes : Natural) is
+ begin
+ Registers.Unset_And_Set_Mask
+ (Register => Fia_Regs (Port).PORT_TX_DFLEXDPMLE1,
+ Mask_Unset => DFLEXDPMLE1_DPMLETC_MASK (Port),
+ Mask_Set => (case Lanes is
+ -- ML0 is not lane-reversed, ML3 is reverse
+ when 1 => DFLEXDPMLE1_DPMLETC_ML0 (Port),
+ -- ML1_0 is not reversed, ML3_2 is reverse
+ when 2 => DFLEXDPMLE1_DPMLETC_ML1_0 (Port),
+ -- symmetric
+ when 4 => DFLEXDPMLE1_DPMLETC_ML3_0 (Port),
+ when others => 0));
+ end Set_Lane_Count;
+
+ ---------------------------------------------------------------------
+
+ procedure Is_DP_Phy_Mode_Status_Complete
+ (Port : USBC_Port;
+ Success: out Boolean)
+ is
+ begin
+ Registers.Is_Set_Mask
+ (Register => Fia_Regs (Port).PORT_TX_DFLEXDPPMS,
+ Mask => DP_PHY_MODE_STATUS_COMPLETE (Port),
+ Result => Success);
+ end Is_DP_Phy_Mode_Status_Complete;
+
+ procedure Connect
+ (Port : in USBC_Port;
+ Success : out Boolean)
+ is
+ procedure Get_Lane_Assignment_Count
+ (Port : USBC_Port;
+ Lanes: out natural)
+ is
+ Lane_Mask : Word32;
+ Tmp : Word32;
+ begin
+ Registers.Read (Fia_Regs (Port).PORT_TX_DFLEXDPSP, Tmp);
+ Lane_Mask :=
+ Shift_Right (Tmp and DP_LANE_ASSIGNMENT_MASK (Port),
+ DP_LANE_ASSIGNMENT_SHIFT (Port));
+ Lanes :=
+ (case Lane_Mask is
+ when 1 | 2 | 4 | 8 => 1,
+ when 3 | 12 => 2,
+ when 15 => 4,
+ when others => 1);
+ end Get_Lane_Assignment_Count;
+ Lanes : natural;
+ begin
+ Is_DP_Phy_Mode_Status_Complete (Port, Success);
+ if not Success then
+ Debug.Put_Line ("DP PHY mode status not complete");
+ return;
+ end if;
+
+ Registers.Set_Mask
+ (Register => Fia_Regs (Port).PORT_TX_DFLEXDPCSSS,
+ Mask => DP_PHY_MODE_STATUS_NOT_SAFE (Port));
+
+ Registers.Is_Set_Mask
+ (Register => Fia_Regs (Port).PORT_TX_DFLEXDPSP,
+ Mask => TC_LIVE_STATE_TC (Port),
+ Result => Success);
+
+ if not Success then
+ pragma Debug (Debug.Put_Line ("Type-C Port is not connected."));
+ end if;
+
+ pragma Debug
+ (not Success, Debug.Put_Line ("Type-C Port is not connected."));
+
+ Get_Lane_Assignment_Count (Port, Lanes);
+ Set_Lane_Count (Port, Lanes);
+ end Connect;
+
+ ---------------------------------------------------------------------
+
+ procedure Disconnect (Port : USBC_Port) is
+ begin
+ Registers.Unset_Mask
+ (Register => Fia_Regs (Port).PORT_TX_DFLEXDPCSSS,
+ Mask => Word32 (Fia_Index (Port)));
+
+ Registers.Wait_Unset_mask
+ (Register => Fia_Regs (Port).PORT_TX_DFLEXDPPMS,
+ Mask => DP_PHY_MODE_STATUS_COMPLETE (Port));
+ end Disconnect;
+
+ ---------------------------------------------------------------------
+
+ procedure Set_Vswing_And_Deemphasis
+ (Port : USBC_Port;
+ Buf_Trans : Buffer_Trans)
+ is
+ -- Preshoot Coeff, Deemphasis Coeff, VSwing Control,
+ DPcnt_Mask : constant Word32 := 16#3_ff07#;
+ DPcnt_Val : constant Word32 :=
+ Buf_Trans.Vswing_Control or
+ Shift_Left (Buf_Trans.Deemphasis_Control, 8) or
+ Shift_Left (Buf_Trans.Preshoot_Control, 13);
+ DKL_TX_DP20BITMODE : constant := 1 * 2 ** 2;
+ begin
+ for Lane in 0 .. 1 loop
+ Set_HIP_For_Port (Port, Lane);
+ Registers.Write (Vswing_Regs (Port).DKL_TX_PMD_LANE_SUS, 0);
+ Registers.Unset_And_Set_Mask
+ (Vswing_Regs (Port).DKL_TX_DPCNTL0, DPcnt_Mask, DPcnt_Val);
+ Registers.Unset_And_Set_Mask
+ (Vswing_Regs (Port).DKL_TX_DPCNTL1, DPcnt_Mask, DPcnt_Val);
+ Registers.Unset_Mask
+ (Vswing_Regs (Port).DKL_TX_DPCNTL2, DKL_TX_DP20BITMODE);
+ end loop;
+
+ end Set_Vswing_And_Deemphasis;
+
+ ---------------------------------------------------------------------
+
+ procedure Set_Signal_Levels
+ (Port : USBC_Port;
+ Link : DP_Link;
+ Train_Set : DP_Info.Train_Set)
+ is
+ function To_Buf_Trans_Index
+ (Set : DP_Info.Train_Set) return Buffer_Trans_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_Range :=
+ To_Buf_Trans_Index (Train_Set);
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ Registers.Is_Set_Mask
+ (Register => DDI_BUF_CTL (Port),
+ Mask => DDI_BUF_CTL_BUFFER_ENABLE,
+ Result => Was_Enabled);
+
+ if Config.Has_TGL_Buffer_Translations then
+ if Link.Bandwidth > DP_Bandwidth_2_7 then
+ Buf_Trans := TGL_Buffer_Trans_DP_HBR2 (Entry_Index);
+ else
+ Buf_Trans := TGL_Buffer_Trans_DP_HBR (Entry_Index);
+ end if;
+ else
+ if Link.Bandwidth > DP_Bandwidth_2_7 then
+ Buf_Trans := ADL_Buffer_Trans_DP_HBR2 (Entry_Index);
+ else
+ Buf_Trans := ADL_Buffer_Trans_DP_HBR (Entry_Index);
+ end if;
+ end if;
+
+ Set_Vswing_And_Deemphasis (Port, Buf_Trans);
+
+ 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));
+ Registers.Posting_Read (DDI_BUF_CTL (Port));
+
+ if not Was_Enabled then
+ Registers.Wait_Unset_Mask (DDI_BUF_CTL (Port), DDI_BUF_CTL_IDLE_STATUS);
+ end if;
+ end Set_Signal_Levels;
+
+ procedure Enable_HDMI (Port : USBC_Port)
+ is
+ HDMI_Lane_Count : constant := 4;
+ Buf_Trans : constant Buffer_Trans :=
+ Buffer_Trans_HDMI (Buffer_Trans_HDMI'Last);
+ begin
+ Program_DP_Mode (Port, HDMI_Lane_Count);
+ Set_Vswing_And_Deemphasis (Port, Buf_Trans);
+ end Enable_HDMI;
+
+end HW.GFX.GMA.Connectors.TC;
diff --git a/common/tigerlake/hw-gfx-gma-connectors-tc.ads b/common/tigerlake/hw-gfx-gma-connectors-tc.ads
new file mode 100644
index 0000000..d169706
--- /dev/null
+++ b/common/tigerlake/hw-gfx-gma-connectors-tc.ads
@@ -0,0 +1,38 @@
+--
+-- 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.GMA.DP_Info;
+
+package HW.GFX.GMA.Connectors.TC is
+
+ procedure Connect (Port : in USBC_Port; Success: out Boolean);
+ procedure Disconnect (Port : USBC_Port);
+ procedure Program_DP_Mode (P : USBC_Port; Lane_Count : Natural);
+ procedure Set_Lane_Count (Port : USBC_Port; Lanes : Natural);
+ procedure Is_DP_Phy_Mode_Status_Complete
+ (Port : USBC_Port;
+ Success: out Boolean);
+ procedure Enable_HDMI (Port : USBC_Port);
+
+ procedure Set_Signal_Levels
+ (Port : USBC_Port;
+ Link : DP_Link;
+ Train_Set : DP_Info.Train_Set);
+
+ type TC_Cold_Request_Type is (Block, Unblock);
+ procedure TC_Cold_Request
+ (Request : in TC_Cold_Request_Type;
+ Success : out Boolean);
+
+end HW.GFX.GMA.Connectors.TC;
diff --git a/common/tigerlake/hw-gfx-gma-connectors.adb b/common/tigerlake/hw-gfx-gma-connectors.adb
index 73fafee..e02c7f2 100644
--- a/common/tigerlake/hw-gfx-gma-connectors.adb
+++ b/common/tigerlake/hw-gfx-gma-connectors.adb
@@ -12,60 +12,367 @@
-- GNU General Public License for more details.
--

+with HW.GFX.GMA.DP_Aux_Ch;
+with HW.GFX.DP_Training;
with HW.GFX.GMA.Config;
+with HW.GFX.GMA.Config_Helpers;
+with HW.GFX.GMA.Connectors.TC;
+with HW.GFX.GMA.Connectors.Combo_Phy;
+with HW.GFX.GMA.DP_Aux_Request;
+with HW.GFX.GMA.DP_Info;
with HW.GFX.GMA.Panel;
+with HW.GFX.GMA.Registers;
+with HW.GFX.GMA.Transcoder;

with HW.Debug;
with GNAT.Source_Info;

package body HW.GFX.GMA.Connectors is

- procedure Post_Reset_Off is
- begin
- pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
- end Post_Reset_Off;
+ type Pipe_Regs is array (Pipe_Index) of Registers.Registers_Index;
+ DP_TP_CTL : constant Pipe_Regs := Pipe_Regs'
+ (Primary => Registers.TGL_DP_TP_CTL_A,
+ Secondary => Registers.TGL_DP_TP_CTL_B,
+ Tertiary => Registers.TGL_DP_TP_CTL_C);
+ DP_TP_CTL_TRANSPORT_ENABLE : constant := 1 * 2 ** 31;
+ DP_TP_CTL_MODE_SST : constant := 0 * 2 ** 27;
+ DP_TP_CTL_MODE_MST : constant := 1 * 2 ** 27;
+ DP_TP_CTL_FORCE_ACT : constant := 1 * 2 ** 25;
+ DP_TP_CTL_ENHANCED_FRAME_ENABLE : constant := 1 * 2 ** 18;
+ DP_TP_CTL_LINK_TRAIN_MASK : constant := 7 * 2 ** 8;
+ DP_TP_CTL_LINK_TRAIN_PAT1 : constant := 0 * 2 ** 8;
+ DP_TP_CTL_LINK_TRAIN_PAT2 : constant := 1 * 2 ** 8;
+ DP_TP_CTL_LINK_TRAIN_IDLE : constant := 2 * 2 ** 8;
+ DP_TP_CTL_LINK_TRAIN_NORMAL : constant := 3 * 2 ** 8;
+ DP_TP_CTL_LINK_TRAIN_PAT3 : constant := 4 * 2 ** 8;
+ DP_TP_CTL_LINK_TRAIN_PAT4 : constant := 5 * 2 ** 8;

- procedure Initialize is
+ DP_TP_STATUS : constant Pipe_Regs := Pipe_Regs'
+ (Primary => Registers.TGL_DP_TP_STATUS_A,
+ Secondary => Registers.TGL_DP_TP_STATUS_B,
+ Tertiary => Registers.TGL_DP_TP_STATUS_C);
+ DP_TP_STATUS_MIN_IDLES_SENT : constant := 1 * 2 ** 25;
+
+ DDI_BUF_CTL_BUFFER_ENABLE : constant := 1 * 2 ** 31;
+ 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_PORT_REVERSAL : constant := 1 * 2 ** 16;
+ DDI_BUF_CTL_IDLE_STATUS : constant := 1 * 2 ** 7;
+ DDI_BUF_CTL_TRANS_SELECT_MASK : constant := 16#f# * 2 ** 24;
+
+ type DDI_CLK_SEL_Shift_Array is array (Combo_Port) of Natural;
+ DDI_CLK_SEL_SHIFT : constant DDI_CLK_SEL_Shift_Array :=
+ DDI_CLK_SEL_Shift_Array'
+ (DIGI_A => 0,
+ DIGI_B => 2,
+ DIGI_C => 4);
+
+ type TGL_Digital_Port_Array is array (TGL_Digital_Port) of Word32;
+ DDI_CLK_OFF : constant TGL_Digital_Port_Array :=
+ TGL_Digital_Port_Array'
+ (DIGI_A => 1 * 2 ** 10,
+ DIGI_B => 1 * 2 ** 11,
+ DIGI_C => 1 * 2 ** 24,
+ DDI_TC1 => 1 * 2 ** 12,
+ DDI_TC2 => 1 * 2 ** 13,
+ DDI_TC3 => 1 * 2 ** 14,
+ DDI_TC4 => 1 * 2 ** 21,
+ DDI_TC5 => 1 * 2 ** 22,
+ DDI_TC6 => 1 * 2 ** 23,
+ others => 0);
+
+ type TGL_Digital_Port_Regs is array (TGL_Digital_Port) of Registers.Registers_Index;
+ DDI_BUF_CTL : constant TGL_Digital_Port_Regs :=
+ TGL_Digital_Port_Regs'
+ (DIGI_A => Registers.DDI_BUF_CTL_A,
+ DIGI_B => Registers.DDI_BUF_CTL_B,
+ DIGI_C => Registers.DDI_BUF_CTL_C,
+ 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,
+ others => Registers.DDI_BUF_CTL_A);
+
+ type DDI_CLK_SEL_Array is array (USBC_Port) of Registers.Registers_Index;
+ DDI_CLK_SEL : constant DDI_CLK_SEL_Array :=
+ DDI_CLK_SEL_Array'
+ (DDI_TC1 => Registers.DDI_CLK_SEL_USBC1,
+ DDI_TC2 => Registers.DDI_CLK_SEL_USBC2,
+ DDI_TC3 => Registers.DDI_CLK_SEL_USBC3,
+ DDI_TC4 => Registers.DDI_CLK_SEL_USBC4,
+ DDI_TC5 => Registers.DDI_CLK_SEL_USBC5,
+ DDI_TC6 => Registers.DDI_CLK_SEL_USBC6);
+
+ type Training_Port_Info is record
+ Port : TGL_Digital_Port;
+ Pipe : Pipe_Index;
+ eDP : Boolean;
+ end record;
+
+ function To_DP (Port_Info : Training_Port_Info) return DP_Port is
+ (case Port_Info.Port is
+ when DIGI_A => DP_A,
+ when DIGI_B => DP_B,
+ when DIGI_C => DP_C,
+ when DDI_TC1 => DP_D,
+ when DDI_TC2 => DP_E,
+ when DDI_TC3 => DP_F,
+ when DDI_TC4 => DP_G,
+ when DDI_TC5 => DP_H,
+ when DDI_TC6 => DP_I,
+ when others => DP_A);
+
+ ---------------------------------------------------------------------
+
+ procedure Off (Pipe : Pipe_Index; Port : TGL_Digital_Port)
+ is
+ Enabled : Boolean;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
- end Initialize;
+ Registers.Is_Set_Mask
+ (Register => DDI_BUF_CTL (Port),
+ Mask => DDI_BUF_CTL_BUFFER_ENABLE,
+ Result => Enabled);
+
+ if Enabled then
+ Registers.Unset_Mask
+ (Register => DDI_BUF_CTL (Port),
+ Mask => DDI_BUF_CTL_BUFFER_ENABLE);
+ end if;
+
+ Registers.Unset_Mask
+ (Register => DP_TP_CTL (Pipe),
+ Mask => DP_TP_CTL_TRANSPORT_ENABLE);
+
+ if Enabled then
+ Registers.Wait_Set_Mask
+ (Register => DDI_BUF_CTL (Port),
+ Mask => DDI_BUF_CTL_IDLE_STATUS);
+ end if;
+
+ Registers.Set_Mask
+ (Register => Registers.DPCLKA_CFGCR0,
+ Mask => DDI_CLK_OFF (Port));
+ end Off;
+
+ procedure Off (Port_Info : Training_Port_Info) is
+ begin
+ Off (Port_Info.Pipe, Port_Info.Port);
+ end Off;
+
+ ---------------------------------------------------------------------
+
+ procedure Set_TP_CTL
+ (Pipe : Pipe_Index;
+ Link : DP_Link;
+ Pattern : DP_Info.Training_Pattern)
+ is
+ type DP_TP_CTL_LINK_TRAIN_ARRAY is
+ array (DP_Info.Training_Pattern) of Word32;
+ DP_TP_CTL_LINK_TRAIN : constant DP_TP_CTL_LINK_TRAIN_ARRAY :=
+ DP_TP_CTL_LINK_TRAIN_ARRAY'
+ (DP_Info.TP_1 => DP_TP_CTL_LINK_TRAIN_PAT1,
+ DP_Info.TP_2 => DP_TP_CTL_LINK_TRAIN_PAT2,
+ DP_Info.TP_3 => DP_TP_CTL_LINK_TRAIN_PAT3,
+ DP_Info.TP_Idle => DP_TP_CTL_LINK_TRAIN_IDLE,
+ DP_Info.TP_None => DP_TP_CTL_LINK_TRAIN_NORMAL);
+
+ DP_TP_CTL_Enhanced_Frame : Word32 := 0;
+ begin
+ if Link.Enhanced_Framing then
+ DP_TP_CTL_Enhanced_Frame := DP_TP_CTL_ENHANCED_FRAME_ENABLE;
+ end if;
+
+ Registers.Write
+ (Register => DP_TP_CTL (Pipe),
+ Value => DP_TP_CTL_TRANSPORT_ENABLE or
+ DP_TP_CTL_Enhanced_Frame or
+ DP_TP_CTL_MODE_SST or
+ DP_TP_CTL_LINK_TRAIN (Pattern));
+ Registers.Posting_Read (DP_TP_CTL (Pipe));
+ end Set_TP_CTL;
+
+ procedure Set_Training_Pattern
+ (Port_Info : Training_Port_Info;
+ Link : DP_Link;
+ Pattern : DP_Info.Training_Pattern)
+ is
+ use type DP_Info.Training_Pattern;
+ Pipe : Pipe_Index renames Port_Info.Pipe;
+ begin
+ if Pattern < DP_Info.TP_Idle then
+ Set_TP_CTL (Pipe, Link, Pattern);
+ else
+ Set_TP_CTL (Pipe, Link, DP_Info.TP_Idle);
+ Registers.Wait_Set_Mask
+ (Register => DP_TP_STATUS (Pipe),
+ Mask => DP_TP_STATUS_MIN_IDLES_SENT);
+ Set_TP_CTL (Pipe, Link, DP_Info.TP_None);
+ end if;
+ end Set_Training_Pattern;
+
+ ---------------------------------------------------------------------
+
+ pragma Warnings (GNATprove, Off, "unused variable ""Port_Info""",
+ Reason => "Needed for a common interface");
+ function Max_V_Swing
+ (Port_Info : Training_Port_Info) return DP_Info.DP_Voltage_Swing
+ is
+ (DP_Info.VS_Level_3);
+
+ function Max_Pre_Emph
+ (Port_Info : Training_Port_Info;
+ Train_Set : DP_Info.Train_Set)
+ return DP_Info.DP_Pre_Emph
+ is
+ begin
+ return
+ (case Train_Set.Voltage_Swing is
+ when DP_Info.VS_Level_0 => DP_Info.Emph_Level_3,
+ when DP_Info.VS_Level_1 => DP_Info.Emph_Level_2,
+ when DP_Info.VS_Level_2 => DP_Info.Emph_Level_1,
+ when others => DP_Info.Emph_Level_0);
+ end Max_Pre_Emph;
+ pragma Warnings (GNATprove, On, "unused variable ""Port_Info""");
+
+ ---------------------------------------------------------------------
+
+ procedure Set_Signal_Levels
+ (Port_Info : Training_Port_Info;
+ Link : DP_Link;
+ Train_Set : DP_Info.Train_Set)
+ is
+ Port : TGL_Digital_Port renames Port_Info.Port;
+ begin
+ if Port in Combo_Port then
+ Combo_Phy.Set_Signal_Levels (Port, Port_Info.eDP, Link, Train_Set);
+ elsif Port in USBC_Port then
+ TC.Set_Signal_Levels (Port, Link, Train_Set);
+ end if;
+ end Set_Signal_Levels;
+
+ ---------------------------------------------------------------------
+
+ procedure Map_PLL_To_Port
+ (Port : TGL_Digital_Port;
+ PLL_Hint : Word32)
+ is
+ CLOCK_SELECT_MASK : constant := 16#f000_0000#;
+ CLOCK_SELECT_TYPEC : constant := 16#8000_0000#;
+ DDI_CLK_SEL_MASK : constant := 3;
+ Clk_Sel_Shift : Natural;
+ begin
+ if Port in USBC_Port then
+ Registers.Unset_And_Set_Mask
+ (Register => DDI_CLK_SEL (Port),
+ Mask_Unset => CLOCK_SELECT_MASK,
+ Mask_Set => CLOCK_SELECT_TYPEC);
+ end if;
+
+ if Port in Combo_Port then
+ Clk_Sel_Shift := DDI_CLK_SEL_SHIFT (Port);
+ Registers.Unset_And_Set_Mask
+ (Register => Registers.DPCLKA_CFGCR0,
+ Mask_Unset => Shift_Left (DDI_CLK_SEL_MASK, Clk_Sel_Shift),
+ Mask_Set => Shift_Left (PLL_Hint, Clk_Sel_Shift));
+ Registers.Posting_Read (Registers.DPCLKA_CFGCR0);
+ end if;
+ end Map_PLL_To_Port;

procedure Pre_On
(Pipe : in Pipe_Index;
Port_Cfg : in Port_Config;
PLL_Hint : in Word32;
- Success : out Boolean) is
+ Success : out Boolean)
+ is
+ package Training is new DP_Training
+ (TPS3_Supported => True,
+ T => Training_Port_Info,
+ Aux_T => DP_Port,
+ Aux_Ch => HW.GFX.GMA.DP_Aux_Ch,
+ DP_Info => DP_Info,
+ To_Aux => To_DP,
+ Max_V_Swing => Max_V_Swing,
+ Max_Pre_Emph => Max_Pre_Emph,
+ Set_Pattern => Set_Training_Pattern,
+ Set_Signal_Levels => Set_Signal_Levels,
+ Off => Off);
+ Port : TGL_Digital_Port;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
- Success := True;
+
+ if Port_Cfg.Port not in TGL_Digital_Port then
+ Success := False;
+ return;
+ end if;
+
+ Port := Port_Cfg.Port;
+ Map_PLL_To_Port (Port, PLL_Hint);
+
+ Registers.Unset_Mask
+ (Register => Registers.DPCLKA_CFGCR0,
+ Mask => DDI_CLK_OFF (Port));
+
+ if Port_Cfg.Display = DP then
+ if Port in USBC_Port then
+ TC.Program_DP_Mode
+ (Port, Natural (Lane_Count_As_Integer (Port_Cfg.DP.Lane_Count)));
+ end if;
+ Transcoder.Enable_Pipe_Clock (Pipe, Port_Cfg);
+ Transcoder.Configure (Pipe, Port_Cfg, False);
+
+ Training.Train_DP
+ (Port => (Port, Pipe, eDP => Port_Cfg.Is_eDP),
+ Link => Port_Cfg.DP,
+ Success => Success);
+ elsif Port_Cfg.Display = HDMI then
+ Transcoder.Enable_Pipe_Clock (Pipe, Port_Cfg);
+ Transcoder.Configure (Pipe, Port_Cfg, False);
+
+ Success := True;
+ if Port in Combo_Port then
+ Combo_Phy.Enable_HDMI (Port);
+ elsif Port in USBC_Port then
+ TC.Enable_HDMI (Port);
+ else
+ Success := False;
+ end if;
+ else
+ Success := False;
+ end if;
end Pre_On;

+ ---------------------------------------------------------------------
+
procedure Post_On
(Pipe : in Pipe_Index;
Port_Cfg : in Port_Config;
PLL_Hint : in Word32;
Success : out Boolean) is
begin
- pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Panel.Backlight_On (Port_Cfg.Panel);
Success := True;
end Post_On;

procedure Pre_Off (Pipe : Pipe_Index; Port_Cfg : Port_Config) is
begin
- pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Panel.Backlight_Off (Port_Cfg.Panel);
Panel.Off (Port_Cfg.Panel);
end Pre_Off;

procedure Post_Off (Pipe : Pipe_Index; Port_Cfg : Port_Config) is
begin
- pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+ if Port_Cfg.Port in Combo_Port then
+ Off (Pipe, Port_Cfg.Port);
+ end if;
end Post_Off;

procedure Pre_All_Off is
begin
- pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
for P in Valid_Panels loop
Panel.Backlight_Off (P);
Panel.Off (P);
@@ -74,7 +381,29 @@

procedure Post_All_Off is
begin
- pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+ for Port in Combo_Port loop
+ Off (Pipe_Index'First, Port); -- pipe index is arbitrary
+ end loop;
end Post_All_Off;

+ pragma Warnings (GNATprove, Off, "subprogram ""Post_On"" has no effect",
+ Reason => "Not supported");
+ procedure Post_On (Pipe : Pipe_Index; Port_Cfg : Port_Config) is
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+ end Post_On;
+ pragma Warnings (GNATprove, On, "subprogram ""Post_On"" has no effect");
+
+ procedure Post_Reset_Off is
+ begin
+ for Port in Combo_Port loop
+ Off (Pipe_Index'First, Port);
+ end loop;
+ end Post_Reset_Off;
+
+ procedure Initialize is
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+ end Initialize;
+
end HW.GFX.GMA.Connectors;
diff --git a/common/tigerlake/hw-gfx-gma-power_and_clocks.adb b/common/tigerlake/hw-gfx-gma-power_and_clocks.adb
index 88e932d..099376a 100644
--- a/common/tigerlake/hw-gfx-gma-power_and_clocks.adb
+++ b/common/tigerlake/hw-gfx-gma-power_and_clocks.adb
@@ -19,6 +19,8 @@
with HW.GFX.GMA.PCode;
with HW.GFX.GMA.Registers;
with HW.GFX.GMA.Transcoder;
+with HW.GFX.GMA.Connectors;
+with HW.GFX.GMA.Connectors.TC;

use type HW.Word64;

@@ -222,6 +224,7 @@
procedure Pre_On (PD : Power_Domain)
is
DP_AUX_CH_CTL_TBT_IO : constant := 1 * 2 ** 11;
+ Success : Boolean;
begin
if PD in AUX_USBC_Domain then
-- Disable TBT IO mode for AUX
@@ -229,9 +232,20 @@
(Register => AUX_CTL_Regs (PD),
Mask => DP_AUX_CH_CTL_TBT_IO);

+ Connectors.TC.Connect (Aux_To_Port (PD), Success);
+ if not Success then
+ Debug.Put_Line ("Connection flow failed!");
+ end if;
end if;
end Pre_On;

+ procedure Pre_Off (PD : Power_Domain) is
+ begin
+ if PD in AUX_USBC_Domain then
+ Connectors.TC.Disconnect (Aux_To_Port (PD));
+ end if;
+ end Pre_Off;
+
procedure Post_On (PD : Power_Domain)
is
DKL_CMN_UC_DW_27_UC_HEALTH : constant := 1 * 2 ** 15;
@@ -801,9 +815,15 @@

procedure Power_Up (Old_Configs, New_Configs : Pipe_Configs)
is
+ Success : Boolean;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));

+ Connectors.TC.TC_Cold_Request (Connectors.TC.Block, Success);
+ if not Success then
+ Debug.Put_Line ("Failed to unblock TCCOLD");
+ end if;
+
for PD in Power_Domain loop
if not Need_PD (PD, Old_Configs) and Need_PD (PD, New_Configs) then
PD_On (PD);
@@ -813,6 +833,7 @@

procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Pipe_Configs)
is
+ Success : Boolean;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
for PD in reverse Power_Domain loop
@@ -823,6 +844,10 @@
end if;
end loop;

+ Connectors.TC.TC_Cold_Request (Connectors.TC.Unblock, Success);
+ if not Success then
+ Debug.Put_Line ("Failed to unblock TCCOLD");
+ end if;
end Power_Down;

procedure Pre_All_Off is

To view, visit change 82144. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: libgfxinit
Gerrit-Branch: cros
Gerrit-Change-Id: I908e8bef8451d21eecde9ce6defddc2b3df7f738
Gerrit-Change-Number: 82144
Gerrit-PatchSet: 1
Gerrit-Owner: Dinesh Gehlot <digehlot@google.com>
Gerrit-Reviewer: Nico Huber <nico.h@gmx.de>
Gerrit-Reviewer: Tim Wawrzynczak <inforichland@gmail.com>
Gerrit-Attention: Nico Huber <nico.h@gmx.de>
Gerrit-Attention: Tim Wawrzynczak <inforichland@gmail.com>
Gerrit-MessageType: newchange