Attention is currently required from: Nico Huber, Tim Wawrzynczak.
Hello Nico Huber, Tim Wawrzynczak,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/libgfxinit/+/82144?usp=email
to review the following change.
Change subject: gma tgl: Add connector programming ......................................................................
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