Angel Pons has uploaded this change for review. ( https://review.coreboot.org/c/libgfxinit/+/44795 )
Change subject: baytrail: Add PLL initialisation code ......................................................................
baytrail: Add PLL initialisation code
Change-Id: I3f59e1cd6623f6c65cd1f8e231ea1aa1ec41bd16 Signed-off-by: Angel Pons th3fanbus@gmail.com --- M common/valleyview/Makefile.inc A common/valleyview/hw-gfx-gma-plls.adb A common/valleyview/hw-gfx-gma-plls.ads 3 files changed, 648 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/libgfxinit refs/changes/95/44795/1
diff --git a/common/valleyview/Makefile.inc b/common/valleyview/Makefile.inc index c587a3e..39241c2 100644 --- a/common/valleyview/Makefile.inc +++ b/common/valleyview/Makefile.inc @@ -7,8 +7,6 @@ gfxinit-y += ../g45/hw-gfx-gma-gmch-lvds.ads gfxinit-y += ../g45/hw-gfx-gma-gmch-vga.adb gfxinit-y += ../g45/hw-gfx-gma-gmch-vga.ads -gfxinit-y += ../g45/hw-gfx-gma-plls.adb -gfxinit-y += ../g45/hw-gfx-gma-plls.ads gfxinit-y += ../g45/hw-gfx-gma-port_detect.adb gfxinit-y += ../g45/hw-gfx-gma-gmch.ads gfxinit-y += ../g45/hw-gfx-gma-power_and_clocks.ads @@ -18,3 +16,5 @@ gfxinit-y += hw-gfx-gma-dpio.ads gfxinit-y += hw-gfx-gma-iosf.adb gfxinit-y += hw-gfx-gma-iosf.ads +gfxinit-y += hw-gfx-gma-plls.adb +gfxinit-y += hw-gfx-gma-plls.ads diff --git a/common/valleyview/hw-gfx-gma-plls.adb b/common/valleyview/hw-gfx-gma-plls.adb new file mode 100644 index 0000000..dd3fe41 --- /dev/null +++ b/common/valleyview/hw-gfx-gma-plls.adb @@ -0,0 +1,603 @@ +-- +-- Copyright (C) 2020 Angel Pons th3fanbus@gmail.com +-- +-- 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 HW.Time; +with HW.GFX.GMA.Config; +with HW.GFX.GMA.DPIO; +with HW.GFX.GMA.IOSF; +with HW.GFX.GMA.Registers; + +with HW.Debug; +with GNAT.Source_Info; + +package body HW.GFX.GMA.PLLs +with + Refined_State => (State => PLLs) +is + + Debug_Clocks : constant Boolean := False; + + type Count_Range is new Natural range 0 .. 2; + + type PLL_State is record + Use_Count : Count_Range; + Used_For_DP : Boolean; + Link_Rate : DP_Bandwidth; + Mode : Mode_Type; + end record; + + type PLL_State_Array is array (DPLLs) of PLL_State; + + PLLs : PLL_State_Array; + + ---------------------------------------------------------------------------- + + subtype N_Range is Int64 range 1 .. 8; + subtype M1_Range is Int64 range 2 .. 4; + subtype M2_Range is Int64 range 11 .. 157; + subtype P1_Range is Int64 range 2 .. 4; + subtype P2_Range is Int64 range 2 .. 21; + subtype VCO_Range is Int64 range 4_000_000_000 .. 6_000_000_001; + subtype Clock_Range is HW.GFX.Frequency_Type; + + type Clock_Type is + record + N : N_Range; + M1 : M1_Range; + M2 : M2_Range; + P1 : P1_Range; + P2 : P2_Range; + VCO : VCO_Range; + Reference_Clock : Clock_Range; + Dotclock : Clock_Range; + end record; + + Invalid_Clock : constant Clock_Type := Clock_Type' + (N => N_Range'Last, + M1 => M1_Range'Last, + M2 => M2_Range'Last, + P1 => P1_Range'Last, + P2 => P2_Range'Last, + Reference_Clock => Clock_Range'Last, + VCO => VCO_Range'Last, + Dotclock => Clock_Range'Last); + + type Limits_Type is + record + N_Lower : N_Range; + N_Upper : N_Range; + M1_Lower : M1_Range; + M1_Upper : M1_Range; + M2_Lower : M2_Range; + M2_Upper : M2_Range; + P1_Lower : P1_Range; + P1_Upper : P1_Range; + P2_Lower : P2_Range; + P2_Upper : P2_Range; + VCO_Lower : VCO_Range; + VCO_Upper : VCO_Range; + end record; + + Baytrail_Limits : constant Limits_Type := Limits_Type' + (N_Lower => 1, N_Upper => 7, + M1_Lower => 2, M1_Upper => 3, + M2_Lower => 11, M2_Upper => 156, + P1_Lower => 2, P1_Upper => 3, + P2_Lower => 2, P2_Upper => 20, + VCO_Lower => 4_000_000_000, VCO_Upper => 6_000_000_000); + + ---------------------------------------------------------------------------- + + -- intel_display.c: vlv_wait_port_ready() + procedure Wait_Port_Ready (Pipe : Pipe_Index) + is + Port_Mask : constant Word32 := + (case Pipe is + when Primary => 16#0f#, + when Secondary => 16#0f# * 2 ** 4, + when others => 16#0f#); -- FIXME + begin + Registers.Wait_Unset_Mask + (Register => Registers.GMCH_DPLL_A, + Mask => Port_Mask, + TOut_MS => 1000, + Verbose => True); + + end Wait_Port_Ready; + + ---------------------------------------------------------------------------- + + procedure Verify_Parameters + (N : in N_Range; + M1 : in M1_Range; + P1 : in P1_Range; + P2 : in P2_Range; + Target_Dotclock : in Clock_Range; + Reference_Clock : in Clock_Range; + Current_Limits : in Limits_Type; + Result : out Clock_Type; + Valid : out Boolean) + with + Global => null, + Pre => True, + Post => True + is + M2 : Int64; + M : Int64; + P : Int64; + VCO : Int64; + Dotclock : Int64; + begin + pragma Debug (Debug_Clocks, Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + P := P1 * P2; + M2 := (Target_Dotclock * P * N) / (Reference_Clock * M1); + M := M1 * M2; + + if P = 0 then + pragma Debug (Debug_Clocks, Debug.Put_Line ("P value is zero!")); + Result := Invalid_Clock; + Valid := False; + return; + end if; + + VCO := (Reference_Clock * M) / N; + Dotclock := VCO / P; + + pragma Debug (Debug_Clocks and not (Current_Limits.P1_Lower <= P1 and P1 <= Current_Limits.P1_Upper ), Debug.Put_Line ("P1 out of range.")); + pragma Debug (Debug_Clocks and not (Current_Limits.P2_Lower <= P2 and P2 <= Current_Limits.P2_Upper ), Debug.Put_Line ("P2 out of range.")); + pragma Debug (Debug_Clocks and not (Current_Limits.M1_Lower <= M1 and M1 <= Current_Limits.M1_Upper ), Debug.Put_Line ("M1 out of range.")); + pragma Debug (Debug_Clocks and not (Current_Limits.M2_Lower <= M2 and M2 <= Current_Limits.M2_Upper ), Debug.Put_Line ("M2 out of range.")); + pragma Debug (Debug_Clocks and not (Current_Limits.N_Lower <= N and N <= Current_Limits.N_Upper ), Debug.Put_Line ("N out of range.")); + pragma Debug (Debug_Clocks and not (Current_Limits.VCO_Lower <= VCO and VCO <= Current_Limits.VCO_Upper), Debug.Put_Line ("VCO out of range.")); + + pragma Debug (Debug_Clocks and not (Int64 (Clock_Range'First) <= Dotclock), Debug.Put_Line ("Dotclock too low.")); + pragma Debug (Debug_Clocks and not (Int64 (Clock_Range'First) <= Dotclock), Debug.Put_Int64 (Dotclock)); + pragma Debug (Debug_Clocks and not (Int64 (Clock_Range'First) <= Dotclock), Debug.New_Line); + + pragma Debug (Debug_Clocks and not (Dotclock <= Int64 (Clock_Range'Last)), Debug.Put_Line ("Dotclock too high.")); + pragma Debug (Debug_Clocks and not (Dotclock <= Int64 (Clock_Range'Last)), Debug.Put_Int64 (Dotclock)); + pragma Debug (Debug_Clocks and not (Dotclock <= Int64 (Clock_Range'Last)), Debug.New_Line); + + Valid := + Current_Limits.N_Lower <= N and N <= Current_Limits.N_Upper and + Current_Limits.P1_Lower <= P1 and P1 <= Current_Limits.P1_Upper and + -- Current_Limits.P2_Lower <= P2 and P2 <= Current_Limits.P2_Upper and + Current_Limits.M1_Lower <= M1 and M1 <= Current_Limits.M1_Upper and + Current_Limits.M2_Lower <= M2 and M2 <= Current_Limits.M2_Upper and + Current_Limits.VCO_Lower <= VCO and VCO <= Current_Limits.VCO_Upper and + Int64 (Clock_Range'First) <= Dotclock and + Dotclock <= Int64 (Clock_Range'Last); + + -- FIXME: intel_display.c: vlv_PLL_is_optimal() + + if Valid + then + Result := Clock_Type' + (N => N, + M1 => M1, + M2 => M2, + P1 => P1, + P2 => P2, + Reference_Clock => Reference_Clock, + VCO => VCO, + Dotclock => Clock_Range (Dotclock)); + else + Result := Invalid_Clock; + end if; + + end Verify_Parameters; + + procedure Calculate_Clock_Parameters + (Display : in Display_Type; + Target_Dotclock : in Clock_Range; + Reference_Clock : in Clock_Range; + Limits : in Limits_Type; + Best_Clock : out Clock_Type; + Valid : out Boolean) + with + Global => null, + Pre => True, + Post => True + is + Max_N : constant Int64 := Reference_Clock / 19200; + + P2_Flip_Flop : Boolean; + Best_Delta : Int64 := Int64'Last; + Current_Delta : Int64; + Current_Clock : Clock_Type; + Registers_Valid : Boolean; + begin + pragma Debug (Debug_Clocks, Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Valid := False; + Best_Clock := Invalid_Clock; + + -- Based on hardware requirement, prefer smaller n to precision + for N in N_Range range Limits.N_Lower .. Int64'Min (Limits.N_Upper, Max_N) + loop + -- Reverse loops as hardware prefers higher values + for P1 in reverse P1_Range range Limits.P1_Lower .. Limits.P1_Upper + loop + P2_Flip_Flop := False; + for P2 in reverse P2_Range range Limits.P2_Lower .. Limits.P2_Upper + loop + -- Skip reserved values + P2_Flip_Flop := not P2_Flip_Flop; + if P2_Flip_Flop or else P2 <= 10 then + -- FIXME: Check if hardware prefers big or small M1, M2 values + for M1 in M1_Range range Limits.M1_Lower .. Limits.M1_Upper + loop + Verify_Parameters + (N => N, + M1 => M1, + P1 => P1, + P2 => P2, + Target_Dotclock => Target_Dotclock, + Reference_Clock => Reference_Clock, + Current_Limits => Limits, + Result => Current_Clock, + Valid => Registers_Valid); + + if Registers_Valid + then + if Current_Clock.Dotclock > Target_Dotclock + then + Current_Delta := Current_Clock.Dotclock - Target_Dotclock; + else + Current_Delta := Target_Dotclock - Current_Clock.Dotclock; + end if; + + if Current_Delta < Best_Delta + then + Best_Delta := Current_Delta; + Best_Clock := Current_Clock; + Valid := True; + end if; + + pragma Debug (Debug_Clocks, Debug.Put ("Current/Target/Best_Delta: ")); + pragma Debug (Debug_Clocks, Debug.Put_Int64 (Current_Clock.Dotclock)); + pragma Debug (Debug_Clocks, Debug.Put ("/")); + pragma Debug (Debug_Clocks, Debug.Put_Int64 (Target_Dotclock)); + pragma Debug (Debug_Clocks, Debug.Put ("/")); + pragma Debug (Debug_Clocks, Debug.Put_Int64 (Best_Delta)); + pragma Debug (Debug_Clocks, Debug.Put_Line (".")); + + end if; + end loop; + end if; + end loop; + end loop; + end loop; + + pragma Debug (Valid, Debug.Put_Line ("Valid clock found.")); + pragma Debug (Valid, Debug.Put ("Best/Target/Delta: ")); + pragma Debug (Valid, Debug.Put_Int64 (Best_Clock.Dotclock)); + pragma Debug (Valid, Debug.Put ("/")); + pragma Debug (Valid, Debug.Put_Int64 (Target_Dotclock)); + pragma Debug (Valid, Debug.Put ("/")); + pragma Debug (Valid, Debug.Put_Int64 (Best_Delta)); + pragma Debug (Valid, Debug.Put_Line (".")); + pragma Debug (not Valid, Debug.Put_Line ("No valid clock found.")); + + end Calculate_Clock_Parameters; + + type Regs is array (DPLLs) of Registers.Registers_Index; + + DPLL_CTRL : constant Regs := (Registers.GMCH_DPLL_A, Registers.GMCH_DPLL_B); + PP_CONTROL : constant Regs := + (Registers.GMCH_PP_CONTROL, + Registers.VLV_PIPE_B_PP_CONTROL); + + -- On VLV the Panel Protection also locks DPLL registers, unlock them just in case. + procedure Unlock_DPLL_Regs (PLL : in DPLLs) + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Registers.Unset_And_Set_Mask + (Register => PP_CONTROL (PLL), + Mask_Unset => 16#ffff# * 2 ** 16, + Mask_Set => 16#abcd# * 2 ** 16); + end Unlock_DPLL_Regs; + + VLV_DPLL_VCO_ENABLE : constant := 1 * 2 ** 31; + VLV_DPLL_CLOCK_DRIVE_EN : constant := 1 * 2 ** 30; + VLV_DPLL_REF_CLOCK_EN : constant := 1 * 2 ** 29; + VLV_DPLL_VGA_MODE_DIS : constant := 1 * 2 ** 28; + VLV_DPLL_A_SINGLE_FREQ : constant := 1 * 2 ** 26; + VLV_DPLL_UNLOCK : constant := 0 * 2 ** 15; + VLV_DPLL_LOCK : constant := 1 * 2 ** 15; + VLV_DPLL_DISP_RATE_SW : constant := 1 * 2 ** 8; + + -- DPLL A only + VLV_DPLL_P2_10_OR_14 : constant := 0 * 2 ** 24; -- Dot clock <= 270 MHz + VLV_DPLL_P2_5_OR_7 : constant := 1 * 2 ** 24; -- Dot clock > 270 MHz + VLV_DPLL_VCC_LDO : constant := 1 * 2 ** 14; -- Note: For TNG use + VLV_REFCLK_EXT_PAD : constant := 0 * 2 ** 13; -- External refclk pad, 27 MHz + VLV_REFCLK_INT_CORE : constant := 1 * 2 ** 13; -- Integrated core refclk, default 100 MHz + + -- DPLL B only + VLV_CRICLK_EXT_PAD : constant := 0 * 2 ** 14; -- External refclk pad + VLV_CRICLK_INT_CORE : constant := 1 * 2 ** 14; -- Integrated core refclk + + -- + -- Post divider depends on pixel clock rate, DAC vs digital + -- (and LVDS, but we don't support that). + -- + -- Note: don't use the DAC post divider as it seems unstable. + -- + function Make_Mdiv (N, M1, M2, P1, P2, K, PD : in Word32) return Word32 is + ((PD * 2 ** 28) or -- Post divider + (K * 2 ** 24) or + (P1 * 2 ** 21) or + (P2 * 2 ** 16) or + (N * 2 ** 12) or + (M1 * 2 ** 8) or + (M2 and 16#ff#)) with Inline; + + PLL_To_Channel : constant array (DPLLs) of DPIO.Channel := (DPIO.DPIO_CH0, DPIO.DPIO_CH1); + + PLL_Names : constant array (DPLLs) of String (1 .. 8) := + (DPLL_A => "DPLL A ", + DPLL_B => "DPLL B "); + + -- intel_display.c: vlv_prepare_pll() + procedure Program_DPLL + (PLL : DPLLs; + Display : Display_Type; + Clk : Clock_Type) + with + Global => (In_Out => Registers.Register_State), + Pre => True, + Post => True + is + Mdiv : Word32; + begin + pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity)); + pragma Debug (Debug.Put_Line (": " & PLL_Names (PLL))); + + Mdiv := Make_Mdiv + (N => Word32 (Clk.N), + M1 => Word32 (Clk.M1), + M2 => Word32 (Clk.M2), + P1 => Word32 (Clk.P1), + P2 => Word32 (Clk.P2), + K => 1, + PD => 1); + + DPIO.Vlv_Pll_Prepare (PLL_To_Channel (PLL), Mdiv, Display); + + end Program_DPLL; + + function Get_Max_Clock (Limits : in Limits_Type) return Int64 is + (Limits.VCO_Upper / Limits.P1_Lower / Limits.P2_Lower / 5); + + procedure On + (PLL : in T; + Port_Cfg : in Port_Config; + Success : out Boolean) + is + Limits : constant Limits_Type := Baytrail_Limits; + Max_Clock : constant Int64 := Get_Max_Clock (Limits); + Target_Clock : constant Frequency_Type := + (if Port_Cfg.Display = DP then + DP_Symbol_Rate (Port_Cfg.DP.Bandwidth) + else + Port_Cfg.Mode.Dotclock); + Clk : Clock_Type; + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Success := PLL in DPLLs; + Clk := Invalid_Clock; + + if Success then + -- Unlock DPLL regs + Unlock_DPLL_Regs (PLL); + + if Port_Cfg.Display = DP then + -- we use static values for DP + case Port_Cfg.DP.Bandwidth is + when DP_Bandwidth_1_62 => + Clk.N := 5; + Clk.M1 := 3; + Clk.M2 := 81; + Clk.P1 := 3; + Clk.P2 := 2; + when DP_Bandwidth_2_7 => + Clk.N := 1; + Clk.M1 := 2; + Clk.M2 := 27; + Clk.P1 := 2; + Clk.P2 := 2; + when others => + Success := False; + end case; + elsif Target_Clock <= Max_Clock then + Calculate_Clock_Parameters + (Display => Port_Cfg.Display, + Target_Dotclock => Target_Clock * 5, + Reference_Clock => 100_000_000, + Limits => Limits, + Best_Clock => Clk, + Valid => Success); + else + Success := False; + pragma Debug (Debug.Put ("WARNING: Targeted clock too high: ")); + pragma Debug (Debug.Put_Int64 (Target_Clock)); + pragma Debug (Debug.Put (" > ")); + pragma Debug (Debug.Put_Int64 (Max_Clock)); + pragma Debug (Debug.New_Line); + pragma Debug (Debug.New_Line); + end if; + end if; + + if Success then + Program_DPLL (PLL, Port_Cfg.Display, Clk); + + Registers.Set_Mask (DPLL_CTRL (PLL), VLV_DPLL_VCO_ENABLE or VLV_DPLL_CLOCK_DRIVE_EN); + Registers.Posting_Read (DPLL_CTRL (PLL)); + Time.U_Delay (150); + + DPIO.Vlv_Phy_Pre_Encoder_Enable (PLL_To_Channel (PLL)); + end if; + end On; + + -- intel_display.c: vlv_disable_pll() + procedure Off (PLL : T) + is + Value : Word32 := VLV_REFCLK_INT_CORE or + VLV_DPLL_REF_CLOCK_EN or + VLV_DPLL_VGA_MODE_DIS; + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + if PLL in DPLLs then + if PLL /= DPLL_A then + Value := Value or VLV_CRICLK_INT_CORE; + end if; + Registers.Write (DPLL_CTRL (PLL), Value); + Registers.Posting_Read (DPLL_CTRL (PLL)); + end if; + end Off; + + ---------------------------------------------------------------------------- + + procedure Initialize + is + begin + PLLs := + (DPLLs => + (Use_Count => 0, + Used_For_DP => False, + Link_Rate => DP_Bandwidth'First, + Mode => Invalid_Mode)); + + -- Enable Refclk, this needs to be done early + Registers.Write + (Register => Registers.GMCH_DPLL_A, + Value => VLV_DPLL_VGA_MODE_DIS or + VLV_DPLL_REF_CLOCK_EN or + VLV_REFCLK_INT_CORE); + Registers.Write + (Register => Registers.GMCH_DPLL_B, + Value => VLV_DPLL_VGA_MODE_DIS or + VLV_DPLL_REF_CLOCK_EN or + VLV_CRICLK_INT_CORE or + VLV_REFCLK_INT_CORE); + end Initialize; + + procedure Alloc_Configurable + (Port_Cfg : in Port_Config; + PLL : out T; + Success : out Boolean) + with + Pre => True + is + function Config_Matches (PE : PLL_State) return Boolean + is + begin + return + PE.Used_For_DP = (Port_Cfg.Display = DP) and + ((PE.Used_For_DP and PE.Link_Rate = Port_Cfg.DP.Bandwidth) or + (not PE.Used_For_DP and PE.Mode = Port_Cfg.Mode)); + end Config_Matches; + begin + -- try to find shareable PLL + -- FIXME: Sharing PLLs in VLV requires some special DPIO settings + for P in DPLLs loop + Success := PLLs (P).Use_Count /= 0 and + PLLs (P).Use_Count /= Count_Range'Last and + Config_Matches (PLLs (P)); + if Success then + PLL := P; + pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity)); + pragma Debug (Debug.Put_Line (": Will share " & PLL_Names (PLL))); + PLLs (PLL).Use_Count := PLLs (PLL).Use_Count + 1; + return; + end if; + end loop; + + -- try to find free PLL + for P in DPLLs loop + if PLLs (P).Use_Count = 0 then + PLL := P; + pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity)); + pragma Debug (Debug.Put_Line (": Will power on " & PLL_Names (PLL))); + On (PLL, Port_Cfg, Success); + if Success then + PLLs (PLL) := + (Use_Count => 1, + Used_For_DP => Port_Cfg.Display = DP, + Link_Rate => Port_Cfg.DP.Bandwidth, + Mode => Port_Cfg.Mode); + end if; + return; + end if; + end loop; + + pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity)); + pragma Debug (Debug.Put_Line (": Could not allocate PLL!")); + PLL := Invalid; + end Alloc_Configurable; + + procedure Alloc + (Port_Cfg : in Port_Config; + PLL : out T; + Success : out Boolean) + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + if Port_Cfg.Port in DIGI_B .. DIGI_D then + Alloc_Configurable (Port_Cfg, PLL, Success); + else + PLL := Invalid; + Success := False; + end if; + end Alloc; + + procedure Free (PLL : T) + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + if PLL in DPLLs then + if PLLs (PLL).Use_Count /= 0 then + PLLs (PLL).Use_Count := PLLs (PLL).Use_Count - 1; + if PLLs (PLL).Use_Count = 0 then + Off (PLL); + end if; + end if; + end if; + end Free; + + procedure All_Off + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + for PLL in DPLLs loop + Off (PLL); + end loop; + end All_Off; + + function Register_Value (PLL : T) return Word32 + is + begin + return (if PLL = DPLL_B then 1 else 0); + end Register_Value; + +end HW.GFX.GMA.PLLs; diff --git a/common/valleyview/hw-gfx-gma-plls.ads b/common/valleyview/hw-gfx-gma-plls.ads new file mode 100644 index 0000000..917fa39 --- /dev/null +++ b/common/valleyview/hw-gfx-gma-plls.ads @@ -0,0 +1,43 @@ +-- +-- Copyright (C) 2020 Angel Pons th3fanbus@gmail.com +-- +-- 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.PLLs +with + Abstract_State => (State with Part_Of => GMA.State) +is + + -- XXX: Types should be private (but that triggers a bug in SPARK GPL 2016) + type T is (Invalid_PLL, DPLL_A, DPLL_B); + subtype DPLLs is T range DPLL_A .. DPLL_B; + Invalid : constant T := Invalid_PLL; + + -- intel_display.c: vlv_wait_port_ready() + procedure Wait_Port_Ready (Pipe : Pipe_Index); + + procedure Initialize + with + Global => (Output => State); + + procedure Alloc + (Port_Cfg : in Port_Config; + PLL : out T; + Success : out Boolean); + + procedure Free (PLL : T); + + procedure All_Off; + + function Register_Value (PLL : T) return Word32; + +end HW.GFX.GMA.PLLs;
Hello Nico Huber, Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/libgfxinit/+/44795
to look at the new patch set (#2).
Change subject: baytrail: Add PLL initialisation code ......................................................................
baytrail: Add PLL initialisation code
Change-Id: I3f59e1cd6623f6c65cd1f8e231ea1aa1ec41bd16 Signed-off-by: Angel Pons th3fanbus@gmail.com --- M common/valleyview/Makefile.inc A common/valleyview/hw-gfx-gma-plls.adb A common/valleyview/hw-gfx-gma-plls.ads 3 files changed, 630 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/libgfxinit refs/changes/95/44795/2
Hello Nico Huber, Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/libgfxinit/+/44795
to look at the new patch set (#3).
Change subject: gma baytrail: Add PLL initialisation code ......................................................................
gma baytrail: Add PLL initialisation code
Change-Id: I3f59e1cd6623f6c65cd1f8e231ea1aa1ec41bd16 Signed-off-by: Angel Pons th3fanbus@gmail.com --- M common/valleyview/Makefile.inc A common/valleyview/hw-gfx-gma-plls.adb A common/valleyview/hw-gfx-gma-plls.ads 3 files changed, 631 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/libgfxinit refs/changes/95/44795/3
Hello Nico Huber, Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/libgfxinit/+/44795
to look at the new patch set (#5).
Change subject: gma baytrail: Add PLL initialisation code ......................................................................
gma baytrail: Add PLL initialisation code
Change-Id: I3f59e1cd6623f6c65cd1f8e231ea1aa1ec41bd16 Signed-off-by: Angel Pons th3fanbus@gmail.com --- M common/valleyview/Makefile.inc A common/valleyview/hw-gfx-gma-plls.adb A common/valleyview/hw-gfx-gma-plls.ads 3 files changed, 631 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/libgfxinit refs/changes/95/44795/5
Nico Huber has posted comments on this change. ( https://review.coreboot.org/c/libgfxinit/+/44795 )
Change subject: gma baytrail: Add PLL initialisation code ......................................................................
Patch Set 3:
(7 comments)
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... File common/valleyview/hw-gfx-gma-plls.adb:
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 31: type Count_Range is new Natural range 0 .. 2; : : type PLL_State is record : Use_Count : Count_Range; : Used_For_DP : Boolean; : Link_Rate : DP_Bandwidth; : Mode : Mode_Type; : end record; : : type PLL_State_Array is array (DPLLs) of PLL_State; : : PLLs : PLL_State_Array; This should only be necessary if we want to keep track of the current state for potential DPLL sharing. However, each pipe has its own PLL. So I guess we'll never need it?
The situation seems similar to BXT, only that there the PLLs are tied to the ports, not the pipe.
(I know there's a comment below that sharing is possible, but if it's never necessary, we can reduce complexity instead.)
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 129: if P = 0 then Doesn't GNATProve complain here? How can it be 0?
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 336: end Unlock_DPLL_Regs; IIRC, we always have all the registers unlocked (by HW.GFX.GMA.Panel). Please check.
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 363: Nit, drop empty line.
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 548: | Heh, didn't know this works :)
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 584: return (if PLL = DPLL_B then 1 else 0); Is this actually used? I couldn't find a register where it's written to...
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... File common/valleyview/hw-gfx-gma-plls.ads:
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 20: -- XXX: Types should be private (but that triggers a bug in SPARK GPL 2016) Could try if it works now with newer GNATProve.
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/libgfxinit/+/44795 )
Change subject: gma baytrail: Add PLL initialisation code ......................................................................
Patch Set 7:
(5 comments)
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... File common/valleyview/hw-gfx-gma-plls.adb:
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 31: type Count_Range is new Natural range 0 .. 2; : : type PLL_State is record : Use_Count : Count_Range; : Used_For_DP : Boolean; : Link_Rate : DP_Bandwidth; : Mode : Mode_Type; : end record; : : type PLL_State_Array is array (DPLLs) of PLL_State; : : PLLs : PLL_State_Array;
This should only be necessary if we want to keep track of the current […]
Sharing is possible, but tricky to do (IIRC there's special bits in the DPLL registers to do it). I'll drop this and check if the DPLLs are active or not instead.
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 129: if P = 0 then
Doesn't GNATProve complain here? How can it be 0?
It can never be zero given the ranges. I'll drop this.
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 336: end Unlock_DPLL_Regs;
IIRC, we always have all the registers unlocked (by HW.GFX.GMA.Panel). Please check.
I had this here because there are two sets of panel control registers (and a while ago only one panel was handled in HW.GFX.GMA.Panel).
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 548: |
Heh, didn't know this works :)
Once one gets used to writing things in Ada, everything comes out smoothly.
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 584: return (if PLL = DPLL_B then 1 else 0);
Is this actually used? I couldn't find a register where it's written to...
Probably not
Hello Nico Huber, Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/libgfxinit/+/44795
to look at the new patch set (#8).
Change subject: gma baytrail: Add PLL initialisation code ......................................................................
gma baytrail: Add PLL initialisation code
Change-Id: I3f59e1cd6623f6c65cd1f8e231ea1aa1ec41bd16 Signed-off-by: Angel Pons th3fanbus@gmail.com --- M common/valleyview/Makefile.inc A common/valleyview/hw-gfx-gma-plls.adb A common/valleyview/hw-gfx-gma-plls.ads 3 files changed, 555 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/libgfxinit refs/changes/95/44795/8
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/libgfxinit/+/44795 )
Change subject: gma baytrail: Add PLL initialisation code ......................................................................
Patch Set 8:
(4 comments)
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... File common/valleyview/hw-gfx-gma-plls.adb:
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 31: type Count_Range is new Natural range 0 .. 2; : : type PLL_State is record : Use_Count : Count_Range; : Used_For_DP : Boolean; : Link_Rate : DP_Bandwidth; : Mode : Mode_Type; : end record; : : type PLL_State_Array is array (DPLLs) of PLL_State; : : PLLs : PLL_State_Array;
Sharing is possible, but tricky to do (IIRC there's special bits in the DPLL registers to do it). […]
Actually, I need to have some sort of refined state because of contracts, so I had to keep a boolean array.
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 129: if P = 0 then
It can never be zero given the ranges. I'll drop this.
Done
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 336: end Unlock_DPLL_Regs;
I had this here because there are two sets of panel control registers (and a while ago only one pane […]
Done
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 584: return (if PLL = DPLL_B then 1 else 0);
Probably not
It's used by hw-gfx-gma.adb for PLL_Hint. I've replaced it with a function expression instead, for the sake of brevity.
Hello Nico Huber, Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/libgfxinit/+/44795
to look at the new patch set (#9).
Change subject: gma baytrail: Add PLL initialisation code ......................................................................
gma baytrail: Add PLL initialisation code
Change-Id: I3f59e1cd6623f6c65cd1f8e231ea1aa1ec41bd16 Signed-off-by: Angel Pons th3fanbus@gmail.com --- M common/valleyview/Makefile.inc A common/valleyview/hw-gfx-gma-plls.adb A common/valleyview/hw-gfx-gma-plls.ads 3 files changed, 556 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/libgfxinit refs/changes/95/44795/9
Nico Huber has posted comments on this change. ( https://review.coreboot.org/c/libgfxinit/+/44795 )
Change subject: gma baytrail: Add PLL initialisation code ......................................................................
Patch Set 9:
(4 comments)
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... File common/valleyview/hw-gfx-gma-plls.adb:
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 31: type Count_Range is new Natural range 0 .. 2; : : type PLL_State is record : Use_Count : Count_Range; : Used_For_DP : Boolean; : Link_Rate : DP_Bandwidth; : Mode : Mode_Type; : end record; : : type PLL_State_Array is array (DPLLs) of PLL_State; : : PLLs : PLL_State_Array;
Actually, I need to have some sort of refined state because of contracts, so I had to keep a boolean […]
Ah, that's tricky. I had to look at Broxton, how it's done :)
with Refined_State => (State => null)
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 584: return (if PLL = DPLL_B then 1 else 0);
It's used by hw-gfx-gma.adb for PLL_Hint. […]
Yes that's how it's passed around (through `GMA.Connectors`). But IIRC, it never hits any register in the VLV code?
https://review.coreboot.org/c/libgfxinit/+/44795/9/common/valleyview/hw-gfx-... File common/valleyview/hw-gfx-gma-plls.adb:
https://review.coreboot.org/c/libgfxinit/+/44795/9/common/valleyview/hw-gfx-... PS9, Line 452: for P in DPLLs loop AIUI, this is not going to work because you can't cross streams. Unless I missed something, we don't configure which PLL is used for which pipe, so Pipe A should always use PLL A etc. The big comment on the top of `intel_dpio_phy.c` also suggests so.
Tests might not cover this if Pipe A is always enabled first.
We might have to add a `Pipe` parameter to all `Alloc_Configurable` for this. Annoyingly will need lots of annotations for unused parameters too :-/
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... File common/valleyview/hw-gfx-gma-plls.ads:
https://review.coreboot.org/c/libgfxinit/+/44795/3/common/valleyview/hw-gfx-... PS3, Line 41: Actually, I keep it more airy at the package level.
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/libgfxinit/+/44795 )
Change subject: gma baytrail: Add PLL initialisation code ......................................................................
Patch Set 9:
(1 comment)
https://review.coreboot.org/c/libgfxinit/+/44795/9/common/valleyview/hw-gfx-... File common/valleyview/hw-gfx-gma-plls.adb:
https://review.coreboot.org/c/libgfxinit/+/44795/9/common/valleyview/hw-gfx-... PS9, Line 452: for P in DPLLs loop
AIUI, this is not going to work because you can't cross streams. Unless […]
I think there's something regarding which pipe goes to which port in one of the DPIO sequences (the only one that takes both a pipe and a port)
Nico Huber has posted comments on this change. ( https://review.coreboot.org/c/libgfxinit/+/44795 )
Change subject: gma baytrail: Add PLL initialisation code ......................................................................
Patch Set 9:
(1 comment)
https://review.coreboot.org/c/libgfxinit/+/44795/9/common/valleyview/hw-gfx-... File common/valleyview/hw-gfx-gma-plls.adb:
https://review.coreboot.org/c/libgfxinit/+/44795/9/common/valleyview/hw-gfx-... PS9, Line 452: for P in DPLLs loop
I think there's something regarding which pipe goes to which port in one of the DPIO sequences (the […]
There are three entities, PLL, Pipe, and Port. I was talking about the former two.
In the i915 comment it's described that for VLV, the channel stuff of the DPIO (including the PLL) is tied to the pipe and the "spline" stuff is tied to the port.