blob: 446fa6625d438c71ade1abeeaf8a1e2ec3280a68 [file] [log] [blame] [edit]
--
-- 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.Registers;
package body HW.GFX.GMA.Combo_Phy is
PORT_PCS_DW1_DCC_MODE_SELECT_MASK : constant := 3 * 2 ** 20;
PORT_PCS_DW1_DCC_MODE_SELECT_CONTINUOUS : constant := 3 * 2 ** 20;
PORT_COMP_DW0_COMP_INIT : constant := 1 * 2 ** 31;
ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_DIV2 : constant := 1 * 2 ** 29;
PORT_CL_DW5_POWER_DOWN_ENABLE : constant := 1 * 2 ** 4;
PHY_MISC_DE_TO_IO_COMP_PWR_DOWN : constant := 1 * 2 ** 23;
PORT_TX_DW8_ODCC_DIV_SEL_MASK : constant := 3 * 2 ** 29;
PORT_TX_DW8_ODCC_CLKSEL : constant := 1 * 2 ** 31;
PORT_COMP_DW8_IREFGEN : constant := 1 * 2 ** 24;
PORT_COMP_DW1_REF_MASK : constant := 16#ff_00ff#;
type Combo_Phy is (DDI_A, DDI_B, DDI_C);
type Phy_Regs_Record is record
PHY_MISC : Registers.Registers_Index;
PORT_CL_DW5 : Registers.Registers_Index;
PORT_COMP_DW0 : Registers.Registers_Index;
PORT_COMP_DW1 : Registers.Registers_Index;
PORT_COMP_DW3 : Registers.Registers_Index;
PORT_TX_DW8_LN0 : Registers.Registers_Index;
PORT_TX_DW8_GRP : Registers.Registers_Index;
PORT_PCS_DW1_LN0 : Registers.Registers_Index;
PORT_PCS_DW1_GRP : Registers.Registers_Index;
PORT_COMP_DW8 : Registers.Registers_Index;
PORT_COMP_DW9 : Registers.Registers_Index;
PORT_COMP_DW10 : Registers.Registers_Index;
end record;
type Combo_Phy_Regs is array (Combo_Phy) of Phy_Regs_Record;
Phy_Regs : constant Combo_Phy_Regs := Combo_Phy_Regs'
(DDI_A => Phy_Regs_Record'
(PHY_MISC => Registers.PHY_MISC_A,
PORT_CL_DW5 => Registers.PORT_CL_DW5_A,
PORT_COMP_DW0 => Registers.PORT_COMP_DW0_A,
PORT_COMP_DW1 => Registers.PORT_COMP_DW1_A,
PORT_COMP_DW3 => Registers.PORT_COMP_DW3_A,
PORT_TX_DW8_LN0 => Registers.PORT_TX_DW8_LN0_A,
PORT_TX_DW8_GRP => Registers.PORT_TX_DW8_GRP_A,
PORT_PCS_DW1_LN0 => Registers.PORT_PCS_DW1_LN0_A,
PORT_PCS_DW1_GRP => Registers.PORT_PCS_DW1_GRP_A,
PORT_COMP_DW8 => Registers.PORT_COMP_DW8_A,
PORT_COMP_DW9 => Registers.PORT_COMP_DW9_A,
PORT_COMP_DW10 => Registers.PORT_COMP_DW10_A),
DDI_B => Phy_Regs_Record'
(PHY_MISC => Registers.PHY_MISC_B,
PORT_CL_DW5 => Registers.PORT_CL_DW5_B,
PORT_COMP_DW0 => Registers.PORT_COMP_DW0_B,
PORT_COMP_DW1 => Registers.PORT_COMP_DW1_B,
PORT_COMP_DW3 => Registers.PORT_COMP_DW3_B,
PORT_TX_DW8_LN0 => Registers.PORT_TX_DW8_LN0_B,
PORT_TX_DW8_GRP => Registers.PORT_TX_DW8_GRP_B,
PORT_PCS_DW1_LN0 => Registers.PORT_PCS_DW1_LN0_B,
PORT_PCS_DW1_GRP => Registers.PORT_PCS_DW1_GRP_B,
PORT_COMP_DW8 => Registers.PORT_COMP_DW8_B,
PORT_COMP_DW9 => Registers.PORT_COMP_DW9_B,
PORT_COMP_DW10 => Registers.PORT_COMP_DW10_B),
DDI_C => Phy_Regs_Record'
(PHY_MISC => Registers.PHY_MISC_C,
PORT_CL_DW5 => Registers.PORT_CL_DW5_C,
PORT_COMP_DW0 => Registers.PORT_COMP_DW0_C,
PORT_COMP_DW1 => Registers.PORT_COMP_DW1_C,
PORT_COMP_DW3 => Registers.PORT_COMP_DW3_C,
PORT_TX_DW8_LN0 => Registers.PORT_TX_DW8_LN0_C,
PORT_TX_DW8_GRP => Registers.PORT_TX_DW8_GRP_C,
PORT_PCS_DW1_LN0 => Registers.PORT_PCS_DW1_LN0_C,
PORT_PCS_DW1_GRP => Registers.PORT_PCS_DW1_GRP_C,
PORT_COMP_DW8 => Registers.PORT_COMP_DW8_C,
PORT_COMP_DW9 => Registers.PORT_COMP_DW9_C,
PORT_COMP_DW10 => Registers.PORT_COMP_DW10_C));
procedure Propagate_To_Group
(Lane0_Register : Registers.Registers_Index;
Mask_Unset : Word32;
Mask_Set : Word32;
Group_Register : Registers.Registers_Index)
is
Value : Word32;
begin
-- Read from lane 0 and write to the group
Registers.Read (Lane0_Register, Value);
Value := (Value and not Mask_Unset) or Mask_Set;
Registers.Write (Group_Register, Value);
end Propagate_To_Group;
procedure Config_DCC_SusClk (Phy : Combo_Phy) is
begin
Propagate_To_Group
(Lane0_Register => Phy_Regs (Phy).PORT_TX_DW8_LN0,
Mask_Unset => PORT_TX_DW8_ODCC_DIV_SEL_MASK,
Mask_Set => PORT_TX_DW8_ODCC_CLKSEL or
ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_DIV2,
Group_Register => Phy_Regs (Phy).PORT_TX_DW8_GRP);
Propagate_To_Group
(Lane0_Register => Phy_Regs (Phy).PORT_PCS_DW1_LN0,
Mask_Unset => PORT_PCS_DW1_DCC_MODE_SELECT_MASK,
Mask_Set => PORT_PCS_DW1_DCC_MODE_SELECT_CONTINUOUS,
Group_Register => Phy_Regs (Phy).PORT_PCS_DW1_GRP);
end Config_DCC_SusClk;
procedure Config_Procmon_Reference (Phy : Combo_Phy)
is
type Procmon_Voltage is (VOLT_0_85, VOLT_0_95, VOLT_1_05);
type Procmon_Process is (DOT0, DOT1);
type Procmon_References is record
DW1 : Word32;
DW9 : Word32;
DW10 : Word32;
end record;
DOT0_VOLT_0_85 : constant Procmon_References :=
(DW1 => 16#0000_0000#,
DW9 => 16#62ab_67bb#,
DW10 => 16#5191_4f96#);
DOT0_VOLT_0_95 : constant Procmon_References :=
(DW1 => 16#0000_0000#,
DW9 => 16#86e1_72c7#,
DW10 => 16#77ca_5eab#);
DOT0_VOLT_1_05 : constant Procmon_References :=
(DW1 => 16#0000_0000#,
DW9 => 16#98fa_82dd#,
DW10 => 16#89e4_6dc1#);
DOT1_VOLT_0_95 : constant Procmon_References :=
(DW1 => 16#0000_0000#,
DW9 => 16#93f8_7fe1#,
DW10 => 16#8ae8_71c5#);
DOT1_VOLT_1_05 : constant Procmon_References :=
(DW1 => 16#0044_0000#,
DW9 => 16#9a00_ab25#,
DW10 => 16#8ae3_8ff1#);
procedure Read_DW3 (Phy : Combo_Phy; References : out Procmon_References)
is
DW3, Tmp : Word32;
Process : Procmon_Process;
Voltage : Procmon_Voltage;
PROCESS_MASK : constant := 7 * 2 ** 26;
VOLTAGE_MASK : constant := 3 * 2 ** 24;
begin
Registers.Read (Phy_Regs (Phy).PORT_COMP_DW3, DW3);
Tmp := Shift_Right (DW3 and VOLTAGE_MASK, 24);
case (Tmp) is
when 0 => Voltage := VOLT_0_85;
when 1 => Voltage := VOLT_0_95;
when 2 => Voltage := VOLT_1_05;
when others => Voltage := VOLT_0_85;
end case;
Tmp := Shift_Right (DW3 and PROCESS_MASK, 26);
case (Tmp) is
when 0 => Process := DOT0;
when 1 => Process := DOT1;
when others => Process := DOT0;
end case;
if Process = DOT0 then
case (Voltage) is
when VOLT_0_85 => References := DOT0_VOLT_0_85;
when VOLT_0_95 => References := DOT0_VOLT_0_95;
when VOLT_1_05 => References := DOT0_VOLT_1_05;
end case;
else
case (Voltage) is
-- [DOT1, VOLT_0_85] is actually an invalid combination
when VOLT_0_95 | VOLT_0_85 => References := DOT1_VOLT_0_95;
when VOLT_1_05 => References := DOT1_VOLT_1_05;
end case;
end if;
end Read_DW3;
References : Procmon_References;
begin
Read_DW3 (Phy, References);
Registers.Unset_And_Set_Mask (Register => Phy_Regs (Phy).PORT_COMP_DW1,
Mask_Unset => PORT_COMP_DW1_REF_MASK,
Mask_Set => References.DW1);
Registers.Write (Phy_Regs (Phy).PORT_COMP_DW9 , References.DW9);
Registers.Write (Phy_Regs (Phy).PORT_COMP_DW10, References.DW10);
end Config_Procmon_Reference;
function Phy_Is_Master (Phy : Combo_Phy) return Boolean is
begin
case Phy is
when DDI_A => return True;
when others => return False;
end case;
end Phy_Is_Master;
procedure Initialize
is
Was_Enabled : Boolean;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
-- Initialize all combo PHYs with Combo PHY DDI Buffer Combo PHY Init Sequence
for Phy in Combo_Phy'range loop
Registers.Is_Set_Mask (
Phy_Regs (Phy).PORT_COMP_DW0,
PORT_COMP_DW0_COMP_INIT,
Was_Enabled);
if not Was_Enabled then
Config_DCC_SusClk (Phy);
Registers.Unset_Mask
(Phy_Regs (Phy).PHY_MISC,
PHY_MISC_DE_TO_IO_COMP_PWR_DOWN);
Config_Procmon_Reference (Phy);
if Phy_Is_Master (Phy) then
Registers.Set_Mask (Register => Phy_Regs (Phy).PORT_COMP_DW8,
Mask => PORT_COMP_DW8_IREFGEN);
end if;
Registers.Set_Mask (Register => Phy_Regs (Phy).PORT_COMP_DW0,
Mask => PORT_COMP_DW0_COMP_INIT);
Registers.Set_Mask (Register => Phy_Regs (Phy).PORT_CL_DW5,
Mask => PORT_CL_DW5_POWER_DOWN_ENABLE);
end if;
end loop;
end Initialize;
procedure All_Off is
begin
for Phy in Combo_Phy'range loop
Registers.Set_Mask (Phy_Regs (Phy).PHY_MISC,
PHY_MISC_DE_TO_IO_COMP_PWR_DOWN);
Registers.Unset_Mask (Phy_Regs (Phy).PORT_COMP_DW0,
PORT_COMP_DW0_COMP_INIT);
end loop;
end All_Off;
end HW.GFX.GMA.Combo_Phy;