Attention is currently required from: Tim Wawrzynczak.

Dinesh Gehlot would like Tim Wawrzynczak to review this change.

View Change

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;

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

Gerrit-Project: libgfxinit
Gerrit-Branch: cros
Gerrit-Change-Id: Id01752a41e4e401a5f759453c12f368395eebdf2
Gerrit-Change-Number: 82146
Gerrit-PatchSet: 1
Gerrit-Owner: Dinesh Gehlot <digehlot@google.com>
Gerrit-Reviewer: Tim Wawrzynczak <inforichland@gmail.com>
Gerrit-Attention: Tim Wawrzynczak <inforichland@gmail.com>
Gerrit-MessageType: newchange