Initial upstream commit
The history contained unlicensed code so everything got squashed, sorry.
Change-Id: I9f5775208f9df6fb29074bf3bc498f68cb17b3a0
Signed-off-by: Nico Huber <nico.huber@secunet.com>
diff --git a/common/haswell/Makefile.inc b/common/haswell/Makefile.inc
new file mode 100644
index 0000000..682af33
--- /dev/null
+++ b/common/haswell/Makefile.inc
@@ -0,0 +1,8 @@
+gfxinit-y += hw-gfx-gma-plls-lcpll.ads
+gfxinit-y += hw-gfx-gma-plls-wrpll.adb
+gfxinit-y += hw-gfx-gma-plls-wrpll.ads
+gfxinit-y += hw-gfx-gma-plls.adb
+gfxinit-y += hw-gfx-gma-plls.ads
+gfxinit-y += hw-gfx-gma-power_and_clocks.ads
+gfxinit-y += hw-gfx-gma-spll.adb
+gfxinit-y += hw-gfx-gma-spll.ads
diff --git a/common/haswell/hw-gfx-gma-plls-lcpll.ads b/common/haswell/hw-gfx-gma-plls-lcpll.ads
new file mode 100644
index 0000000..7fa45ba
--- /dev/null
+++ b/common/haswell/hw-gfx-gma-plls-lcpll.ads
@@ -0,0 +1,28 @@
+--
+-- Copyright (C) 2015-2016 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; version 2 of the License.
+--
+-- 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.LCPLL
+is
+
+ type Fixed_LCPLLs_Array is array (HW.GFX.DP_Bandwidth) of LCPLLs;
+
+ Fixed_LCPLLs : constant Fixed_LCPLLs_Array := Fixed_LCPLLs_Array'
+ (DP_Bandwidth_5_4 => LCPLL0,
+ DP_Bandwidth_2_7 => LCPLL1,
+ DP_Bandwidth_1_62 => LCPLL2);
+
+ type Value_Array is array (LCPLLs) of Word32;
+ Register_Value : constant Value_Array := Value_Array'
+ (LCPLL0 => 0 * 2 ** 29, LCPLL1 => 1 * 2 ** 29, LCPLL2 => 2 * 2 ** 29);
+
+end HW.GFX.GMA.PLLs.LCPLL;
diff --git a/common/haswell/hw-gfx-gma-plls-wrpll.adb b/common/haswell/hw-gfx-gma-plls-wrpll.adb
new file mode 100644
index 0000000..c9ab532
--- /dev/null
+++ b/common/haswell/hw-gfx-gma-plls-wrpll.adb
@@ -0,0 +1,351 @@
+--
+-- Copyright (C) 2015 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; version 2 of the License.
+--
+-- 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.Registers;
+
+package body HW.GFX.GMA.PLLs.WRPLL is
+
+ ----------------------------------------------------------------------------
+ --
+ -- Divider calculation as found in Linux' i915 driver
+ --
+ -- Copyright (C) 2012 Intel Corporation
+ --
+ -- Permission is hereby granted, free of charge, to any person obtaining a
+ -- copy of this software and associated documentation files (the "Software"),
+ -- to deal in the Software without restriction, including without limitation
+ -- the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ -- and/or sell copies of the Software, and to permit persons to whom the
+ -- Software is furnished to do so, subject to the following conditions:
+ --
+ -- The above copyright notice and this permission notice (including the next
+ -- paragraph) shall be included in all copies or substantial portions of the
+ -- Software.
+ --
+ -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ -- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ -- IN THE SOFTWARE.
+ --
+ -- Authors:
+ -- Eugeni Dodonov <eugeni.dodonov@intel.com>
+ --
+
+ LC_FREQ : constant := 2700; -- in MHz
+ LC_FREQ_2K : constant := LC_FREQ * 2000; -- in 500Hz
+
+ P_MIN : constant := 2;
+ P_MAX : constant := 62; -- i915 says 64, but this would overflow 6-bit
+ P_INC : constant := 2;
+
+ -- Constraints for PLL good behavior
+ REF_MIN : constant := 48;
+ REF_MAX : constant := 400;
+ VCO_MIN : constant := 2400;
+ VCO_MAX : constant := 4800;
+
+ type R2_Range is new Natural range 0 .. LC_FREQ * 2 / REF_MIN;
+ type N2_Range is new Natural range 0 .. VCO_MAX * Natural (R2_Range'Last) / LC_FREQ;
+ type P_Range is new Natural range 0 .. P_MAX;
+
+ type RNP is record
+ P : P_Range;
+ N2 : N2_Range;
+ R2 : R2_Range;
+ end record;
+ Invalid_RNP : constant RNP := RNP'(0, 0, 0);
+
+ function Get_Budget_For_Freq
+ (Clock : HW.GFX.Frequency_Type)
+ return Word64
+ is
+ Result : Word64;
+ begin
+ case Clock is
+ when 25175000 |
+ 25200000 |
+ 27000000 |
+ 27027000 |
+ 37762500 |
+ 37800000 |
+ 40500000 |
+ 40541000 |
+ 54000000 |
+ 54054000 |
+ 59341000 |
+ 59400000 |
+ 72000000 |
+ 74176000 |
+ 74250000 |
+ 81000000 |
+ 81081000 |
+ 89012000 |
+ 89100000 |
+ 108000000 |
+ 108108000 |
+ 111264000 |
+ 111375000 |
+ 148352000 |
+ 148500000 |
+ 162000000 |
+ 162162000 |
+ 222525000 |
+ 222750000 |
+ 296703000 |
+ 297000000 =>
+ Result := 0;
+ when 233500000 |
+ 245250000 |
+ 247750000 |
+ 253250000 |
+ 298000000 =>
+ Result := 1500;
+ when 169128000 |
+ 169500000 |
+ 179500000 |
+ 202000000 =>
+ Result := 2000;
+ when 256250000 |
+ 262500000 |
+ 270000000 |
+ 272500000 |
+ 273750000 |
+ 280750000 |
+ 281250000 |
+ 286000000 |
+ 291750000 =>
+ Result := 4000;
+ when 267250000 |
+ 268500000 =>
+ Result := 5000;
+ when others =>
+ Result := 1000;
+ end case;
+ return Result;
+ end Get_Budget_For_Freq;
+
+ procedure Update_RNP
+ (Freq_2K : in Word64;
+ Budget : in Word64;
+ R2 : in R2_Range;
+ N2 : in N2_Range;
+ P : in P_Range;
+ Best : in out RNP)
+ with
+ Depends => (Best =>+ (Freq_2K, Budget, R2, N2, P))
+ is
+ use type HW.Word64;
+
+ function Abs_Diff (A, B : Word64) return Word64
+ is
+ Result : Word64;
+ begin
+ if A > B then
+ Result := A - B;
+ else
+ Result := B - A;
+ end if;
+ return Result;
+ end Abs_Diff;
+
+ A, B, C, D, Diff, Diff_Best : Word64;
+ begin
+ -- No best (r,n,p) yet */
+ if Best.P = 0 then
+ Best.P := P;
+ Best.N2 := N2;
+ Best.R2 := R2;
+ else
+ -- Config clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to
+ -- freq2k.
+ --
+ -- delta = 1e6 *
+ -- abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) /
+ -- freq2k;
+ --
+ -- and we would like delta <= budget.
+ --
+ -- If the discrepancy is above the PPM-based budget, always prefer to
+ -- improve upon the previous solution. However, if you're within the
+ -- budget, try to maximize Ref * VCO, that is N / (P * R^2).
+ A := Freq_2K * Budget * Word64 (P) * Word64 (R2);
+ B := Freq_2K * Budget * Word64 (Best.P) * Word64 (Best.R2);
+ Diff := Abs_Diff
+ (Freq_2K * Word64 (P) * Word64 (R2),
+ LC_FREQ_2K * Word64 (N2));
+ Diff_Best := Abs_Diff
+ (Freq_2K * Word64 (Best.P) * Word64 (Best.R2),
+ LC_FREQ_2K * Word64 (Best.N2));
+ C := 1000000 * Diff;
+ D := 1000000 * Diff_Best;
+
+ if A < C and B < D then
+ -- If both are above the Budget, pick the closer
+ if Word64 (Best.P) * Word64 (Best.R2) * Diff
+ < Word64 (P) * Word64 (R2) * Diff_Best
+ then
+ Best.P := P;
+ Best.N2 := N2;
+ Best.R2 := R2;
+ end if;
+ elsif A >= C and B < D then
+ -- If A is below the threshold but B is above it? Update.
+ Best.P := P;
+ Best.N2 := N2;
+ Best.R2 := R2;
+ elsif A >= C and B >= D then
+ -- Both are below the limit, so pick the higher N2/(R2*R2)
+ if Word64 (N2) * Word64 (Best.R2) * Word64 (Best.R2)
+ > Word64 (Best.N2) * Word64 (R2) * Word64 (R2)
+ then
+ Best.P := P;
+ Best.N2 := N2;
+ Best.R2 := R2;
+ end if;
+ end if;
+ -- Otherwise A < C && B >= D, do nothing
+ end if;
+ end Update_RNP;
+
+ procedure Calculate_WRPLL
+ (Clock : in HW.GFX.Frequency_Type;
+ R2_Out : out R2_Range;
+ N2_Out : out N2_Range;
+ P_Out : out P_Range)
+ with
+ Global => null,
+ Pre => True,
+ Post => True
+ is
+ use type HW.Word64;
+
+ Freq_2K : Word64;
+ Budget : Word64;
+ Best : RNP := Invalid_RNP;
+ begin
+ Freq_2K := Word64 (Clock) / 100; -- PLL output should be 5x
+ -- the pixel clock
+ Budget := Get_Budget_For_Freq (Clock);
+
+ -- Special case handling for 540MHz pixel clock: bypass WR PLL entirely
+ -- and directly pass the LC PLL to it. */
+ if Freq_2K = 5400000 then
+ N2_Out := 2;
+ P_Out := 1;
+ R2_Out := 2;
+ else
+ -- Ref = LC_FREQ / R, where Ref is the actual reference input seen by
+ -- the WR PLL.
+ --
+ -- We want R so that REF_MIN <= Ref <= REF_MAX.
+ -- Injecting R2 = 2 * R gives:
+ -- REF_MAX * r2 > LC_FREQ * 2 and
+ -- REF_MIN * r2 < LC_FREQ * 2
+ --
+ -- Which means the desired boundaries for r2 are:
+ -- LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN
+ --
+ for R2 in R2_Range range
+ LC_FREQ * 2 / REF_MAX + 1 .. LC_FREQ * 2 / REF_MIN
+ loop
+ -- VCO = N * Ref, that is: VCO = N * LC_FREQ / R
+ --
+ -- Once again we want VCO_MIN <= VCO <= VCO_MAX.
+ -- Injecting R2 = 2 * R and N2 = 2 * N, we get:
+ -- VCO_MAX * r2 > n2 * LC_FREQ and
+ -- VCO_MIN * r2 < n2 * LC_FREQ)
+ --
+ -- Which means the desired boundaries for n2 are:
+ -- VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ
+ for N2 in N2_Range range
+ N2_Range (VCO_MIN * Natural (R2) / LC_FREQ + 1)
+ .. N2_Range (VCO_MAX * Natural (R2) / LC_FREQ)
+ loop
+ for P_Fract in Natural range P_MIN / P_INC .. P_MAX / P_INC
+ loop
+ Update_RNP
+ (Freq_2K, Budget, R2, N2, P_Range (P_Fract * P_INC), Best);
+ end loop;
+ end loop;
+ end loop;
+
+ N2_Out := Best.N2;
+ P_Out := Best.P;
+ R2_Out := Best.R2;
+ end if;
+
+ end Calculate_WRPLL;
+
+ --
+ ----------------------------------------------------------------------------
+
+ type Regs is array (WRPLLs) of Registers.Registers_Index;
+
+ WRPLL_CTL : constant Regs := Regs'(Registers.WRPLL_CTL_1, Registers.WRPLL_CTL_2);
+ WRPLL_CTL_PLL_ENABLE : constant := 1 * 2 ** 31;
+ WRPLL_CTL_SELECT_LCPLL : constant := 3 * 2 ** 28;
+
+ function WRPLL_CTL_DIVIDER_FEEDBACK (N2 : N2_Range) return Word32
+ is
+ begin
+ return Word32 (N2) * 2 ** 16;
+ end WRPLL_CTL_DIVIDER_FEEDBACK;
+
+ function WRPLL_CTL_DIVIDER_POST (P : P_Range) return Word32
+ is
+ begin
+ return Word32 (P) * 2 ** 8;
+ end WRPLL_CTL_DIVIDER_POST;
+
+ function WRPLL_CTL_DIVIDER_REFERENCE (R2 : R2_Range) return Word32
+ is
+ begin
+ return Word32 (R2) * 2 ** 0;
+ end WRPLL_CTL_DIVIDER_REFERENCE;
+
+ ----------------------------------------------------------------------------
+
+ procedure On
+ (PLL : in WRPLLs;
+ Target_Clock : in Frequency_Type;
+ Success : out Boolean)
+ is
+ R2 : R2_Range;
+ N2 : N2_Range;
+ P : P_Range;
+ begin
+ Calculate_WRPLL (Target_Clock, R2, N2, P);
+ Registers.Write
+ (Register => WRPLL_CTL (PLL),
+ Value => WRPLL_CTL_PLL_ENABLE or
+ WRPLL_CTL_SELECT_LCPLL or
+ WRPLL_CTL_DIVIDER_FEEDBACK (N2) or
+ WRPLL_CTL_DIVIDER_POST (P) or
+ WRPLL_CTL_DIVIDER_REFERENCE (R2));
+ Registers.Posting_Read (WRPLL_CTL (PLL));
+ Time.U_Delay (20);
+
+ Success := True;
+ end On;
+
+ procedure Off (PLL : WRPLLs)
+ is
+ begin
+ Registers.Unset_Mask (WRPLL_CTL (PLL), WRPLL_CTL_PLL_ENABLE);
+ end Off;
+
+end HW.GFX.GMA.PLLs.WRPLL;
diff --git a/common/haswell/hw-gfx-gma-plls-wrpll.ads b/common/haswell/hw-gfx-gma-plls-wrpll.ads
new file mode 100644
index 0000000..48f6850
--- /dev/null
+++ b/common/haswell/hw-gfx-gma-plls-wrpll.ads
@@ -0,0 +1,28 @@
+--
+-- Copyright (C) 2015-2016 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; version 2 of the License.
+--
+-- 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.WRPLL
+is
+
+ type Value_Array is array (WRPLLs) of Word32;
+ Register_Value : constant Value_Array := Value_Array'
+ (WRPLL0 => 4 * 2 ** 29, WRPLL1 => 5 * 2 ** 29);
+
+ procedure On
+ (PLL : in WRPLLs;
+ Target_Clock : in Frequency_Type;
+ Success : out Boolean);
+
+ procedure Off (PLL : WRPLLs);
+
+end HW.GFX.GMA.PLLs.WRPLL;
diff --git a/common/haswell/hw-gfx-gma-plls.adb b/common/haswell/hw-gfx-gma-plls.adb
new file mode 100644
index 0000000..45faa66
--- /dev/null
+++ b/common/haswell/hw-gfx-gma-plls.adb
@@ -0,0 +1,130 @@
+--
+-- Copyright (C) 2015-2016 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; version 2 of the License.
+--
+-- 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.GFX.GMA.PLLs.LCPLL;
+with HW.GFX.GMA.PLLs.WRPLL;
+
+with HW.Debug;
+with GNAT.Source_Info;
+
+package body HW.GFX.GMA.PLLs
+with
+ Refined_State => (State => PLLs)
+is
+
+ type Count_Range is new Natural range 0 .. 2;
+
+ type PLL_State is record
+ Use_Count : Count_Range;
+ Mode : Mode_Type;
+ end record;
+
+ type PLL_State_Array is array (WRPLLs) of PLL_State;
+
+ PLLs : PLL_State_Array;
+
+ procedure Initialize
+ is
+ begin
+ PLLs := (WRPLLs => (Use_Count => 0, Mode => Invalid_Mode));
+ end Initialize;
+
+ procedure Alloc_Configurable
+ (Mode : in Mode_Type;
+ PLL : out T;
+ Success : out Boolean)
+ with
+ Pre => True
+ is
+ begin
+ -- try to find shareable PLL
+ for P in WRPLLs loop
+ Success := PLLs (P).Use_Count /= 0 and
+ PLLs (P).Use_Count /= Count_Range'Last and
+ PLLs (P).Mode = Mode;
+ if Success then
+ PLL := P;
+ PLLs (PLL).Use_Count := PLLs (PLL).Use_Count + 1;
+ return;
+ end if;
+ end loop;
+
+ -- try to find free PLL
+ for P in WRPLLs loop
+ if PLLs (P).Use_Count = 0 then
+ PLL := P;
+ WRPLL.On (PLL, Mode.Dotclock, Success);
+ if Success then
+ PLLs (PLL) := (Use_Count => 1, Mode => Mode);
+ end if;
+ return;
+ end if;
+ end loop;
+
+ 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 = DIGI_E then
+ PLL := Invalid;
+ Success := True;
+ elsif Port_Cfg.Display = DP then
+ PLL := LCPLL.Fixed_LCPLLs (Port_Cfg.DP.Bandwidth);
+ Success := True;
+ else
+ Alloc_Configurable (Port_Cfg.Mode, PLL, Success);
+ end if;
+ end Alloc;
+
+ procedure Free (PLL : T)
+ is
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ if PLL in WRPLLs then
+ if PLLs (PLL).Use_Count /= 0 then
+ PLLs (PLL).Use_Count := PLLs (PLL).Use_Count - 1;
+ if PLLs (PLL).Use_Count = 0 then
+ WRPLL.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 WRPLLs loop
+ WRPLL.Off (PLL);
+ end loop;
+ end All_Off;
+
+ function Register_Value (PLL : T) return Word32
+ is
+ begin
+ return
+ (if PLL in LCPLLs then LCPLL.Register_Value (PLL)
+ elsif PLL in WRPLLs then WRPLL.Register_Value (PLL)
+ else 0);
+ end Register_Value;
+
+end HW.GFX.GMA.PLLs;
diff --git a/common/haswell/hw-gfx-gma-plls.ads b/common/haswell/hw-gfx-gma-plls.ads
new file mode 100644
index 0000000..9b158ae
--- /dev/null
+++ b/common/haswell/hw-gfx-gma-plls.ads
@@ -0,0 +1,40 @@
+--
+-- Copyright (C) 2015-2016 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; version 2 of the License.
+--
+-- 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, LCPLL0, LCPLL1, LCPLL2, WRPLL0, WRPLL1);
+ subtype LCPLLs is T range LCPLL0 .. LCPLL2;
+ subtype WRPLLs is T range WRPLL0 .. WRPLL1;
+ Invalid : constant T := Invalid_PLL;
+
+ 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;
diff --git a/common/haswell/hw-gfx-gma-power_and_clocks.ads b/common/haswell/hw-gfx-gma-power_and_clocks.ads
new file mode 100644
index 0000000..5e040ed
--- /dev/null
+++ b/common/haswell/hw-gfx-gma-power_and_clocks.ads
@@ -0,0 +1,17 @@
+--
+-- Copyright (C) 2016 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; version 2 of the License.
+--
+-- 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.GFX.GMA.Power_And_Clocks_Haswell;
+
+private package HW.GFX.GMA.Power_And_Clocks
+ renames HW.GFX.GMA.Power_And_Clocks_Haswell;
diff --git a/common/haswell/hw-gfx-gma-spll.adb b/common/haswell/hw-gfx-gma-spll.adb
new file mode 100644
index 0000000..71c9cd4
--- /dev/null
+++ b/common/haswell/hw-gfx-gma-spll.adb
@@ -0,0 +1,43 @@
+--
+-- Copyright (C) 2015-2016 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; version 2 of the License.
+--
+-- 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.Registers;
+
+package body HW.GFX.GMA.SPLL is
+
+ SPLL_CTL_PLL_ENABLE : constant := 1 * 2 ** 31;
+ SPLL_CTL_REF_SEL_MASK : constant := 3 * 2 ** 28;
+ SPLL_CTL_REF_SEL_SSC : constant := 1 * 2 ** 28;
+ SPLL_CTL_REF_SEL_NON_SSC : constant := 2 * 2 ** 28;
+ SPLL_CTL_FREQ_SEL_MASK : constant := 3 * 2 ** 26;
+ SPLL_CTL_FREQ_SEL_810 : constant := 0 * 2 ** 26;
+ SPLL_CTL_FREQ_SEL_1350 : constant := 1 * 2 ** 26;
+
+ procedure On is
+ begin
+ Registers.Write
+ (Register => Registers.SPLL_CTL,
+ Value => SPLL_CTL_PLL_ENABLE or
+ SPLL_CTL_REF_SEL_SSC or
+ SPLL_CTL_FREQ_SEL_1350);
+ Registers.Posting_Read (Registers.SPLL_CTL);
+ Time.U_Delay (20);
+ end On;
+
+ procedure Off is
+ begin
+ Registers.Unset_Mask (Registers.SPLL_CTL, SPLL_CTL_PLL_ENABLE);
+ end Off;
+
+end HW.GFX.GMA.SPLL;
diff --git a/common/haswell/hw-gfx-gma-spll.ads b/common/haswell/hw-gfx-gma-spll.ads
new file mode 100644
index 0000000..223f856
--- /dev/null
+++ b/common/haswell/hw-gfx-gma-spll.ads
@@ -0,0 +1,20 @@
+--
+-- Copyright (C) 2015-2016 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; version 2 of the License.
+--
+-- 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.
+--
+
+package HW.GFX.GMA.SPLL is
+
+ procedure On;
+
+ procedure Off;
+
+end HW.GFX.GMA.SPLL;