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;