diff --git a/common/broxton/Makefile.inc b/common/broxton/Makefile.inc index c4360ecf9f..90241b2f20 100644 --- a/common/broxton/Makefile.inc +++ b/common/broxton/Makefile.inc @@ -1,3 +1,4 @@ +gfxinit-y += hw-gfx-gma-ddi_phy.adb gfxinit-y += hw-gfx-gma-ddi_phy.ads gfxinit-y += hw-gfx-gma-plls.adb gfxinit-y += hw-gfx-gma-plls.ads diff --git a/common/broxton/hw-gfx-gma-ddi_phy.adb b/common/broxton/hw-gfx-gma-ddi_phy.adb new file mode 100644 index 0000000000..83c7c28024 --- /dev/null +++ b/common/broxton/hw-gfx-gma-ddi_phy.adb @@ -0,0 +1,262 @@ +-- +-- Copyright (C) 2017 secunet Security Networks AG +-- +-- 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; + +use HW.GFX.GMA.Registers; + +package body HW.GFX.GMA.DDI_Phy is + + subtype Dual_Channel is T range BC .. BC; + + type DDI_Range is record + First : DDI_Phy_Port; + Last : DDI_Phy_Port; + end record; + type DDI_Range_Array is array (T) of DDI_Range; + DDIs : constant DDI_Range_Array := + (A => (DIGI_A, DIGI_A), + BC => (DIGI_B, DIGI_C)); + + ---------------------------------------------------------------------------- + + type CL1CM is record + DW0 : Registers_Index; + DW9 : Registers_Index; + DW10 : Registers_Index; + DW28 : Registers_Index; + DW30 : Registers_Index; + end record; + type CL1CM_Array is array (T) of CL1CM; + PORT_CL1CM : constant CL1CM_Array := + (A => + (DW0 => BXT_PORT_CL1CM_DW0_A, + DW9 => BXT_PORT_CL1CM_DW9_A, + DW10 => BXT_PORT_CL1CM_DW10_A, + DW28 => BXT_PORT_CL1CM_DW28_A, + DW30 => BXT_PORT_CL1CM_DW30_A), + BC => + (DW0 => BXT_PORT_CL1CM_DW0_BC, + DW9 => BXT_PORT_CL1CM_DW9_BC, + DW10 => BXT_PORT_CL1CM_DW10_BC, + DW28 => BXT_PORT_CL1CM_DW28_BC, + DW30 => BXT_PORT_CL1CM_DW30_BC)); + + type CL2CM is record + DW6 : Registers_Index; + end record; + type CL2CM_Array is array (Dual_Channel) of CL2CM; + PORT_CL2CM : constant CL2CM_Array := + (BC => (DW6 => BXT_PORT_CL2CM_DW6_BC)); + + type Port_Ref_Regs is record + DW3 : Registers_Index; + DW6 : Registers_Index; + DW8 : Registers_Index; + end record; + type Port_Ref_Array is array (T) of Port_Ref_Regs; + PORT_REF : constant Port_Ref_Array := + (A => + (DW3 => BXT_PORT_REF_DW3_A, + DW6 => BXT_PORT_REF_DW6_A, + DW8 => BXT_PORT_REF_DW8_A), + BC => + (DW3 => BXT_PORT_REF_DW3_BC, + DW6 => BXT_PORT_REF_DW6_BC, + DW8 => BXT_PORT_REF_DW8_BC)); + + type Regs is array (T) of Registers_Index; + PHY_CTL_FAMILY : constant Regs := + (A => BXT_PHY_CTL_FAM_EDP, BC => BXT_PHY_CTL_FAM_DDI); + + type DDI_Regs is array (DDI_Phy_Port) of Registers_Index; + PHY_CTL : constant DDI_Regs := + (DIGI_A => BXT_PHY_CTL_A, + DIGI_B => BXT_PHY_CTL_B, + DIGI_C => BXT_PHY_CTL_C); + + ---------------------------------------------------------------------------- + + type Values is array (T) of Word32; + GT_DISPLAY_POWER_ON : constant Values := + (A => 1 * 2 ** 1, + BC => 1 * 2 ** 0); + + PORT_CL1CM_PHY_POWER_GOOD : constant := 1 * 2 ** 16; + PORT_CL1CM_PHY_RESERVED : constant := 1 * 2 ** 7; + + PORT_CL1CM_IREFxRC_OFFSET_SHIFT : constant := 8; + PORT_CL1CM_IREFxRC_OFFSET_MASK : constant := 16#ff# * 2 ** 8; + + PORT_CL1CM_OCL1_POWER_DOWN_EN : constant := 1 * 2 ** 23; + PORT_CL1CM_OLDO_DYN_POWER_DOWN_EN : constant := 1 * 2 ** 22; + PORT_CL1CM_SUS_CLK_CONFIG : constant := 3 * 2 ** 0; + + PORT_CL2CM_OLDO_DYN_POWER_DOWN_EN : constant := 1 * 2 ** 28; + + PORT_REF_GRC_DONE : constant := 1 * 2 ** 22; + + PORT_REF_GRC_CODE_SHIFT : constant := 24; + PORT_REF_GRC_FAST_SHIFT : constant := 16; + PORT_REF_GRC_SLOW_SHIFT : constant := 8; + + PORT_REF_GRC_DISABLE : constant := 1 * 2 ** 15; + PORT_REF_GRC_READY_OVERRIDE : constant := 1 * 2 ** 1; + + PHY_CTL_FAM_CMN_RESET_DIS : constant := 1 * 2 ** 31; + + PHY_CTL_CMNLANE_POWERDOWN_ACK : constant := 1 * 2 ** 10; + + ---------------------------------------------------------------------------- + + procedure Is_Enabled (Phy : in T; Enabled : out Boolean) + is + Phy_Pwr : Word32; + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Is_Set_Mask (BXT_P_CR_GT_DISP_PWRON, GT_DISPLAY_POWER_ON (Phy), Enabled); + + if Enabled then + Read (PORT_CL1CM (Phy).DW0, Phy_Pwr); + Enabled := + (Phy_Pwr and (PORT_CL1CM_PHY_POWER_GOOD or PORT_CL1CM_PHY_RESERVED)) + = PORT_CL1CM_PHY_POWER_GOOD; + pragma Debug (not Enabled, Debug.Put_Line ("DDI PHY power unsettled")); + end if; + + if Enabled then + Is_Set_Mask (PHY_CTL_FAMILY (Phy), PHY_CTL_FAM_CMN_RESET_DIS, Enabled); + pragma Debug (not Enabled, Debug.Put_Line ("DDI PHY still in reset")); + end if; + + for DDI in DDIs (Phy).First .. DDIs (Phy).Last loop + if Enabled then + declare + Common_Lane_Powerdown : Boolean; + begin + Is_Set_Mask + (Register => PHY_CTL (DDI), + Mask => PHY_CTL_CMNLANE_POWERDOWN_ACK, + Result => Common_Lane_Powerdown); + Enabled := not Common_Lane_Powerdown; + pragma Debug + (not Enabled, Debug.Put_Line ("Common lane powered down")); + end; + end if; + end loop; + end Is_Enabled; + + procedure Power_On_Phy (Phy : T) + with + Pre => True + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Set_Mask (BXT_P_CR_GT_DISP_PWRON, GT_DISPLAY_POWER_ON (Phy)); + + Wait + (Register => PORT_CL1CM (Phy).DW0, + Mask => PORT_CL1CM_PHY_POWER_GOOD or + PORT_CL1CM_PHY_RESERVED, + Value => PORT_CL1CM_PHY_POWER_GOOD, + TOut_MS => 1); -- 50~100us + + Unset_And_Set_Mask + (Register => PORT_CL1CM (Phy).DW9, + Mask_Unset => PORT_CL1CM_IREFxRC_OFFSET_MASK, + Mask_Set => Shift_Left + (16#e4#, PORT_CL1CM_IREFxRC_OFFSET_SHIFT)); + Unset_And_Set_Mask + (Register => PORT_CL1CM (Phy).DW10, + Mask_Unset => PORT_CL1CM_IREFxRC_OFFSET_MASK, + Mask_Set => Shift_Left + (16#e4#, PORT_CL1CM_IREFxRC_OFFSET_SHIFT)); + + Set_Mask + (Register => PORT_CL1CM (Phy).DW28, + Mask => PORT_CL1CM_OCL1_POWER_DOWN_EN or + PORT_CL1CM_OLDO_DYN_POWER_DOWN_EN or + PORT_CL1CM_SUS_CLK_CONFIG); + + if Phy in Dual_Channel then + Set_Mask (PORT_CL2CM (Phy).DW6, PORT_CL2CM_OLDO_DYN_POWER_DOWN_EN); + end if; + + if Phy = BC then + declare + GRC_Val : Word32; + begin + -- take RCOMP calibration result from A + + Wait_Set_Mask (PORT_REF (A).DW3, PORT_REF_GRC_DONE, TOut_MS => 10); + Read (PORT_REF (A).DW6, GRC_Val); + GRC_Val := Shift_Right (GRC_Val, PORT_REF_GRC_CODE_SHIFT); + + -- use it for BC too + GRC_Val := Shift_Left (GRC_Val, PORT_REF_GRC_FAST_SHIFT) or + Shift_Left (GRC_Val, PORT_REF_GRC_SLOW_SHIFT) or + GRC_Val; + Write (PORT_REF (Phy).DW6, GRC_Val); + + Set_Mask + (Register => PORT_REF (Phy).DW8, + Mask => PORT_REF_GRC_DISABLE or + PORT_REF_GRC_READY_OVERRIDE); + end; + end if; + + Set_Mask (PHY_CTL_FAMILY (Phy), PHY_CTL_FAM_CMN_RESET_DIS); + end Power_On_Phy; + + procedure Power_On (Phy : T) + is + Phy_A_Enabled : Boolean := False; + Enabled : Boolean; + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Is_Enabled (Phy, Enabled); + pragma Debug (Enabled, Debug.Put_Line ("DDI PHY already enabled")); + + if not Enabled then + if Phy = BC then + -- PHY BC needs RCOMP calibration results from PHY A + Is_Enabled (A, Phy_A_Enabled); + if not Phy_A_Enabled then + Power_On_Phy (A); + end if; + end if; + + Power_On_Phy (Phy); + + if Phy = BC and then not Phy_A_Enabled then + Power_Off (A); + end if; + end if; + end Power_On; + + procedure Power_Off (Phy : T) is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Unset_Mask (PHY_CTL_FAMILY (Phy), PHY_CTL_FAM_CMN_RESET_DIS); + Unset_Mask (BXT_P_CR_GT_DISP_PWRON, GT_DISPLAY_POWER_ON (Phy)); + end Power_Off; + +end HW.GFX.GMA.DDI_Phy; diff --git a/common/broxton/hw-gfx-gma-ddi_phy.ads b/common/broxton/hw-gfx-gma-ddi_phy.ads index 89f19f0c4a..51221b01c6 100644 --- a/common/broxton/hw-gfx-gma-ddi_phy.ads +++ b/common/broxton/hw-gfx-gma-ddi_phy.ads @@ -16,7 +16,9 @@ private package HW.GFX.GMA.DDI_Phy is type T is (BC, A); - procedure Power_On (Phy : T) is null; - procedure Power_Off (Phy : T) is null; + procedure Power_On (Phy : T); + procedure Power_Off (Phy : T); + + subtype DDI_Phy_Port is GPU_Port range DIGI_A .. DIGI_C; end HW.GFX.GMA.DDI_Phy; diff --git a/common/hw-gfx-gma-registers.ads b/common/hw-gfx-gma-registers.ads index 814dd11a2b..cb558d72a2 100644 --- a/common/hw-gfx-gma-registers.ads +++ b/common/hw-gfx-gma-registers.ads @@ -212,6 +212,11 @@ is DP_TP_STATUS_E, SRD_CTL, SRD_STATUS, + BXT_PHY_CTL_A, + BXT_PHY_CTL_B, + BXT_PHY_CTL_C, + BXT_PHY_CTL_FAM_EDP, + BXT_PHY_CTL_FAM_DDI, AUD_VID_DID, PFA_WIN_POS, PFA_WIN_SZ, @@ -237,6 +242,9 @@ is PS_WIN_POS_1_C, PS_WIN_SZ_1_C, PS_CTRL_1_C, + BXT_PORT_CL1CM_DW0_BC, + BXT_PORT_CL1CM_DW9_BC, + BXT_PORT_CL1CM_DW10_BC, DPLL1_CFGR1, DPLL1_CFGR2, DPLL2_CFGR1, @@ -246,6 +254,12 @@ is DPLL_CTRL1, DPLL_CTRL2, DPLL_STATUS, + BXT_PORT_CL1CM_DW28_BC, + BXT_PORT_CL1CM_DW30_BC, + BXT_PORT_REF_DW3_BC, + BXT_PORT_REF_DW6_BC, + BXT_PORT_REF_DW8_BC, + BXT_PORT_CL2CM_DW6_BC, BXT_DE_PLL_CTL, HTOTAL_EDP, HBLANK_EDP, @@ -457,9 +471,18 @@ is FDI_RXC_TUSIZE1, QUIRK_F2060, TRANSC_CHICKEN2, + BXT_P_CR_GT_DISP_PWRON, GT_MAILBOX, GT_MAILBOX_DATA, - GT_MAILBOX_DATA_1); + GT_MAILBOX_DATA_1, + BXT_PORT_CL1CM_DW0_A, + BXT_PORT_CL1CM_DW9_A, + BXT_PORT_CL1CM_DW10_A, + BXT_PORT_CL1CM_DW28_A, + BXT_PORT_CL1CM_DW30_A, + BXT_PORT_REF_DW3_A, + BXT_PORT_REF_DW6_A, + BXT_PORT_REF_DW8_A); pragma Warnings (GNATprove, Off, "pragma ""KEEP_NAMES"" ignored *(not yet supported)", @@ -836,6 +859,35 @@ is BXT_DE_PLL_CTL => 16#06_d000# / Register_Width, BXT_DE_PLL_ENABLE => 16#04_6070# / Register_Width, + -- Broxton DDI PHY registers + BXT_P_CR_GT_DISP_PWRON => 16#13_8090# / Register_Width, + BXT_PHY_CTL_A => 16#06_4c00# / Register_Width, + BXT_PHY_CTL_B => 16#06_4c10# / Register_Width, + BXT_PHY_CTL_C => 16#06_4c20# / Register_Width, + BXT_PHY_CTL_FAM_EDP => 16#06_4c80# / Register_Width, + BXT_PHY_CTL_FAM_DDI => 16#06_4c90# / Register_Width, + + -- Broxton DDI PHY common lane registers + BXT_PORT_CL1CM_DW0_A => 16#16_2000# / Register_Width, + BXT_PORT_CL1CM_DW0_BC => 16#06_c000# / Register_Width, + BXT_PORT_CL1CM_DW9_A => 16#16_2024# / Register_Width, + BXT_PORT_CL1CM_DW9_BC => 16#06_c024# / Register_Width, + BXT_PORT_CL1CM_DW10_A => 16#16_2028# / Register_Width, + BXT_PORT_CL1CM_DW10_BC => 16#06_c028# / Register_Width, + BXT_PORT_CL1CM_DW28_A => 16#16_2070# / Register_Width, + BXT_PORT_CL1CM_DW28_BC => 16#06_c070# / Register_Width, + BXT_PORT_CL1CM_DW30_A => 16#16_2078# / Register_Width, + BXT_PORT_CL1CM_DW30_BC => 16#06_c078# / Register_Width, + BXT_PORT_CL2CM_DW6_BC => 16#06_c358# / Register_Width, + + -- Broxton DDI PHY ref registers + BXT_PORT_REF_DW3_A => 16#16_218c# / Register_Width, + BXT_PORT_REF_DW3_BC => 16#06_c18c# / Register_Width, + BXT_PORT_REF_DW6_A => 16#16_2198# / Register_Width, + BXT_PORT_REF_DW6_BC => 16#06_c198# / Register_Width, + BXT_PORT_REF_DW8_A => 16#16_21a0# / Register_Width, + BXT_PORT_REF_DW8_BC => 16#06_c1a0# / Register_Width, + -- Power Down Well registers PWR_WELL_CTL_BIOS => 16#04_5400# / Register_Width, PWR_WELL_CTL_DRIVER => 16#04_5404# / Register_Width,