Nico Huber has submitted this change. ( https://review.coreboot.org/c/libgfxinit/+/35715 )
Change subject: gma g45: Read CDClk and calculate dot-clock limits ......................................................................
gma g45: Read CDClk and calculate dot-clock limits
Numbers are taken from `intel_cdclk.c` of Linux' i915 driver.
We introduce three new procedures to the `Power_And_Clocks` interface:
o Limit_Dotclocks() limits the dot clocks of all pipe configs according to the maximum supported CDClk. It also reports if CDClk has to be switched for these configs.
o Update_CDClk() performs the CDClk switch if necessary. It may further limit the dot clocks if the switch didn't succeed.
o Enable_CDClk() ensures that the CDClk is running. This may be necessary to probe for DP displays when no pipes are active.
The latter two are no-ops for G45, as the CDClk runs at a fixed rate. Dot clocks are limited to 90% of CDClk.
Change-Id: Ie50c0f8f51b3a0a6ed58c6461069c556cc92f51e Signed-off-by: Nico Huber nico.h@gmx.de Reviewed-on: https://review.coreboot.org/c/libgfxinit/+/35715 Reviewed-by: Matt DeVillier matt.devillier@gmail.com Reviewed-by: Angel Pons th3fanbus@gmail.com Reviewed-by: Arthur Heymans arthur@aheymans.xyz --- M common/g45/hw-gfx-gma-power_and_clocks.adb M common/g45/hw-gfx-gma-power_and_clocks.ads M common/hw-gfx-gma-config.ads.template M common/hw-gfx-gma-registers.ads 4 files changed, 132 insertions(+), 10 deletions(-)
Approvals: Nico Huber: Verified Matt DeVillier: Looks good to me, but someone else must approve Arthur Heymans: Looks good to me, approved Angel Pons: Looks good to me, approved
diff --git a/common/g45/hw-gfx-gma-power_and_clocks.adb b/common/g45/hw-gfx-gma-power_and_clocks.adb index d6ee9f9..0ecf09b 100644 --- a/common/g45/hw-gfx-gma-power_and_clocks.adb +++ b/common/g45/hw-gfx-gma-power_and_clocks.adb @@ -1,5 +1,6 @@ -- -- Copyright (C) 2016 secunet Security Networks AG +-- Copyright (C) 2019 Nico Huber nico.h@gmx.de -- -- 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 @@ -26,8 +27,91 @@ CLKCFG_FSB_1067 : constant Frequency_Type := 266_666_666; CLKCFG_FSB_1333 : constant Frequency_Type := 333_333_333;
+ type Div_Array is array (0 .. 7) of Pos64; + + procedure Get_VCO (VCO : out Int64; Divisors : out Div_Array) + is + G45_3200 : constant Div_Array := (12, 10, 8, 7, 5, 16, others => 1); + G45_4000 : constant Div_Array := (14, 12, 10, 8, 6, 20, others => 1); + G45_4800 : constant Div_Array := (20, 14, 12, 10, 8, 24, others => 1); + G45_5333 : constant Div_Array := (20, 16, 12, 12, 8, 28, others => 1); + G45_Divs : constant array (Natural range 0 .. 7) of Div_Array := + (G45_3200, G45_4000, G45_5333, G45_4800, others => (others => 1)); + + GM45_2667 : constant Div_Array := (12, 8, others => 1); + GM45_3200 : constant Div_Array := (14, 10, others => 1); + GM45_4000 : constant Div_Array := (18, 12, others => 1); + GM45_5333 : constant Div_Array := (24, 16, others => 1); + GM45_Divs : constant array (Natural range 0 .. 7) of Div_Array := + (0 => GM45_3200, 1 => GM45_4000, 2 => GM45_5333, 4 => GM45_2667, + others => (others => 1)); + + HPLLVCO : Word32; + VCO_Sel : Natural range 0 .. 7; + begin + if Config.Has_GMCH_Mobile_VCO then + Registers.Read (Registers.GMCH_HPLLVCO_MOBILE, HPLLVCO); + VCO_Sel := Natural (HPLLVCO and 7); + VCO := + (case VCO_Sel is + when 0 => 3_200_000_000, + when 1 => 4_000_000_000, + when 2 => 5_333_333_333, + --when 3 => 6_400_000_000, + when 4 => 2_666_666_667, + --when 5 => 4_266_666_667, + when others => 0); + Divisors := GM45_Divs (VCO_Sel); + else + Registers.Read (Registers.GMCH_HPLLVCO, HPLLVCO); + VCO_Sel := Natural (HPLLVCO and 7); + VCO := + (case VCO_Sel is + when 0 => 3_200_000_000, + when 1 => 4_000_000_000, + when 2 => 5_333_333_333, + when 3 => 4_800_000_000, + when others => 0); + Divisors := G45_Divs (VCO_Sel); + end if; + end Get_VCO; + + procedure Get_CDClk (CDClk : out Config.CDClk_Range) + is + use type HW.Word16; + + Tmp_Clk : Int64 := 0; + + VCO : Int64; + Divisors : Div_Array; + + GCFGC : Word16; + CDClk_Sel : Natural range 0 .. 7; + begin + if PCI_Usable then + Get_VCO (VCO, Divisors); + PCI_Read16 (GCFGC, 16#f0#); + if Config.Has_GMCH_Mobile_VCO then + CDClk_Sel := Natural (Shift_Right (GCFGC, 12) and 1); + else + CDClk_Sel := Natural (Shift_Right (GCFGC, 4) and 7); + end if; + Tmp_Clk := VCO / Divisors (CDClk_Sel); + end if; + + if Tmp_Clk in Config.CDClk_Range then + CDClk := Tmp_Clk; + else + if Config.Has_GMCH_Mobile_VCO then + CDClk := 5_333_333_333 / 24; + else + CDClk := 5_333_333_333 / 28; + end if; + end if; + end Get_CDClk; + -- The Raw Freq is 1/4 of the FSB freq - procedure Initialize + procedure Get_Raw_Clock (Raw_Clock : out Frequency_Type) is CLK_CFG : Word32; type Freq_Sel is new Natural range 0 .. 7; @@ -36,15 +120,35 @@ (Register => Registers.GMCH_CLKCFG, Value => CLK_CFG); case Freq_Sel (CLK_CFG and FSB_FREQ_SEL_MASK) is - when 0 => Config.Raw_Clock := CLKCFG_FSB_1067; - when 1 => Config.Raw_Clock := CLKCFG_FSB_533; - when 2 => Config.Raw_Clock := CLKCFG_FSB_800; - when 3 => Config.Raw_Clock := CLKCFG_FSB_667; - when 4 => Config.Raw_Clock := CLKCFG_FSB_1333; - when 5 => Config.Raw_Clock := CLKCFG_FSB_400; - when 6 => Config.Raw_Clock := CLKCFG_FSB_1067; - when 7 => Config.Raw_Clock := CLKCFG_FSB_1333; + when 0 => Raw_Clock := CLKCFG_FSB_1067; + when 1 => Raw_Clock := CLKCFG_FSB_533; + when 2 => Raw_Clock := CLKCFG_FSB_800; + when 3 => Raw_Clock := CLKCFG_FSB_667; + when 4 => Raw_Clock := CLKCFG_FSB_1333; + when 5 => Raw_Clock := CLKCFG_FSB_400; + when 6 => Raw_Clock := CLKCFG_FSB_1067; + when 7 => Raw_Clock := CLKCFG_FSB_1333; end case; + end Get_Raw_Clock; + + procedure Initialize + is + CDClk : Config.CDClk_Range; + begin + Get_CDClk (CDClk); + Config.CDClk := CDClk; + Config.Max_CDClk := CDClk; + + Get_Raw_Clock (Config.Raw_Clock); end Initialize;
+ procedure Limit_Dotclocks + (Configs : in out Pipe_Configs; + CDClk_Switch : out Boolean) + is + begin + Config_Helpers.Limit_Dotclocks (Configs, Config.CDClk * 90 / 100); + CDClk_Switch := False; + end Limit_Dotclocks; + end HW.GFX.GMA.Power_And_Clocks; diff --git a/common/g45/hw-gfx-gma-power_and_clocks.ads b/common/g45/hw-gfx-gma-power_and_clocks.ads index 8f6c13c..313239b 100644 --- a/common/g45/hw-gfx-gma-power_and_clocks.ads +++ b/common/g45/hw-gfx-gma-power_and_clocks.ads @@ -12,10 +12,22 @@ -- GNU General Public License for more details. --
+with HW.GFX.GMA.Config_Helpers; + private package HW.GFX.GMA.Power_And_Clocks is
procedure Initialize;
+ procedure Limit_Dotclocks + (Configs : in out Pipe_Configs; + CDClk_Switch : out Boolean) + with + Post => + not CDClk_Switch and + Config_Helpers.Stable_FB (Configs'Old, Configs); + procedure Update_CDClk (Configs : in out Pipe_Configs) is null; + procedure Enable_CDClk is null; + procedure Pre_All_Off is null;
procedure Post_All_Off is null; diff --git a/common/hw-gfx-gma-config.ads.template b/common/hw-gfx-gma-config.ads.template index f7312fe..481897c 100644 --- a/common/hw-gfx-gma-config.ads.template +++ b/common/hw-gfx-gma-config.ads.template @@ -125,6 +125,7 @@ Broxton_On : <genbool> := Gen >= Broxton; Skylake_On : <genbool> := Gen >= Skylake;
+ GMCH_GM45 : <g45bool> := Gen_G45 and then CPU = GM45; CPU_Ironlake : <ilkbool> := Gen_Ironlake and then CPU = Ironlake; CPU_Sandybridge : <ilkbool> := Gen_Ironlake and then CPU = Sandybridge; CPU_Ivybridge : <ilkbool> := Gen_Ironlake and then CPU = Ivybridge; @@ -205,6 +206,7 @@ Has_FDI_RX_Power_Down : <genbool> := Gen_Haswell;
Has_GMCH_RawClk : <genbool> := Gen_G45; + Has_GMCH_Mobile_VCO : <g45bool> := GMCH_GM45;
----------- DDI: ------------- End_EDP_Training_Late : <genbool> := Gen_Haswell; diff --git a/common/hw-gfx-gma-registers.ads b/common/hw-gfx-gma-registers.ads index 81fb219..1d38ffd 100644 --- a/common/hw-gfx-gma-registers.ads +++ b/common/hw-gfx-gma-registers.ads @@ -70,6 +70,8 @@ UCGCTL1, UCGCTL2, GMCH_CLKCFG, + GMCH_HPLLVCO_MOBILE, + GMCH_HPLLVCO, VCS_RING_BUFFER_TAIL, VCS_RING_BUFFER_HEAD, VCS_RING_BUFFER_STRT, @@ -1617,7 +1619,9 @@
-- MCHBAR Mirror
- GMCH_CLKCFG => 16#01_0c00# / Register_Width); + GMCH_CLKCFG => 16#01_0c00# / Register_Width, + GMCH_HPLLVCO_MOBILE => 16#01_0c0f# / Register_Width, + GMCH_HPLLVCO => 16#01_0c38# / Register_Width);
subtype Registers_Index is Registers_Invalid_Index range Registers_Invalid_Index'Succ (Invalid_Register) ..