Attention is currently required from: Tim Wawrzynczak.
Hello Tim Wawrzynczak,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/libgfxinit/+/82146?usp=email
to review the following change.
Change subject: gma: Support ADL-P CDClk clock crawl ......................................................................
gma: Support ADL-P CDClk clock crawl
Setting up CDCLK is a little different for ADL-P, i915 calls it adlp_cdclk_pll_crawl.
Signed-off-by: Tim Wawrzynczak twawrzynczak@chromium.org Change-Id: Id01752a41e4e401a5f759453c12f368395eebdf2 --- M common/hw-gfx-gma-config.ads.template M common/tigerlake/Makefile.inc M common/tigerlake/hw-gfx-gma-connectors-tc.adb M common/tigerlake/hw-gfx-gma-port_detect.adb A common/tigerlake/hw-gfx-gma-power_and_clocks-tgl.adb A common/tigerlake/hw-gfx-gma-power_and_clocks-tgl.ads A common/tigerlake/hw-gfx-gma-power_and_clocks-xelpd.adb A common/tigerlake/hw-gfx-gma-power_and_clocks-xelpd.ads M common/tigerlake/hw-gfx-gma-power_and_clocks.adb M common/tigerlake/hw-gfx-gma-power_and_clocks.ads 10 files changed, 1,293 insertions(+), 485 deletions(-)
git pull ssh://review.coreboot.org:29418/libgfxinit refs/changes/46/82146/1
diff --git a/common/hw-gfx-gma-config.ads.template b/common/hw-gfx-gma-config.ads.template index b56086f..41fe590 100644 --- a/common/hw-gfx-gma-config.ads.template +++ b/common/hw-gfx-gma-config.ads.template @@ -262,6 +262,7 @@ Can_Switch_CDClk : <hswbool> := Broadwell_On; Has_Fractional_RawClk : <genbool> := Cannon_Point_On; Has_New_Type_C_PLL_Enable : <tglbool> := Alderlake_On; + Has_CDClk_PLL_Crawl : <tglbool> := Alderlake_On;
----------- DDI: ------------- End_EDP_Training_Late : <genbool> := Gen_Haswell; @@ -302,12 +303,17 @@ Has_IPS_CTL_Mailbox : <hswbool> := CPU_Broadwell;
Has_Per_Pipe_SRD : <hswbool> := Broadwell_On; + Has_XELPD_Power_Domains : <tglbool> := Alderlake_On;
----------- GTT: ------------- Has_64bit_GTT : <hswbool> := Broadwell_On;
----------- Type-C: ---------- Has_Type_C_Ports : <genbool> := Tigerlake_On; + Need_TC_PHY_Ownership : <tglbool> := Alderlake_On; + Need_Loadgen_Select : <tglbool> := Alderlake_On; + Need_DP_Alt_Switch : <tglbool> := Alderlake_On; + Has_TCSS_DDI_Status : <tglbool> := Alderlake_On;
----------- Rawclk ----------- Need_Rawclk_Numerator : <genbool> := Tigerlake_On; diff --git a/common/tigerlake/Makefile.inc b/common/tigerlake/Makefile.inc index b76f2fe..c5a1c79 100644 --- a/common/tigerlake/Makefile.inc +++ b/common/tigerlake/Makefile.inc @@ -2,6 +2,10 @@ gfxinit-y += hw-gfx-gma-combo_phy.ads gfxinit-y += hw-gfx-gma-power_and_clocks.adb gfxinit-y += hw-gfx-gma-power_and_clocks.ads +gfxinit-y += hw-gfx-gma-power_and_clocks-tgl.adb +gfxinit-y += hw-gfx-gma-power_and_clocks-tgl.ads +gfxinit-y += hw-gfx-gma-power_and_clocks-xelpd.adb +gfxinit-y += hw-gfx-gma-power_and_clocks-xelpd.ads gfxinit-y += hw-gfx-gma-connectors.adb gfxinit-y += hw-gfx-gma-connectors-tc.adb gfxinit-y += hw-gfx-gma-connectors-tc.ads diff --git a/common/tigerlake/hw-gfx-gma-connectors-tc.adb b/common/tigerlake/hw-gfx-gma-connectors-tc.adb index 976c5f2..b1c284e 100644 --- a/common/tigerlake/hw-gfx-gma-connectors-tc.adb +++ b/common/tigerlake/hw-gfx-gma-connectors-tc.adb @@ -44,6 +44,25 @@ DDI_TC5 => Registers.DKL_DP_MODE_5, DDI_TC6 => Registers.DKL_DP_MODE_6);
+ DKL_PCS_DW5 : constant Port_Regs_Array := + Port_Regs_Array' + (DDI_TC1 => Registers.DKL_PCS_DW5_1, + DDI_TC2 => Registers.DKL_PCS_DW5_2, + DDI_TC3 => Registers.DKL_PCS_DW5_3, + DDI_TC4 => Registers.DKL_PCS_DW5_4, + others => Registers.DKL_PCS_DW5_1); + + TCSS_DDI_STATUS : constant Port_Regs_Array := + Port_Regs_Array' + (DDI_TC1 => Registers.TCSS_DDI_STATUS_1, + DDI_TC2 => Registers.TCSS_DDI_STATUS_2, + DDI_TC3 => Registers.TCSS_DDI_STATUS_3, + DDI_TC4 => Registers.TCSS_DDI_STATUS_4, + others => Registers.TCSS_DDI_STATUS_1); + + TCSS_DDI_STATUS_HPD_LIVE_STATUS_ALT : constant := 1 * 2 ** 0; + TCSS_DDI_STATUS_READY : constant := 1 * 2 ** 2; + function DP_PIN_ASSIGNMENT_SHIFT (P : USBC_Port) return natural is (case P is when DDI_TC1 => 0, @@ -144,6 +163,7 @@ DDI_BUF_CTL_PORT_WIDTH_2_LANES : constant := 1 * 2 ** 1; DDI_BUF_CTL_PORT_WIDTH_4_LANES : constant := 3 * 2 ** 1; DDI_BUF_CTL_IDLE_STATUS : constant := 1 * 2 ** 7; + DDI_BUF_CTL_TC_PHY_OWNERSHIP : constant := 1 * 2 ** 6;
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 := @@ -401,10 +421,17 @@ 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); + if Config.Need_TC_PHY_Ownership then + Registers.Is_Set_Mask + (Register => TCSS_DDI_STATUS (Port), + Mask => TCSS_DDI_STATUS_READY, + Result => Success); + else + Registers.Is_Set_Mask + (Register => Fia_Regs (Port).PORT_TX_DFLEXDPPMS, + Mask => DP_PHY_MODE_STATUS_COMPLETE (Port), + Result => Success); + end if; end Is_DP_Phy_Mode_Status_Complete;
procedure Connect @@ -437,17 +464,31 @@ return; end if;
- Registers.Set_Mask - (Register => Fia_Regs (Port).PORT_TX_DFLEXDPCSSS, - Mask => DP_PHY_MODE_STATUS_NOT_SAFE (Port)); + -- Take ownership and check live status + if Config.Need_TC_PHY_Ownership then + -- TODO: also check SDEISR for legacy "connection" + Registers.Is_Set_Mask + (Register => TCSS_DDI_STATUS (Port), + Mask => TCSS_DDI_STATUS_HPD_LIVE_STATUS_ALT, + Result => Success);
- Registers.Is_Set_Mask - (Register => Fia_Regs (Port).PORT_TX_DFLEXDPSP, - Mask => TC_LIVE_STATE_TC (Port), - Result => Success); + if Success then + Registers.Set_Mask + (Register => DDI_BUF_CTL (Port), + Mask => DDI_BUF_CTL_TC_PHY_OWNERSHIP); + end if; + else + -- TODO: also check SDEISR for legacy "connection" + 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.")); + if Success then + Registers.Set_Mask + (Register => Fia_Regs (Port).PORT_TX_DFLEXDPCSSS, + Mask => DP_PHY_MODE_STATUS_NOT_SAFE (Port)); + end if; end if;
pragma Debug @@ -461,13 +502,19 @@
procedure Disconnect (Port : USBC_Port) is begin - Registers.Unset_Mask - (Register => Fia_Regs (Port).PORT_TX_DFLEXDPCSSS, - Mask => Word32 (Fia_Index (Port))); + if Config.Need_TC_PHY_Ownership then + Registers.Unset_Mask + (Register => DDI_BUF_CTL (Port), + Mask => DDI_BUF_CTL_TC_PHY_OWNERSHIP); + else + 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)); + Registers.Wait_Unset_mask + (Register => Fia_Regs (Port).PORT_TX_DFLEXDPPMS, + Mask => DP_PHY_MODE_STATUS_COMPLETE (Port)); + end if; end Disconnect;
--------------------------------------------------------------------- @@ -483,6 +530,14 @@ Shift_Left (Buf_Trans.Deemphasis_Control, 8) or Shift_Left (Buf_Trans.Preshoot_Control, 13); DKL_TX_DP20BITMODE : constant := 1 * 2 ** 2; + + function DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1 (N : Word32) return Word32 + is (Shift_Left (N and 16#3#, 3)); + function DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2 (N : Word32) return Word32 + is (Shift_Left (N and 16#3#, 5)); + + DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK : constant := 16#18#; + DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK : constant := 16#60#; begin for Lane in 0 .. 1 loop Set_HIP_For_Port (Port, Lane); @@ -493,6 +548,31 @@ (Vswing_Regs (Port).DKL_TX_DPCNTL1, DPcnt_Mask, DPcnt_Val); Registers.Unset_Mask (Vswing_Regs (Port).DKL_TX_DPCNTL2, DKL_TX_DP20BITMODE); + + if Config.Need_Loadgen_Select then + declare + Val : Word32; + begin + -- if Port in USBC1_HDMI .. USBC6_HDMI then + -- if Lane = 0 then + -- Val := DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1 (0) or + -- DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2 (2); + -- else + -- Val := DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1 (3) or + -- DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2 (3); + -- end if; + -- else + Val := DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1 (3) or + DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2 (3); + -- end if; + + Registers.Unset_And_Set_Mask + (Register => Vswing_Regs (Port).DKL_TX_DPCNTL2, + Mask_Unset => DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK or + DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK, + Mask_Set => Val); + end; + end if; end loop;
end Set_Vswing_And_Deemphasis; @@ -504,6 +584,7 @@ Link : DP_Link; Train_Set : DP_Info.Train_Set) is + DKL_PCS_DW5_CORE_SOFTRESET : constant := 1 * 2 ** 11; function To_Buf_Trans_Index (Set : DP_Info.Train_Set) return Buffer_Trans_Range is @@ -565,13 +646,24 @@
Set_Vswing_And_Deemphasis (Port, Buf_Trans);
+ if Config.Need_DP_Alt_Switch and not Was_Enabled then + for Lane in 0 .. 1 loop + Set_HIP_For_Port (Port, Lane); + Registers.Unset_Mask + (Register => DKL_PCS_DW5 (Port), + Mask => DKL_PCS_DW5_CORE_SOFTRESET); + end loop; + end if; + Registers.Unset_And_Set_Mask (Register => DDI_BUF_CTL (Port), Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or DDI_BUF_CTL_PORT_REVERSAL or DDI_BUF_CTL_PORT_WIDTH_MASK, Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE or - DDI_BUF_CTL_PORT_WIDTH (Link.Lane_Count)); + DDI_BUF_CTL_PORT_WIDTH (Link.Lane_Count) or + (if Config.Need_TC_PHY_Ownership + then DDI_BUF_CTL_TC_PHY_OWNERSHIP else 0)); Registers.Posting_Read (DDI_BUF_CTL (Port));
if not Was_Enabled then diff --git a/common/tigerlake/hw-gfx-gma-port_detect.adb b/common/tigerlake/hw-gfx-gma-port_detect.adb index 681172b..d9b8f60 100644 --- a/common/tigerlake/hw-gfx-gma-port_detect.adb +++ b/common/tigerlake/hw-gfx-gma-port_detect.adb @@ -16,6 +16,7 @@ with HW.GFX.GMA.Registers; with HW.GFX.GMA.Config_Helpers; with HW.GFX.GMA.Connectors.TC; +with HW.GFX.GMA.Power_And_Clocks;
with HW.Debug; with GNAT.Source_Info; @@ -26,6 +27,7 @@
function SDEISR_MASK (Port : Active_Port_Type) return Word32 is (case Port is + when eDP => 16#1_0000#, when DP1 | HDMI1 => 16#1_0000#, when DP2 | HDMI2 => 16#2_0000#, when DP3 | HDMI3 => 16#4_0000#, @@ -64,22 +66,10 @@ procedure Initialize is INIT_DISPLAY_DETECTED : constant := 1 * 2 ** 0; - Internal_Detected : Boolean; Success : Boolean; begin pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
- -- only for DDI_A / eDP - if Config.Has_Presence_Straps and not Config.Ignore_Presence_Straps then - Registers.Is_Set_Mask - (Register => Registers.DDI_BUF_CTL_A, - Mask => INIT_DISPLAY_DETECTED, - Result => Internal_Detected); - else - Internal_Detected := True; - end if; - Config.Valid_Port (eDP) := Internal_Detected; - Registers.Unset_And_Set_Mask (Register => Registers.SHPD_FILTER_CNT, Mask_Unset => 16#1_ffff#, @@ -116,15 +106,25 @@ TC_HOTPLUG_CTL_HPD_ENABLE (USBC6_DP)); -- also USBC6_HDMI
-- Validity can only be detected via hotplug + Config.Valid_Port (eDP) := True; for Port in DP1 .. HDMI3 loop Config.Valid_Port (Port) := True; end loop;
- -- For Type-C ports, we can check if the IOM PHY status is 'Complete'. + -- For Type-C ports, we can check if the IOM PHY status is 'Complete', + -- then perform the connection flow for all connected ports. + Power_And_Clocks.Power_Up_Aux ; for Port in USBC1_DP .. USBC6_HDMI loop - Connectors.TC.Is_DP_Phy_Mode_Status_Complete - (Port => Config_Helpers.To_GPU_Port (Pipe_Index'First, Port), - Success => Config.Valid_Port (Port)); + declare + G : GPU_Port; + Success : Boolean; + begin + G := Config_Helpers.To_GPU_Port (Pipe_Index'First, Port); + if G in USBC_Port then + Connectors.TC.Connect (G, Success); + Config.Valid_Port (Port) := Success; + end if; + end; end loop;
-- TCCOLD should be blocked first before accessing FIA registers @@ -134,12 +134,14 @@ -- In order to avoid keeping track of the state and constantly -- blocking and unblocking, we just block it once at the beginning and -- leave it that way. - Connectors.TC.TC_Cold_Request (Connectors.TC.Block, Success); - if not Success then - Debug.Put_Line ("Failed to bock TCCOLD, Type-C will not work!"); - for Port in USBC1_DP .. USBC6_HDMI loop - Config.Valid_Port (Port) := False; - end loop; + if not Config.Has_XELPD_Power_Domains then + Connectors.TC.TC_Cold_Request (Connectors.TC.Block, Success); + if not Success then + Debug.Put_Line ("Failed to bock TCCOLD, Type-C will not work!"); + for Port in USBC1_DP .. USBC6_HDMI loop + Config.Valid_Port (Port) := False; + end loop; + end if; end if; end Initialize;
diff --git a/common/tigerlake/hw-gfx-gma-power_and_clocks-tgl.adb b/common/tigerlake/hw-gfx-gma-power_and_clocks-tgl.adb new file mode 100644 index 0000000..b9417af --- /dev/null +++ b/common/tigerlake/hw-gfx-gma-power_and_clocks-tgl.adb @@ -0,0 +1,425 @@ +-- +-- 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 GNAT.Source_Info; +with HW.Debug; +with HW.GFX.GMA.Config; +with HW.GFX.GMA.Registers; +with HW.GFX.GMA.Connectors.TC; + +use type HW.Word64; + +package body HW.GFX.GMA.Power_And_Clocks.TGL is + + type Power_Domain_Types is (Power_Well, Power_DDI, Power_AUX); + subtype PW_Domain is Power_Domain range PW1 .. PW5; + subtype DDI_Domain is Power_Domain range DDI_A .. DDI_USBC6; + subtype AUX_Domain is Power_Domain range AUX_A .. AUX_USBC6; + subtype AUX_USBC_Domain is Power_Domain range AUX_USBC1 .. AUX_USBC6; + + function HIP_INDEX_REG (A : AUX_USBC_Domain) return Registers.Registers_Index + is (if A <= AUX_USBC4 + then Registers.HIP_INDEX_REG0 + else Registers.HIP_INDEX_REG1); + + function HIP_INDEX_VAL (A : AUX_USBC_Domain; Val : Word32) return Word32 is + (case A is + when AUX_USBC1 | AUX_USBC3 | AUX_USBC5 => Val * 2 ** 0, + when AUX_USBC2 | AUX_USBC4 | AUX_USBC6 => Val * 2 ** 8); + + type DKL_Regs is array (AUX_USBC_Domain) of Registers.Registers_Index; + DKL_CMN_UC_DW_27 : constant DKL_Regs := DKL_Regs' + (AUX_USBC1 => Registers.DKL_CMN_UC_DW_27_1, + AUX_USBC2 => Registers.DKL_CMN_UC_DW_27_2, + AUX_USBC3 => Registers.DKL_CMN_UC_DW_27_3, + AUX_USBC4 => Registers.DKL_CMN_UC_DW_27_4, + AUX_USBC5 => Registers.DKL_CMN_UC_DW_27_5, + AUX_USBC6 => Registers.DKL_CMN_UC_DW_27_6); + + ---------------------------------------------------------------------------- + + function Power_Domain_Type (PD : Power_Domain) return Power_Domain_Types is + (if PD in PW_Domain then Power_Well + elsif PD in DDI_Domain then Power_DDI + else Power_AUX); + + type Power_Well_Regs is array (Power_Domain_Types) of Registers.Registers_Index; + PWR_CTL_BIOS : constant Power_Well_Regs := + (Power_Well => Registers.PWR_WELL_CTL_BIOS, + Power_DDI => Registers.PWR_DDI_CTL_BIOS, + Power_AUX => Registers.PWR_AUX_CTL_BIOS); + PWR_CTL_DRIVER : constant Power_Well_Regs := + (Power_Well => Registers.PWR_WELL_CTL_DRIVER, + Power_DDI => Registers.PWR_DDI_CTL_DRIVER, + Power_AUX => Registers.PWR_AUX_CTL_DRIVER); + + package Rep is + function PW_Index (PW : PW_Domain) return natural + with Post => PW_Index'Result < PW_Domain'Range_Length; + function DDI_Index (DDI : DDI_Domain) return natural + with Post => DDI_Index'Result < DDI_Domain'Range_Length; + function AUX_Index (AUX : AUX_Domain) return natural + with Post => Aux_Index'Result < AUX_Domain'Range_Length; + end Rep; + + package body Rep is + function PW_Index (PW : PW_Domain) return natural + with + SPARK_Mode => Off + is + begin + return PW'Enum_Rep - PW1'Enum_Rep; + end PW_Index; + + function DDI_Index (DDI : DDI_Domain) return natural + with + SPARK_Mode => Off + is + begin + return DDI'Enum_Rep - DDI_A'Enum_Rep; + end DDI_Index; + + function AUX_Index (AUX : AUX_Domain) return natural + with + SPARK_Mode => Off + is + begin + return AUX'Enum_Rep - AUX_A'Enum_Rep; + end AUX_Index; + end Rep; + + function PW_Request_Mask (PW : PW_Domain) return Word32 is + (2 * 2 ** (2 * Rep.PW_Index (PW))); + function PW_State_Mask (PW : PW_Domain) return Word32 is + (1 * 2 ** (2 * Rep.PW_Index (PW))); + + function DDI_Request_Mask (DDI : DDI_Domain) return Word32 is + (2 * 2 ** (2 * Rep.DDI_Index (DDI))); + function DDI_State_Mask (DDI : DDI_Domain) return Word32 is + (1 * 2 ** (2 * Rep.DDI_Index (DDI))); + + function AUX_Request_Mask (AUX : AUX_Domain) return Word32 is + (2 * 2 ** (2 * Rep.AUX_Index (AUX))); + function AUX_State_Mask (AUX : AUX_Domain) return Word32 is + (1 * 2 ** (2 * Rep.AUX_Index (AUX))); + + ---------------------------------------------------------------------------- + + FUSE_STATUS_PG0_DIST_STATUS : constant := 1 * 2 ** 27; + type Power_Well_Values is array (PW_Domain) of Word32; + FUSE_STATUS_PGx_DIST_STATUS : constant Power_Well_Values := + (PW1 => 1 * 2 ** 26, + PW2 => 1 * 2 ** 25, + PW3 => 1 * 2 ** 24, + PW4 => 1 * 2 ** 23, + PW5 => 1 * 2 ** 22); + + ---------------------------------------------------------------------------- + + function Power_Request_Mask (PD : Power_Domain) return Word32 is + begin + if PD in PW_Domain then + return PW_Request_Mask (PD); + elsif PD in DDI_Domain then + return DDI_Request_Mask (PD); + else + return AUX_Request_Mask (PD); + end if; + end Power_Request_Mask; + + function Power_State_Mask (PD : Power_Domain) return Word32 is + begin + if PD in PW_Domain then + return PW_State_Mask (PD); + elsif PD in DDI_Domain then + return DDI_State_Mask (PD); + else + return AUX_State_Mask (PD); + end if; + end Power_State_Mask; + + ---------------------------------------------------------------------------- + + type AUX_CTL_Array is array (AUX_USBC_Domain) of Registers.Registers_Index; + AUX_CTL_Regs : constant AUX_CTL_Array := + AUX_CTL_Array' + (AUX_USBC1 => Registers.DDI_AUX_CTL_USBC1, + AUX_USBC2 => Registers.DDI_AUX_CTL_USBC2, + AUX_USBC3 => Registers.DDI_AUX_CTL_USBC3, + AUX_USBC4 => Registers.DDI_AUX_CTL_USBC4, + AUX_USBC5 => Registers.DDI_AUX_CTL_USBC5, + AUX_USBC6 => Registers.DDI_AUX_CTL_USBC6); + + function Aux_To_Port (PD : AUX_USBC_Domain) return USBC_Port + is (case PD is + when AUX_USBC1 => DDI_TC1, + when AUX_USBC2 => DDI_TC2, + when AUX_USBC3 => DDI_TC3, + when AUX_USBC4 => DDI_TC4, + when AUX_USBC5 => DDI_TC5, + when AUX_USBC6 => DDI_TC6); + + procedure Pre_On (PD : Power_Domain) + is + DP_AUX_CH_CTL_TBT_IO : constant := 1 * 2 ** 11; + begin + if PD in AUX_USBC_Domain then + -- Disable TBT IO mode for AUX + Registers.Unset_Mask + (Register => AUX_CTL_Regs (PD), + Mask => DP_AUX_CH_CTL_TBT_IO); + elsif PD = PW1 then + Registers.Wait_Set_Mask + (Register => Registers.FUSE_STATUS, + Mask => FUSE_STATUS_PG0_DIST_STATUS); + 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; + begin + if PD in PW_Domain then + Registers.Wait_Set_Mask (Registers.FUSE_STATUS, + FUSE_STATUS_PGx_DIST_STATUS (PD)); + elsif PD in AUX_USBC_Domain then + Registers.Write (HIP_INDEX_REG (PD), HIP_INDEX_VAL (PD, 2)); + Registers.Wait_Set_Mask + (Register => DKL_CMN_UC_DW_27 (PD), + Mask => DKL_CMN_UC_DW_27_UC_HEALTH); + end if; + end Post_On; + + procedure PD_On (PD : Power_Domain) + is + Ctl1, Ctl2 : Word32; + PD_Type : constant Power_Domain_Types := Power_Domain_Type (PD); + Success : Boolean; + DP_AUX_CH_CTL_TBT_IO : constant := 1 * 2 ** 11; + begin + Pre_On (PD); + + Registers.Read (PWR_CTL_BIOS (PD_Type), Ctl1); + Registers.Read (PWR_CTL_DRIVER (PD_Type), Ctl2); + + if ((Ctl1 or Ctl2) and Power_Request_Mask (PD)) = 0 then + Registers.Wait_Unset_Mask + (Register => PWR_CTL_DRIVER (PD_Type), + Mask => Power_State_Mask (PD)); + end if; + + if (Ctl2 and Power_Request_Mask (PD)) = 0 then + Registers.Set_Mask (PWR_CTL_DRIVER (PD_Type), Power_Request_Mask (PD)); + Registers.Wait_Set_Mask + (Register => PWR_CTL_DRIVER (PD_Type), + Mask => Power_State_Mask (PD), + Success => Success); + + if not Success then + Debug.Put_Line ("Failed to enable power domain!"); + return; + end if; + end if; + + Post_On (PD); + end PD_On; + + procedure PD_Off (PD : Power_Domain) + is + Ctl1, Ctl2 : Word32; + PD_Type : constant Power_Domain_Types := Power_Domain_Type (PD); + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + Registers.Read (PWR_CTL_BIOS (PD_Type), Ctl1); + Registers.Read (PWR_CTL_DRIVER (PD_Type), Ctl2); + + -- PW1 is "always-on" + if PD = PW1 then + return; + end if; + + if ((Ctl1 or Ctl2) and Power_Request_Mask (PD)) /= 0 then + Registers.Wait_Set_Mask + (Register => PWR_CTL_DRIVER (PD_Type), + Mask => Power_State_Mask (PD)); + end if; + + Pre_Off (PD); + + if (Ctl2 and Power_Request_Mask (PD)) /= 0 then + Registers.Unset_Mask (PWR_CTL_DRIVER (PD_Type), Power_Request_Mask (PD)); + Registers.Unset_Mask (PWR_CTL_BIOS (PD_Type), Power_Request_Mask (PD)); + end if; + end PD_Off; + + type Port_Array is array (natural range <>) of Active_Port_Type; + DDI_TC : constant Port_Array := + Port_Array' + (USBC1_DP, USBC2_DP, USBC3_DP, USBC4_DP, USBC5_DP, USBC6_DP, + USBC1_HDMI, USBC2_HDMI, USBC3_HDMI, USBC4_HDMI, USBC5_HDMI, + USBC6_HDMI); + + function Need_PD (PD : Power_Domain; Configs : Pipe_Configs) return Boolean + is + function Any_Port_Is (Port : Active_Port_Type) return Boolean is + (Configs (Primary).Port = Port or Configs (Secondary).Port = Port or + Configs (Tertiary).Port = Port); + + function Any_Port_In (Ports : Port_Array) return Boolean is + begin + for P of Ports loop + if (Configs (Primary).Port = P) or + (Configs (Secondary).Port = P) or + (Configs (Tertiary).Port = P) + then + return True; + end if; + end loop; + return False; + end Any_Port_In; + + function Num_Active_Pipes return Natural is + Count : Natural := 0; + begin + for I in Pipe_Index loop + if Configs (I).Port /= Disabled then + Count := Count + 1; + end if; + end loop; + return Count; + end Num_Active_Pipes; + begin + case PD is + when PW1 | PW2 => + if Num_Active_Pipes >= 1 or Any_Port_In (DDI_TC) then + return True; + end if; + when PW3 => + if Num_Active_Pipes >= 2 or Any_Port_In (DDI_TC) then + return True; + end if; + when PW4 => + if Num_Active_Pipes >= 3 then + return True; + end if; + when PW5 => return False; + when DDI_A | AUX_A => + if Any_Port_Is (DP1) or Any_Port_Is (HDMI1) or Any_Port_Is (eDP) then + return True; + end if; + when DDI_B | AUX_B => + if Any_Port_Is (DP2) or Any_Port_Is (HDMI2) then + return True; + end if; + when DDI_C | AUX_C => + if Any_Port_Is (DP3) or Any_Port_Is (HDMI3) then + return True; + end if; + when DDI_USBC1 | AUX_USBC1 => + return Any_Port_Is (USBC1_DP) or Any_Port_Is (USBC1_HDMI); + when DDI_USBC2 | AUX_USBC2 => + return Any_Port_Is (USBC2_DP) or Any_Port_Is (USBC2_HDMI); + when DDI_USBC3 | AUX_USBC3 => + return Any_Port_Is (USBC3_DP) or Any_Port_Is (USBC3_HDMI); + when DDI_USBC4 | AUX_USBC4 => + return Any_Port_Is (USBC4_DP) or Any_Port_Is (USBC4_HDMI); + when DDI_USBC5 | AUX_USBC5 => + return Any_Port_Is (USBC5_DP) or Any_Port_Is (USBC5_HDMI); + when DDI_USBC6 | AUX_USBC6 => + return Any_Port_Is (USBC6_DP) or Any_Port_Is (USBC6_HDMI); + end case; + + return False; + end Need_PD; + + procedure Aux_Off is + begin + for AUX in reverse AUX_USBC1 .. AUX_USBC6 loop + PD_Off (AUX); + end loop; + end Aux_off; + + procedure Init_Power is + begin + PD_On (PW1); + end Init_Power; + + procedure Power_Set_To (Configs : Pipe_Configs) is + begin + for PD in reverse Power_Domain loop + if not Need_PD (PD, Configs) then + PD_Off (PD); + end if; + end loop; + + for PD in Power_Domain loop + if Need_PD (PD, Configs) then + PD_On (PD); + end if; + end loop; + end Power_Set_To; + + 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); + end if; + end loop; + end Power_Up; + + procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Pipe_Configs) + is + begin + for PD in reverse Power_Domain loop + if (Need_PD (PD, Old_Configs) or Need_PD (PD, Tmp_Configs)) and + not Need_PD (PD, New_Configs) + then + PD_Off (PD); + end if; + end loop; + end Power_Down; + + procedure All_Off is + begin + for AUX in reverse AUX_A .. AUX_USBC6 loop + PD_Off (AUX); + end loop; + + for DDI in reverse DDI_A .. DDI_USBC6 loop + PD_Off (DDI); + end loop; + + for PW in reverse PW1 .. PW5 loop + PD_Off (PW); + end loop; + end All_Off; + +end HW.GFX.GMA.Power_And_Clocks.TGL; diff --git a/common/tigerlake/hw-gfx-gma-power_and_clocks-tgl.ads b/common/tigerlake/hw-gfx-gma-power_and_clocks-tgl.ads new file mode 100644 index 0000000..cfbfe19 --- /dev/null +++ b/common/tigerlake/hw-gfx-gma-power_and_clocks-tgl.ads @@ -0,0 +1,31 @@ +-- (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. +-- + +private package HW.GFX.GMA.Power_And_Clocks.TGL is + + type Power_Domain is + (PW1, PW2, PW3, PW4, PW5, + AUX_A, AUX_B, AUX_C, + AUX_USBC1, AUX_USBC2, AUX_USBC3, AUX_USBC4, AUX_USBC5, AUX_USBC6, + DDI_A, DDI_B, DDI_C, + DDI_USBC1, DDI_USBC2, DDI_USBC3, DDI_USBC4, DDI_USBC5, DDI_USBC6); + + procedure Power_Set_To (Configs : Pipe_Configs); + procedure Power_Up (Old_Configs, New_Configs : Pipe_Configs); + procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Pipe_Configs); + procedure All_Off; + function Need_PD (PD : Power_Domain; Configs : Pipe_Configs) return Boolean; + procedure Init_Power; + procedure Aux_Off; + +end HW.GFX.GMA.Power_And_Clocks.TGL; diff --git a/common/tigerlake/hw-gfx-gma-power_and_clocks-xelpd.adb b/common/tigerlake/hw-gfx-gma-power_and_clocks-xelpd.adb new file mode 100644 index 0000000..b2e9769 --- /dev/null +++ b/common/tigerlake/hw-gfx-gma-power_and_clocks-xelpd.adb @@ -0,0 +1,372 @@ +-- (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 GNAT.Source_Info; +with HW.Debug; +with HW.GFX.GMA.Config; +with HW.GFX.GMA.Registers; +with HW.GFX.GMA.Connectors.TC; + +use type HW.Word64; + +package body HW.GFX.GMA.Power_And_Clocks.XELPD is + + -- Comment lifted from i915: + -- XE_LPD Power Domains + -- + -- Previous platforms required that PG(n-1) be enabled before PG(n). That + -- dependency chain turns into a dependency tree on XE_LPD: + -- + -- PG0 + -- | + -- --PG1-- + -- / \ + -- PGA --PG2-- + -- / | \ + -- PGB PGC PGD + -- + -- Power wells must be enabled from top to bottom and disabled from bottom + -- to top. This allows pipes to be power gated independently. + + type Power_Domain_Types is (Power_Well, Power_DDI, Power_AUX); + subtype PW_Domain is Power_Domain range PW1 .. PWD; + subtype DDI_Domain is Power_Domain range DDI_A .. DDI_USBC4; + subtype AUX_Domain is Power_Domain range AUX_A .. AUX_USBC4; + subtype AUX_USBC_Domain is Power_Domain range AUX_USBC1 .. AUX_USBC4; + + function Power_Domain_Type (PD : Power_Domain) return Power_Domain_Types is + (if PD in PW_Domain then Power_Well + elsif PD in DDI_Domain then Power_DDI + else Power_AUX); + + HIP_INDEX_REG : constant Registers.Registers_Index := Registers.HIP_INDEX_REG0; + function HIP_INDEX_VAL (A : AUX_USBC_Domain; Val : Word32) return Word32 is + (case A is + when AUX_USBC1 | AUX_USBC3 => Val, + when AUX_USBC2 | AUX_USBC4 => Shift_Left (Val, 8)); + + type DKL_Regs is array (AUX_USBC_Domain) of Registers.Registers_Index; + DKL_CMN_UC_DW_27 : constant DKL_Regs := DKL_Regs' + (AUX_USBC1 => Registers.DKL_CMN_UC_DW_27_1, + AUX_USBC2 => Registers.DKL_CMN_UC_DW_27_2, + AUX_USBC3 => Registers.DKL_CMN_UC_DW_27_3, + AUX_USBC4 => Registers.DKL_CMN_UC_DW_27_4); + + type Power_Well_Regs is array (Power_Domain_Types) of Registers.Registers_Index; + PWR_CTL_BIOS : constant Power_Well_Regs := + (Power_Well => Registers.PWR_WELL_CTL_BIOS, + Power_DDI => Registers.PWR_DDI_CTL_BIOS, + Power_AUX => Registers.PWR_AUX_CTL_BIOS); + PWR_CTL_DRIVER : constant Power_Well_Regs := + (Power_Well => Registers.PWR_WELL_CTL_DRIVER, + Power_DDI => Registers.PWR_DDI_CTL_DRIVER, + Power_AUX => Registers.PWR_AUX_CTL_DRIVER); + + FUSE_STATUS_PG0_DIST_STATUS : constant := 1 * 2 ** 27; + type Power_Well_Values is array (PW_Domain) of Word32; + FUSE_STATUS_PGx_DIST_STATUS : constant Power_Well_Values := + (PW1 => 1 * 2 ** 26, + PW2 => 1 * 2 ** 25, + PWA => 1 * 2 ** 21, + PWB => 1 * 2 ** 20, + PWC => 1 * 2 ** 19, + PWD => 1 * 2 ** 18); + + function Power_State_Mask (PD : Power_Domain) return Word32 is + begin + return + 2 ** (2 * (case PD is + when PW1 => 0, + when PW2 => 1, + when PWA => 5, + when PWB => 6, + when PWC => 7, + when PWD => 8, + when AUX_A => 0, + when AUX_B => 1, + when AUX_USBC1 => 5, + when AUX_USBC2 => 6, + when AUX_USBC3 => 7, + when AUX_USBC4 => 8, + when DDI_A => 0, + when DDI_B => 1, + when DDI_USBC1 => 5, + when DDI_USBC2 => 6, + when DDI_USBC3 => 7, + when DDI_USBC4 => 8)); + end Power_State_Mask; + + function Power_Request_Mask (PD : Power_Domain) return Word32 is + begin + return Shift_Left (Power_State_Mask (PD), 1); + end Power_Request_Mask; + + type AUX_CTL_Array is array (AUX_USBC_Domain) of Registers.Registers_Index; + AUX_CTL_Regs : constant AUX_CTL_Array := + AUX_CTL_Array' + (AUX_USBC1 => Registers.DDI_AUX_CTL_USBC1, + AUX_USBC2 => Registers.DDI_AUX_CTL_USBC2, + AUX_USBC3 => Registers.DDI_AUX_CTL_USBC3, + AUX_USBC4 => Registers.DDI_AUX_CTL_USBC4); + + procedure Pre_On (PD : Power_Domain) + is + DP_AUX_CH_CTL_TBT_IO : constant := 1 * 2 ** 11; + begin + if PD in AUX_USBC_Domain then + Registers.Unset_Mask + (Register => AUX_CTL_Regs (PD), + Mask => DP_AUX_CH_CTL_TBT_IO); + elsif PD = PW1 then + Registers.Set_Mask + (Register => Registers.GEN8_CHICKEN_DCPR_1, + Mask => 1 * 2 ** 15); -- DISABLE_FLR_SRC + Registers.Wait_Set_Mask + (Register => Registers.FUSE_STATUS, + Mask => FUSE_STATUS_PG0_DIST_STATUS); + end if; + end Pre_On; + + procedure Post_On (PD : Power_Domain) + is + DKL_CMN_UC_DW_27_UC_HEALTH : constant := 1 * 2 ** 15; + begin + if PD in PW_Domain then + Registers.Wait_Set_Mask (Registers.FUSE_STATUS, + FUSE_STATUS_PGx_DIST_STATUS (PD)); + elsif PD in AUX_USBC_Domain then + Registers.Write (HIP_INDEX_REG, HIP_INDEX_VAL (PD, 2)); + Registers.Wait_Set_Mask + (Register => DKL_CMN_UC_DW_27 (PD), + Mask => DKL_CMN_UC_DW_27_UC_HEALTH); + end if; + end Post_On; + + function Aux_To_Port (PD : AUX_USBC_Domain) return USBC_Port + is (case PD is + when AUX_USBC1 => DDI_TC1, + when AUX_USBC2 => DDI_TC2, + when AUX_USBC3 => DDI_TC3, + when AUX_USBC4 => DDI_TC4); + + 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 PD_On (PD : Power_Domain) is + PD_Type : constant Power_Domain_Types := Power_Domain_Type (PD); + Ctl1, Ctl2 : Word32; + Success : Boolean; + begin + Pre_On (PD); + + Registers.Read (PWR_CTL_BIOS (PD_Type), Ctl1); + Registers.Read (PWR_CTL_DRIVER (PD_Type), Ctl2); + + if ((Ctl1 or Ctl2) and Power_Request_Mask (PD)) = 0 then + Registers.Wait_Unset_Mask + (Register => PWR_CTL_DRIVER (PD_Type), + Mask => Power_State_Mask (PD)); + end if; + + if (Ctl2 and Power_Request_Mask (PD)) = 0 then + Registers.Set_Mask (PWR_CTL_DRIVER (PD_Type), Power_Request_Mask (PD)); + Registers.Wait_Set_Mask + (Register => PWR_CTL_DRIVER (PD_Type), + Mask => Power_State_Mask (PD), + Success => Success); + + if not Success then + if PD in AUX_USBC_Domain then + pragma Debug (Debug.Put_Line ("AUX timeout expected.")); + else + Debug.Put_Line ("Failed to enable power domain!"); + return; + end if; + end if; + end if; + + Post_On (PD); + end PD_On; + + procedure PD_Off (PD : Power_Domain) + is + PD_Type : constant Power_Domain_Types := Power_Domain_Type (PD); + Ctl1, Ctl2 : Word32; + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + Registers.Read (PWR_CTL_BIOS (PD_Type), Ctl1); + Registers.Read (PWR_CTL_DRIVER (PD_Type), Ctl2); + + -- PW1 is "always-on" + if PD = PW1 then + return; + end if; + + if ((Ctl1 or Ctl2) and Power_Request_Mask (PD)) /= 0 then + Registers.Wait_Set_Mask + (Register => PWR_CTL_DRIVER (PD_Type), + Mask => Power_State_Mask (PD)); + end if; + + Pre_Off (PD); + + if (Ctl2 and Power_Request_Mask (PD)) /= 0 then + Registers.Unset_Mask (PWR_CTL_DRIVER (PD_Type), Power_Request_Mask (PD)); + Registers.Unset_Mask (PWR_CTL_BIOS (PD_Type), Power_Request_Mask (PD)); + end if; + end PD_Off; + + function Need_PD (PD : Power_Domain; Configs : Pipe_Configs) return Boolean + is + function Any_Port_Is (Port : Active_Port_Type) return Boolean is + (Configs (Primary).Port = Port or Configs (Secondary).Port = Port or + Configs (Tertiary).Port = Port); + + type Port_Array is array (natural range <>) of Active_Port_Type; + function Any_Port_In (Ports : Port_Array) return Boolean is + begin + for P of Ports loop + if (Configs (Primary).Port = P) or + (Configs (Secondary).Port = P) or + (Configs (Tertiary).Port = P) + then + return True; + end if; + end loop; + return False; + end Any_Port_In; + + DDI_UBSC : constant Port_Array := + Port_Array' + (USBC1_DP, USBC2_DP, USBC3_DP, USBC4_DP, + USBC1_HDMI, USBC2_HDMI, USBC3_HDMI, USBC4_HDMI); + + function Num_Active_Pipes return Natural is + Count : Natural := 0; + begin + for I in Pipe_Index loop + if Configs (I).Port /= Disabled then + Count := Count + 1; + end if; + end loop; + return Count; + end Num_Active_Pipes; + begin + case PD is + when PW1 => + return True; + when PW2 => + return Any_Port_In (DDI_UBSC); + when PWA => + return Num_Active_Pipes >= 1; + when PWB => + return Num_Active_Pipes >= 2; + when PWC => + return Num_Active_Pipes >= 3; + when PWD => + return Num_Active_Pipes >= 4; + when DDI_A | AUX_A => + return Any_Port_Is (DP1) or else Any_Port_Is (HDMI1) or else + Any_Port_Is (eDP); + when DDI_B | AUX_B => + return Any_Port_Is (DP2) or else Any_Port_Is (HDMI2); + when DDI_USBC1 | AUX_USBC1 => + return Any_Port_Is (USBC1_DP) or Any_Port_Is (USBC1_HDMI); + when DDI_USBC2 | AUX_USBC2 => + return Any_Port_Is (USBC2_DP) or Any_Port_Is (USBC2_HDMI); + when DDI_USBC3 | AUX_USBC3 => + return Any_Port_Is (USBC3_DP) or Any_Port_Is (USBC3_HDMI); + when DDI_USBC4 | AUX_USBC4 => + return Any_Port_Is (USBC4_DP) or Any_Port_Is (USBC4_HDMI); + end case; + end Need_PD; + + procedure Aux_Off is + begin + for AUX in reverse AUX_USBC1 .. AUX_USBC4 loop + PD_Off (AUX); + end loop; + PD_Off (AUX_B); + PD_Off (AUX_A); + end Aux_off; + + procedure Init_Power is + begin + PD_On (PW1); + end Init_Power; + + procedure Power_Set_To (Configs : Pipe_Configs) is + begin + for PD in reverse Power_Domain loop + if not Need_PD (PD, Configs) then + PD_Off (PD); + end if; + end loop; + + for PD in Power_Domain loop + if Need_PD (PD, Configs) then + PD_On (PD); + end if; + end loop; + end Power_Set_To; + + procedure Power_Up (Old_Configs, New_Configs : Pipe_Configs) is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + for PD in Power_Domain loop + if not Need_PD (PD, Old_Configs) and Need_PD (PD, New_Configs) then + PD_On (PD); + end if; + end loop; + end Power_Up; + + procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Pipe_Configs) + is + begin + for PD in reverse Power_Domain loop + if (Need_PD (PD, Old_Configs) or Need_PD (PD, Tmp_Configs)) and + not Need_PD (PD, New_Configs) + then + PD_Off (PD); + end if; + end loop; + end Power_Down; + + procedure All_Off is + begin + for AUX in reverse AUX_A .. AUX_USBC4 loop + PD_Off (AUX); + end loop; + + for DDI in reverse DDI_A .. DDI_USBC4 loop + PD_Off (DDI); + end loop; + + for PW in reverse PW1 .. PWD loop + PD_Off (PW); + end loop; + end All_Off; + + procedure Power_Up_Aux is + begin + for Aux in AUX_Domain loop + PD_On (Aux); + end loop; + end Power_Up_Aux; + +end HW.GFX.GMA.Power_And_Clocks.XELPD; diff --git a/common/tigerlake/hw-gfx-gma-power_and_clocks-xelpd.ads b/common/tigerlake/hw-gfx-gma-power_and_clocks-xelpd.ads new file mode 100644 index 0000000..9bbd397 --- /dev/null +++ b/common/tigerlake/hw-gfx-gma-power_and_clocks-xelpd.ads @@ -0,0 +1,30 @@ +-- (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. +-- + +private package HW.GFX.GMA.Power_And_Clocks.XELPD is + + type Power_Domain is + (PW1, PWA, PW2, PWB, PWC, PWD, + AUX_A, AUX_B, AUX_USBC1, AUX_USBC2, AUX_USBC3, AUX_USBC4, + DDI_A, DDI_B, DDI_USBC1, DDI_USBC2, DDI_USBC3, DDI_USBC4); + + procedure Power_Set_To (Configs : Pipe_Configs); + procedure Power_Up (Old_Configs, New_Configs : Pipe_Configs); + procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Pipe_Configs); + procedure All_Off; + function Need_PD (PD : Power_Domain; Configs : Pipe_Configs) return Boolean; + procedure Init_Power; + procedure Aux_Off; + procedure Power_Up_Aux; + +end HW.GFX.GMA.Power_And_Clocks.XELPD; diff --git a/common/tigerlake/hw-gfx-gma-power_and_clocks.adb b/common/tigerlake/hw-gfx-gma-power_and_clocks.adb index 099376a..68636f7 100644 --- a/common/tigerlake/hw-gfx-gma-power_and_clocks.adb +++ b/common/tigerlake/hw-gfx-gma-power_and_clocks.adb @@ -19,25 +19,15 @@ 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; +with HW.GFX.GMA.Power_And_Clocks.TGL; +with HW.GFX.GMA.Power_And_Clocks.XELPD;
use type HW.Word64;
package body HW.GFX.GMA.Power_And_Clocks is
- type Power_Domain is - (PW1, PW2, PW3, PW4, PW5, - AUX_A, AUX_B, AUX_C, - AUX_USBC1, AUX_USBC2, AUX_USBC3, AUX_USBC4, AUX_USBC5, AUX_USBC6, - DDI_A, DDI_B, DDI_C, - DDI_USBC1, DDI_USBC2, DDI_USBC3, DDI_USBC4, DDI_USBC5, DDI_USBC6); - type Power_Domain_Types is (Power_Well, Power_DDI, Power_AUX); - subtype PW_Domain is Power_Domain range PW1 .. PW5; - subtype DDI_Domain is Power_Domain range DDI_A .. DDI_USBC6; - subtype AUX_Domain is Power_Domain range AUX_A .. AUX_USBC6; - subtype AUX_USBC_Domain is Power_Domain range AUX_USBC1 .. AUX_USBC6; - + DARBF_GATING_DIS : constant := 1 * 2 ** 27; PCH_DPMGUNIT_CLOCK_GATE_DISABLE : constant := 1 * 2 ** 15; NDE_RSTWRN_OPT_RST_PCH_Handshake_En : constant := 1 * 2 ** 4;
@@ -46,8 +36,25 @@ DBUF_CTL_DBUF_POWER_REQUEST : constant := 1 * 2 ** 31; DBUF_CTL_TRACKER_STATE_SERVICE_MASK : constant := 16#f8_0000#; DBUF_CTL_TRACKER_STATE_SERVICE_SHIFT : constant := 19; + DBUF_CTL_MIN_TRACKER_STATE_SERVICE_SHIFT : constant := 16; + DBUF_CTL_MIN_TRACKER_STATE_SERVICE_MASK : constant := 16#7_0000#; DBUF_CTL_DBUF_POWER_STATE : constant := 1 * 2 ** 30;
+ type DBUF_Regs_Array is array (natural range 0 .. 3) of Registers.Registers_Index; + DBUF_Regs : constant DBUF_Regs_Array := + DBUF_Regs_Array' + (Registers.DBUF_CTL_S0, + Registers.DBUF_CTL_S1, + Registers.DBUF_CTL_S2, + Registers.DBUF_CTL_S3); + + MBUS_JOIN : constant := 1 * 2 ** 31; + MBUS_HASHING_MODE_MASK : constant := 1 * 2 ** 30; + MBUS_HASHING_MODE_2x2 : constant := 0 * 2 ** 30; + MBUS_HASHING_MODE_1x4 : constant := 1 * 2 ** 30; + MBUS_JOIN_PIPE_SELECT_MASK : constant := 16#1c00_0000#; + MBUS_JOIN_PIPE_SELECT_NONE : constant := 16#1c00_0000#; + ----------------------------------------------------------------------------
MBUS_ABOX_CTL_BW_CREDITS_MASK : constant := 16#3# * 2 ** 20; @@ -78,88 +85,10 @@
----------------------------------------------------------------------------
- DCPR_MASK_MAXLATENCY_MEMUP_CLR : constant := 1 * 2 ** 27; - DCPR_MASK_LPMODE : constant := 1 * 2 ** 26; - DCPR_SEND_RESP_IMM : constant := 1 * 2 ** 25; - DCPR_CLEAR_MEMSTAT_DIS : constant := 1 * 2 ** 24; - - ---------------------------------------------------------------------------- - - function HIP_INDEX_REG (A : AUX_USBC_Domain) return Registers.Registers_Index - is (if A <= AUX_USBC4 - then Registers.HIP_INDEX_REG0 - else Registers.HIP_INDEX_REG1); - - function HIP_INDEX_VAL (A : AUX_USBC_Domain; Val : Word32) return Word32 is - (case A is - when AUX_USBC1 | AUX_USBC3 | AUX_USBC5 => Val * 2 ** 0, - when AUX_USBC2 | AUX_USBC4 | AUX_USBC6 => Val * 2 ** 8); - - type DKL_Regs is array (AUX_USBC_Domain) of Registers.Registers_Index; - DKL_CMN_UC_DW_27 : constant DKL_Regs := DKL_Regs' - (AUX_USBC1 => Registers.DKL_CMN_UC_DW_27_1, - AUX_USBC2 => Registers.DKL_CMN_UC_DW_27_2, - AUX_USBC3 => Registers.DKL_CMN_UC_DW_27_3, - AUX_USBC4 => Registers.DKL_CMN_UC_DW_27_4, - AUX_USBC5 => Registers.DKL_CMN_UC_DW_27_5, - AUX_USBC6 => Registers.DKL_CMN_UC_DW_27_6); - - ---------------------------------------------------------------------------- - - function Power_Domain_Type (PD : Power_Domain) return Power_Domain_Types is - (if PD in PW_Domain then Power_Well - elsif PD in DDI_Domain then Power_DDI - else Power_AUX); - - type Power_Well_Regs is array (Power_Domain_Types) of Registers.Registers_Index; - PWR_CTL_BIOS : constant Power_Well_Regs := - (Power_Well => Registers.PWR_WELL_CTL_BIOS, - Power_DDI => Registers.PWR_DDI_CTL_BIOS, - Power_AUX => Registers.PWR_AUX_CTL_BIOS); - PWR_CTL_DRIVER : constant Power_Well_Regs := - (Power_Well => Registers.PWR_WELL_CTL_DRIVER, - Power_DDI => Registers.PWR_DDI_CTL_DRIVER, - Power_AUX => Registers.PWR_AUX_CTL_DRIVER); - - function PW_Index (PW : PW_Domain) return Natural - is - (Power_Domain'Pos (PW) - Power_Domain'Pos (PW1)); - - function DDI_Index (DDI : DDI_Domain) return Natural - is - (Power_Domain'Pos (DDI) - Power_Domain'Pos (DDI_A)); - - function AUX_Index (AUX : AUX_Domain) return Natural - is - (Power_Domain'Pos (AUX) - Power_Domain'Pos (AUX_A)); - - function PW_Request_Mask (PW : PW_Domain) return Word32 is - (2 * 2 ** (2 * PW_Index (PW))); - function PW_State_Mask (PW : PW_Domain) return Word32 is - (1 * 2 ** (2 * PW_Index (PW))); - - function DDI_Request_Mask (DDI : DDI_Domain) return Word32 is - (2 * 2 ** (2 * DDI_Index (DDI))); - function DDI_State_Mask (DDI : DDI_Domain) return Word32 is - (1 * 2 ** (2 * DDI_Index (DDI))); - - function AUX_Request_Mask (AUX : AUX_Domain) return Word32 is - (2 * 2 ** (2 * AUX_Index (AUX))); - function AUX_State_Mask (AUX : AUX_Domain) return Word32 is - (1 * 2 ** (2 * AUX_Index (AUX))); - - ---------------------------------------------------------------------------- - - FUSE_STATUS_PG0_DIST_STATUS : constant := 1 * 2 ** 27; - type Power_Well_Values is array (PW_Domain) of Word32; - FUSE_STATUS_PGx_DIST_STATUS : constant Power_Well_Values := - (PW1 => 1 * 2 ** 26, - PW2 => 1 * 2 ** 25, - PW3 => 1 * 2 ** 24, - PW4 => 1 * 2 ** 23, - PW5 => 1 * 2 ** 22); - - ---------------------------------------------------------------------------- + DCPR_MASK_MAXLATENCY_MEMUP_CLR : constant := 1 * 2 ** 27; + DCPR_MASK_LPMODE : constant := 1 * 2 ** 26; + DCPR_SEND_RESP_IMM : constant := 1 * 2 ** 25; + DCPR_CLEAR_MEMSTAT_DIS : constant := 1 * 2 ** 24;
TGL_PCODE_MEM_SUBSYSTEM_INFO : constant := 16#d#; TGL_PCODE_MEM_SS_READ_GLOBAL_INFO : constant := 0 * 2 ** 8; @@ -167,222 +96,21 @@ TGL_CDCLK_PREPARE_FOR_CHANGE : constant := 3; TGL_CDCLK_READY_FOR_CHANGE : constant := 1;
- ---------------------------------------------------------------------------- - CDCLK_PLL_ENABLE_PLL_RATIO_MASK : constant := 16#ff#; CDCLK_PLL_ENABLE_PLL_ENABLE : constant := 1 * 2 ** 31; CDCLK_PLL_ENABLE_PLL_LOCK : constant := 1 * 2 ** 30; CDCLK_CD2X_DIV_SEL_MASK : constant := 3 * 2 ** 22; CDCLK_CD2X_DIV_SEL_1 : constant := 0 * 2 ** 22; + CDCLK_CD2X_DIV_SEL_1_5 : constant := 1 * 2 ** 22; CDCLK_CD2X_DIV_SEL_2 : constant := 2 * 2 ** 22; + CDCLK_CD2X_DIV_SEL_4 : constant := 3 * 2 ** 22; CDCLK_CD2X_PIPE_NONE : constant := 7 * 2 ** 19; CDCLK_CTL_CD_FREQ_DECIMAL_MASK : constant := 16#7ff#; + CDCLK_PLL_ENABLE_FREQ_REQ_ACK : constant := 1 * 2 ** 22; + CDCLK_PLL_ENABLE_FREQ_REQ : constant := 1 * 2 ** 23;
----------------------------------------------------------------------------
- function Power_Request_Mask (PD : Power_Domain) return Word32 is - begin - if PD in PW_Domain then - return PW_Request_Mask (PD); - elsif PD in DDI_Domain then - return DDI_Request_Mask (PD); - else - return AUX_Request_Mask (PD); - end if; - end Power_Request_Mask; - - function Power_State_Mask (PD : Power_Domain) return Word32 is - begin - if PD in PW_Domain then - return PW_State_Mask (PD); - elsif PD in DDI_Domain then - return DDI_State_Mask (PD); - else - return AUX_State_Mask (PD); - end if; - end Power_State_Mask; - - type AUX_CTL_Array is array (AUX_USBC_Domain) of Registers.Registers_Index; - AUX_CTL_Regs : constant AUX_CTL_Array := - AUX_CTL_Array' - (AUX_USBC1 => Registers.DDI_AUX_CTL_USBC1, - AUX_USBC2 => Registers.DDI_AUX_CTL_USBC2, - AUX_USBC3 => Registers.DDI_AUX_CTL_USBC3, - AUX_USBC4 => Registers.DDI_AUX_CTL_USBC4, - AUX_USBC5 => Registers.DDI_AUX_CTL_USBC5, - AUX_USBC6 => Registers.DDI_AUX_CTL_USBC6); - - function Aux_To_Port (PD : AUX_USBC_Domain) return USBC_Port - is (case PD is - when AUX_USBC1 => DDI_TC1, - when AUX_USBC2 => DDI_TC2, - when AUX_USBC3 => DDI_TC3, - when AUX_USBC4 => DDI_TC4, - when AUX_USBC5 => DDI_TC5, - when AUX_USBC6 => DDI_TC6); - - 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 - Registers.Unset_Mask - (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; - begin - if PD in PW_Domain then - Registers.Wait_Set_Mask (Registers.FUSE_STATUS, - FUSE_STATUS_PGx_DIST_STATUS (PD)); - elsif PD in AUX_USBC_Domain then - Registers.Write (HIP_INDEX_REG (PD), HIP_INDEX_VAL (PD, 2)); - Registers.Wait_Set_Mask - (Register => DKL_CMN_UC_DW_27 (PD), - Mask => DKL_CMN_UC_DW_27_UC_HEALTH); - end if; - end Post_On; - - procedure PD_On (PD : Power_Domain) - is - Ctl1, Ctl2 : Word32; - PD_Type : constant Power_Domain_Types := Power_Domain_Type (PD); - Success : Boolean; - begin - Pre_On (PD); - - Registers.Read (PWR_CTL_BIOS (PD_Type), Ctl1); - Registers.Read (PWR_CTL_DRIVER (PD_Type), Ctl2); - - if ((Ctl1 or Ctl2) and Power_Request_Mask (PD)) = 0 then - Registers.Wait_Unset_Mask - (Register => PWR_CTL_DRIVER (PD_Type), - Mask => Power_State_Mask (PD)); - end if; - - if (Ctl2 and Power_Request_Mask (PD)) = 0 then - Registers.Set_Mask (PWR_CTL_DRIVER (PD_Type), Power_Request_Mask (PD)); - Registers.Wait_Set_Mask - (Register => PWR_CTL_DRIVER (PD_Type), - Mask => Power_State_Mask (PD), - Success => Success); - - if not Success then - Debug.Put_Line ("Failed to enable power domain!"); - return; - end if; - end if; - - Post_On (PD); - end PD_On; - - procedure PD_Off (PD : Power_Domain) - is - Ctl1, Ctl2 : Word32; - PD_Type : constant Power_Domain_Types := Power_Domain_Type (PD); - begin - pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); - Registers.Read (PWR_CTL_BIOS (PD_Type), Ctl1); - Registers.Read (PWR_CTL_DRIVER (PD_Type), Ctl2); - - if ((Ctl1 or Ctl2) and Power_Request_Mask (PD)) /= 0 then - Registers.Wait_Set_Mask - (Register => PWR_CTL_DRIVER (PD_Type), - Mask => Power_State_Mask (PD)); - end if; - - if (Ctl2 and Power_Request_Mask (PD)) /= 0 then - Registers.Unset_Mask (PWR_CTL_DRIVER (PD_Type), Power_Request_Mask (PD)); - Registers.Unset_Mask (PWR_CTL_BIOS (PD_Type), Power_Request_Mask (PD)); - end if; - end PD_Off; - - type Port_Array is array (natural range <>) of Active_Port_Type; - Conventional_Ports : constant Port_Array := - (DP1, DP2, DP3, HDMI1, HDMI2, HDMI3); - TC_Ports : constant Port_Array := - (USBC1_DP, USBC2_DP, USBC3_DP, USBC4_DP, USBC5_DP, USBC6_DP, - USBC1_HDMI, USBC1_HDMI, USBC1_HDMI, USBC1_HDMI, USBC1_HDMI, - USBC1_HDMI); - - function Need_PD (PD : Power_Domain; Configs : Pipe_Configs) return Boolean - is - function Any_Port_Is (Port : Active_Port_Type) return Boolean is - (Configs (Primary).Port = Port or Configs (Secondary).Port = Port or - Configs (Tertiary).Port = Port); - - function Any_Port_In (Ports : Port_Array) return Boolean is - begin - for P of Ports loop - if (Configs (Primary).Port = P) or - (Configs (Secondary).Port = P) or - (Configs (Tertiary).Port = P) - then - return True; - end if; - end loop; - return False; - end Any_Port_In; - - function Num_Active_Pipes return Natural is - Count : Natural := 0; - begin - for I in Pipe_Index loop - if Configs (I).Port /= Disabled then - Count := Count + 1; - end if; - end loop; - return Count; - end Num_Active_Pipes; - begin - case PD is - when PW1 | PW2 => - return Configs (Primary).Port /= Disabled or Any_Port_In (Conventional_Ports); - when PW3 => - return Configs (Secondary).Port /= Disabled or Any_Port_In (TC_Ports); - when PW4 => - return Configs (Tertiary).Port /= Disabled; - when PW5 => - return False; - when DDI_A | AUX_A => - return Any_Port_Is (DP1) or Any_Port_Is (HDMI1) or Any_Port_Is (eDP); - when DDI_B | AUX_B => - return Any_Port_Is (DP2) or Any_Port_Is (HDMI2); - when DDI_C | AUX_C => - return Any_Port_Is (DP3) or Any_Port_Is (HDMI3); - when DDI_USBC1 | AUX_USBC1 => - return Any_Port_Is (USBC1_DP) or Any_Port_Is (USBC1_HDMI); - when DDI_USBC2 | AUX_USBC2 => - return Any_Port_Is (USBC2_DP) or Any_Port_Is (USBC2_HDMI); - when DDI_USBC3 | AUX_USBC3 => - return Any_Port_Is (USBC3_DP) or Any_Port_Is (USBC3_HDMI); - when DDI_USBC4 | AUX_USBC4 => - return Any_Port_Is (USBC4_DP) or Any_Port_Is (USBC4_HDMI); - when DDI_USBC5 | AUX_USBC5 => - return Any_Port_Is (USBC5_DP) or Any_Port_Is (USBC5_HDMI); - when DDI_USBC6 | AUX_USBC6 => - return Any_Port_Is (USBC6_DP) or Any_Port_Is (USBC6_HDMI); - end case; - end Need_PD; - procedure Get_RefClk (Refclk : out Refclk_Range) is DSSM : Word32; @@ -434,22 +162,45 @@ Refclk_Freq : Frequency_Type; begin Get_Refclk (Refclk_Freq); - Normalized := - (case Refclk_Freq is - when 19_200_000 | 38_400_000 => - (if CDClk <= 172_800_000 then 172_800_000 - elsif CDClk <= 192_000_000 then 192_000_000 - elsif CDClk <= 307_200_000 then 307_200_000 - elsif CDClk <= 326_400_000 then 326_400_000 - elsif CDClk <= 556_800_000 then 556_800_000 - else 652_800_000), - when others => - (if CDClk <= 180_000_000 then 180_000_000 - elsif CDClk <= 192_000_000 then 192_000_000 - elsif CDClk <= 312_000_000 then 312_000_000 - elsif CDClk <= 324_000_000 then 324_000_000 - elsif CDClk <= 552_000_000 then 552_000_000 - else 648_000_000)); + if Config.Has_CDClk_PLL_Crawl then + Normalized := + (case Refclk_Freq is + when 19_200_000 => + (if CDClk <= 172_800_000 then 172_800_000 + elsif CDClk <= 192_000_000 then 192_000_000 + elsif CDClk <= 307_200_000 then 307_200_000 + elsif CDClk <= 556_800_000 then 556_800_000 + else 652_800_000), + when 24_000_000 => + (if CDClk <= 176_000_000 then 176_000_000 + elsif CDClk <= 192_000_000 then 192_000_000 + elsif CDClk <= 312_000_000 then 307_200_000 + elsif CDClk <= 552_000_000 then 552_000_000 + else 648_000_000), + when others => -- 38_400_000 + (if CDClk <= 179_200_000 then 179_200_000 + elsif CDClk <= 192_000_000 then 192_000_000 + elsif CDClk <= 307_200_000 then 307_200_000 + elsif CDClk <= 556_800_000 then 556_800_000 + else 652_800_000)); + else + Normalized := + (case Refclk_Freq is + when 19_200_000 | 38_400_000 => + (if CDClk <= 172_800_000 then 172_800_000 + elsif CDClk <= 192_000_000 then 192_000_000 + elsif CDClk <= 307_200_000 then 307_200_000 + elsif CDClk <= 326_400_000 then 326_400_000 + elsif CDClk <= 556_800_000 then 556_800_000 + else 652_800_000), + when others => + (if CDClk <= 180_000_000 then 180_000_000 + elsif CDClk <= 192_000_000 then 192_000_000 + elsif CDClk <= 312_000_000 then 312_000_000 + elsif CDClk <= 324_000_000 then 324_000_000 + elsif CDClk <= 552_000_000 then 552_000_000 + else 648_000_000)); + end if; end Normalize_CDClk;
procedure Get_Cur_CDClk (CDClk : out Config.CDClk_Range) @@ -466,28 +217,76 @@ procedure Set_CDClk (CDClk_In : Frequency_Type) is subtype PLL_Ratio_Range is natural range 0 .. 68; - function Ratio_For_19_2_MHz (CDCLk : Frequency_Type) return PLL_Ratio_Range is + function Ratio_For_19_2_MHz (CDClk : Frequency_Type) return PLL_Ratio_Range is begin - case CDClk is - when 172_800_000 => return 18; - when 192_000_000 => return 20; - when 307_200_000 => return 32; - when 326_400_000 | 652_800_000 => return 68; - when 556_800_000 => return 58; - when others => return 0; - end case; + if Config.Has_CDClk_PLL_Crawl then + case CDClk is + when 172_800_000 => return 27; + when 192_000_000 => return 20; + when 307_200_000 => return 32; + when 556_800_000 => return 58; + when 652_800_000 => return 68; + when others => return 0; + end case; + else + case CDClk is + when 172_800_000 => return 18; + when 192_000_000 => return 20; + when 307_200_000 => return 32; + when 326_400_000 + | 652_800_000 => return 68; + when 556_800_000 => return 58; + when others => return 0; + end case; + end if; end Ratio_For_19_2_MHz;
- function Ratio_For_24_MHz (CDCLk : Frequency_Type) return PLL_Ratio_Range is + function Ratio_For_38_4_MHz (CDClk : Frequency_Type) return PLL_Ratio_Range is begin - case CDClk is - when 180_800_000 => return 15; - when 192_000_000 => return 16; - when 312_000_000 => return 26; - when 324_000_000 | 648_000_000 => return 54; - when 552_000_000 => return 46; - when others => return 0; - end case; + if Config.Has_CDClk_PLL_Crawl then + case CDClk is + when 179_200_000 => return 14; + when 192_000_000 => return 10; + when 307_200_000 => return 16; + when 556_800_000 => return 29; + when 652_800_000 => return 34; + when others => return 0; + end case; + else + case CDClk is + when 172_800_000 => return 9; + when 192_000_000 => return 10; + when 307_200_000 => return 16; + when 326_400_000 + | 652_800_000 => return 34; + when 556_800_000 => return 29; + when others => return 0; + end case; + end if; + end Ratio_For_38_4_MHz; + + function Ratio_For_24_MHz (CDClk : Frequency_Type) return PLL_Ratio_Range is + begin + if Config.Has_CDClk_PLL_Crawl then + case CDClk is + when 176_000_000 => return 22; + when 192_000_000 => return 16; + when 312_000_000 => return 26; + when 552_000_000 => return 46; + when 648_000_000 => return 54; + when others => return 0; + end case; + else + case CDClk is + when 180_800_000 => return 15; + when 192_000_000 => return 16; + when 312_000_000 => return 26; + when 324_000_000 + | 648_000_000 => return 54; + when 552_000_000 => return 46; + when others => return 0; + end case; + end if; end Ratio_For_24_MHz;
function CDCLK_CTL_CD_FREQ_DECIMAL (Freq : Frequency_Type) return Word32 with @@ -511,7 +310,7 @@ Get_Refclk (Refclk_Freq); case Refclk_Freq is when 19_200_000 => PLL_Ratio := Ratio_For_19_2_MHz (CDClk); - when 38_400_000 => PLL_Ratio := Ratio_For_19_2_MHz (CDClk) / 2; + when 38_400_000 => PLL_Ratio := Ratio_For_38_4_MHz (CDClk); when 24_000_000 => PLL_Ratio := Ratio_For_24_MHz (CDClk); when others => PLL_Ratio := 0; end case; @@ -535,23 +334,44 @@ return; end if;
- Registers.Unset_Mask - (Register => Registers.CDCLK_PLL_ENABLE, - Mask => CDCLK_PLL_ENABLE_PLL_ENABLE); - Registers.Wait_Unset_Mask - (Register => Registers.CDCLK_PLL_ENABLE, - Mask => CDCLK_PLL_ENABLE_PLL_LOCK); + if Config.Has_CDClk_PLL_Crawl then + Registers.Write + (Register => Registers.CDCLK_PLL_ENABLE, + Value => Word32(PLL_Ratio) or + CDCLK_PLL_ENABLE_PLL_ENABLE); + Registers.Write + (Register => Registers.CDCLK_PLL_ENABLE, + Value => Word32(PLL_Ratio) or + CDCLK_PLL_ENABLE_PLL_ENABLE or + CDCLK_PLL_ENABLE_FREQ_REQ);
- Registers.Write - (Register => Registers.CDCLK_PLL_ENABLE, - Value => Word32(PLL_Ratio)); - Registers.Write - (Register => Registers.CDCLK_PLL_ENABLE, - Value => Word32(PLL_Ratio) or CDCLK_PLL_ENABLE_PLL_ENABLE); - Registers.Wait_Set_Mask - (Register => Registers.CDCLK_PLL_ENABLE, - Mask => CDCLK_PLL_ENABLE_PLL_LOCK, - Success => Success); + Registers.Wait_Set_Mask + (Register => Registers.CDCLK_PLL_ENABLE, + Mask => CDCLK_PLL_ENABLE_PLL_LOCK or + CDCLK_PLL_ENABLE_FREQ_REQ_ACK); + Registers.Write + (Register => Registers.CDCLK_PLL_ENABLE, + Value => Word32(PLL_Ratio) or + CDCLK_PLL_ENABLE_PLL_ENABLE); + else + Registers.Unset_Mask + (Register => Registers.CDCLK_PLL_ENABLE, + Mask => CDCLK_PLL_ENABLE_PLL_ENABLE); + Registers.Wait_Unset_Mask + (Register => Registers.CDCLK_PLL_ENABLE, + Mask => CDCLK_PLL_ENABLE_PLL_LOCK); + + Registers.Write + (Register => Registers.CDCLK_PLL_ENABLE, + Value => Word32(PLL_Ratio)); + Registers.Write + (Register => Registers.CDCLK_PLL_ENABLE, + Value => Word32(PLL_Ratio) or CDCLK_PLL_ENABLE_PLL_ENABLE); + Registers.Wait_Set_Mask + (Register => Registers.CDCLK_PLL_ENABLE, + Mask => CDCLK_PLL_ENABLE_PLL_LOCK, + Success => Success); + end if;
if not Success then Debug.Put_Line ("CDClk PLL failed to lock!"); @@ -562,7 +382,9 @@ CD2X := (case (Div_Round_Closest (VCO, CDClk / 1_000)) is when 2 => CDCLK_CD2X_DIV_SEL_1, + when 3 => CDCLK_CD2X_DIV_SEL_1_5, when 4 => CDCLK_CD2X_DIV_SEL_2, + when 8 => CDCLK_CD2X_DIV_SEL_4, when others => CDCLK_CD2X_DIV_SEL_1);
Registers.Write @@ -607,18 +429,11 @@ BW_BUDDY_MASK : Word32; end record; type Bw_Buddy_Info_Array is array (Natural range 0 .. 3) of Bw_Buddy_Info; - Buddy_Info_Wa : constant Bw_Buddy_Info_Array := - -- wa_1409767108_buddy_page_masks - ((1, DDR4, 1), - (1, LPDDR4, 1), - (2, DDR4, 3), - (2, LPDDR4, 3)); Buddy_Info : constant Bw_Buddy_Info_Array := - -- tgl_buddy_page_masks ((1, DDR4, 16#f#), (2, LPDDR4, 16#1c#), (2, DDR4, 16#1f#), - (4, LPDDR4, 16#1c#)); + (4, LPDDR4, 16#38#)); Result : Word64; Module_Type: DRAM_Module_Type; Channels : Natural; @@ -658,7 +473,6 @@ (Register => Registers.BW_BUDDY2_PAGE_MASK, Mask => Buddy_Info (I).BW_BUDDY_MASK);
- -- Wa_22010178259:tgl,rkl Registers.Unset_And_Set_Mask (Register => Registers.BW_BUDDY1_CTL, Mask_Unset => BW_BUDDY_TLB_REQ_TIMER_MASK, @@ -698,11 +512,31 @@ begin pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
- Get_Default_CDClk(Default_CDClk_Freq); - -- USBC AUX is not supposed to be enabled until the connect flow - for AUX in reverse AUX_USBC1 .. AUX_USBC6 loop - PD_Off (AUX); - end loop; + if Config.Has_CDClk_PLL_Crawl then + XELPD.Aux_Off; + else + TGL.Aux_Off; + end if; + + -- Wa_14011294188:ehl,jsl,tgl,rkl,adl-s,adl-p + Registers.Set_Mask + (Register => Registers.PCH_DSPCLK_GATE_D, + Mask => PCH_DPMGUNIT_CLOCK_GATE_DISABLE); + + if Config.Has_CDClk_PLL_Crawl then + -- Wa_22011091694:adlp + Registers.Set_Mask + (Register => Registers.GEN9_CLKGATE_DIS_5, + Mask => 1 * 2 ** 17); --DPCE_GATING_DIS); + + -- i915 calls this the "Bspec/49189 Initialize Sequence" + Registers.Unset_Mask + (Register => Registers.GEN8_CHICKEN_DCPR_1, + Mask => 1 * 2 ** 7); --DDI_CLOCK_REG_ACCESS); + else + -- Display WA #1185 WaDisableDARBFClkGating + Registers.Set_Mask (Registers.GEN9_CLKGATE_DIS_0, DARBF_GATING_DIS); + end if;
Registers.Set_Mask (Register => Registers.NDE_RSTWRN_OPT, @@ -710,14 +544,16 @@
Combo_Phy.Initialize;
- Registers.Wait_Set_Mask - (Register => Registers.FUSE_STATUS, - Mask => FUSE_STATUS_PG0_DIST_STATUS); - PD_On (PW1); + if Config.Has_CDClk_PLL_Crawl then + XELPD.Init_Power; + else + TGL.Init_Power; + end if;
Get_Cur_CDClk (CDClk); Config.CDClk := CDClk; Get_Max_CDClk (Config.Max_CDClk); + Get_Default_CDClk (Default_CDClk_Freq); if Config.CDClk /= Default_CDClk_Freq then Set_CDClk (Default_CDClk_Freq); end if; @@ -725,42 +561,65 @@ Get_RawClk (Rawclk); Config.Raw_Clock := RawClk;
- for PW in PW2 .. PW4 loop - PD_On (PW); - end loop; + if Config.Has_CDClk_PLL_Crawl then + Registers.Unset_And_Set_Mask + (Register => Registers.MBUS_CTL, + Mask_Unset => MBUS_HASHING_MODE_MASK or + MBUS_JOIN or + MBUS_JOIN_PIPE_SELECT_MASK, + Mask_Set => MBUS_HASHING_MODE_1x4 or + MBUS_JOIN or + MBUS_JOIN_PIPE_SELECT_NONE);
- PD_On (DDI_A); - PD_On (AUX_A); + Registers.Unset_And_Set_Mask + (Register => Registers.DBUF_CTL_S0, + Mask_Unset => DBUF_CTL_MIN_TRACKER_STATE_SERVICE_MASK, + Mask_Set => + Shift_Left (3, DBUF_CTL_MIN_TRACKER_STATE_SERVICE_SHIFT)); + else + Registers.Unset_And_Set_Mask + (Register => Registers.DBUF_CTL_S0, + Mask_Unset => DBUF_CTL_TRACKER_STATE_SERVICE_MASK, + Mask_Set => Shift_Left (8, DBUF_CTL_TRACKER_STATE_SERVICE_SHIFT)); + end if;
- -- Enable first DBUF slice + -- Enable required DBUF slices Registers.Set_Mask (Registers.DBUF_CTL_S0, DBUF_CTL_DBUF_POWER_REQUEST); Registers.Posting_Read (Registers.DBUF_CTL_S0); Registers.Wait_Set_Mask (Registers.DBUF_CTL_S0, DBUF_CTL_DBUF_POWER_STATE);
- for I in MBUS_ABOX_CTL'Range loop - Registers.Unset_And_Set_Mask - (Register => MBUS_ABOX_CTL (I), - Mask_Unset => MBUS_ABOX_MASK, - Mask_Set => MBUS_ABOX_CREDITS); - end loop; + if Config.Has_CDClk_PLL_Crawl then + for I in 1 .. 3 loop + Registers.Set_Mask (DBUF_Regs (I), DBUF_CTL_DBUF_POWER_REQUEST); + Registers.Posting_Read (DBUF_Regs (I)); + Registers.Wait_Set_Mask (DBUF_Regs (I), DBUF_CTL_DBUF_POWER_STATE); + end loop; + end if;
- -- Set DBUF Tracker State Service to 8 - Registers.Unset_And_Set_Mask - (Register => Registers.DBUF_CTL_S0, - Mask_Unset => DBUF_CTL_TRACKER_STATE_SERVICE_MASK, - Mask_Set => 8 * 2 ** DBUF_CTL_TRACKER_STATE_SERVICE_SHIFT); - Registers.Unset_And_Set_Mask - (Register => Registers.DBUF_CTL_S2, - Mask_Unset => DBUF_CTL_TRACKER_STATE_SERVICE_MASK, - Mask_Set => 8 * 2 ** DBUF_CTL_TRACKER_STATE_SERVICE_SHIFT); + if not Config.Has_CDClk_PLL_Crawl then + for I in MBUS_ABOX_CTL'Range loop + Registers.Unset_And_Set_Mask + (Register => MBUS_ABOX_CTL (I), + Mask_Unset => MBUS_ABOX_MASK, + Mask_Set => MBUS_ABOX_CREDITS); + end loop; + end if;
Configure_Bandwidth_Buddy;
-- Display WA #14011508470 tgl,dg1,rkl,adl-s,adl-p Registers.Set_Mask (Register => Registers.GEN11_CHICKEN_DCPR_2, - Mask => DCPR_MASK_MAXLATENCY_MEMUP_CLR or DCPR_MASK_LPMODE or - DCPR_SEND_RESP_IMM or DCPR_CLEAR_MEMSTAT_DIS); + Mask => DCPR_MASK_MAXLATENCY_MEMUP_CLR or + DCPR_MASK_LPMODE or + DCPR_SEND_RESP_IMM or + DCPR_CLEAR_MEMSTAT_DIS); + + if Config.Has_CDClk_PLL_Crawl then + Registers.Write + (Register => Registers.DISPLAY_ERR_FATAL_MASK, + Value => 16#ffff_ffff#); + end if; end Initialize;
procedure Limit_Dotclocks @@ -776,9 +635,11 @@
procedure Update_CDClk (Configs : in out Pipe_Configs) is - New_CDClk : constant Frequency_Type := - Config_Helpers.Highest_Dotclock (Configs); + New_CDClk : Frequency_Type; begin + Normalize_CDClk + (Div_Round_Up (Config_Helpers.Highest_Dotclock (Configs), 2), + New_CDClk); Set_CDClk (New_CDClk); Config_Helpers.Limit_Dotclocks (Configs, Config.CDClk); end Update_CDClk; @@ -800,53 +661,33 @@ begin pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
- for PD in reverse Power_Domain loop - if not Need_PD (PD, Configs) then - PD_Off (PD); - end if; - end loop; - - for PD in Power_Domain loop - if Need_PD (PD, Configs) then - PD_On (PD); - end if; - end loop; + if Config.Has_XELPD_Power_Domains then + XELPD.Power_Set_To (Configs); + else + TGL.Power_Set_To (Configs); + end if; end Power_Set_To;
- procedure Power_Up (Old_Configs, New_Configs : Pipe_Configs) - is - Success : Boolean; + procedure Power_Up (Old_Configs, New_Configs : Pipe_Configs) is 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"); + if Config.Has_XELPD_Power_Domains then + XELPD.Power_Up (Old_Configs, New_Configs); + else + TGL.Power_Up (Old_Configs, New_Configs); 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); - end if; - end loop; end Power_Up;
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 - if (Need_PD (PD, Old_Configs) or Need_PD (PD, Tmp_Configs)) and - not Need_PD (PD, New_Configs) - then - PD_Off (PD); - end if; - end loop;
- Connectors.TC.TC_Cold_Request (Connectors.TC.Unblock, Success); - if not Success then - Debug.Put_Line ("Failed to unblock TCCOLD"); + if Config.Has_XELPD_Power_Domains then + XELPD.Power_Down (Old_Configs, Tmp_Configs, New_Configs); + else + TGL.Power_Down (Old_Configs, Tmp_Configs, New_Configs); end if; end Power_Down;
@@ -860,28 +701,31 @@ begin pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
- Registers.Unset_Mask - (Registers.DBUF_CTL_S0, DBUF_CTL_DBUF_POWER_REQUEST); - Registers.Wait_Unset_Mask - (Registers.DBUF_CTL_S0, DBUF_CTL_DBUF_POWER_STATE); + for I in reverse DBUF_Regs'Range loop + Registers.Unset_Mask + (DBUF_Regs (I), DBUF_CTL_DBUF_POWER_REQUEST); + Registers.Wait_Unset_Mask + (DBUF_Regs (I), DBUF_CTL_DBUF_POWER_STATE); + end loop;
-- Disable CD clock, bypass frequency is Refclk / 2 Get_Refclk (Refclk); Set_CDClk (Refclk / 2);
- for AUX in reverse AUX_A .. AUX_USBC6 loop - PD_Off (AUX); - end loop; - - for DDI in reverse DDI_A .. DDI_USBC6 loop - PD_Off (DDI); - end loop; - - for PW in reverse PW1 .. PW5 loop - PD_Off (PW); - end loop; + if Config.Has_XELPD_Power_Domains then + XELPD.All_Off; + else + TGL.All_Off; + end if;
Combo_Phy.All_Off; end Post_All_Off;
+ procedure Power_Up_Aux is + begin + if Config.Has_XELPD_Power_Domains then + XELPD.Power_Up_Aux; + end if; + end Power_Up_Aux; + end HW.GFX.GMA.Power_And_Clocks; diff --git a/common/tigerlake/hw-gfx-gma-power_and_clocks.ads b/common/tigerlake/hw-gfx-gma-power_and_clocks.ads index b3302fb..1ea09ae 100644 --- a/common/tigerlake/hw-gfx-gma-power_and_clocks.ads +++ b/common/tigerlake/hw-gfx-gma-power_and_clocks.ads @@ -40,6 +40,8 @@ procedure Power_Up (Old_Configs, New_Configs : Pipe_Configs); procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Pipe_Configs);
+ procedure Power_Up_Aux; + procedure Get_Refclk (Refclk : out Refclk_Range);
end HW.GFX.GMA.Power_And_Clocks;