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_shared/Makefile.inc b/common/haswell_shared/Makefile.inc
new file mode 100644
index 0000000..45b505b
--- /dev/null
+++ b/common/haswell_shared/Makefile.inc
@@ -0,0 +1,6 @@
+gfxinit-y += hw-gfx-gma-connectors-ddi.adb
+gfxinit-y += hw-gfx-gma-connectors-ddi.ads
+gfxinit-y += hw-gfx-gma-connectors.adb
+gfxinit-y += hw-gfx-gma-port_detect.adb
+gfxinit-y += hw-gfx-gma-power_and_clocks_haswell.adb
+gfxinit-y += hw-gfx-gma-power_and_clocks_haswell.ads
diff --git a/common/haswell_shared/hw-gfx-gma-connectors-ddi.adb b/common/haswell_shared/hw-gfx-gma-connectors-ddi.adb
new file mode 100644
index 0000000..0459681
--- /dev/null
+++ b/common/haswell_shared/hw-gfx-gma-connectors-ddi.adb
@@ -0,0 +1,554 @@
+--
+-- 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.DP_Training;
+with HW.GFX.GMA.Config;
+with HW.GFX.GMA.PCH.FDI;
+with HW.GFX.GMA.PCH.Transcoder;
+with HW.GFX.GMA.PCH.VGA;
+with HW.GFX.GMA.DP_Info;
+with HW.GFX.GMA.DP_Aux_Ch;
+with HW.GFX.GMA.SPLL;
+
+with HW.Debug;
+with GNAT.Source_Info;
+
+package body HW.GFX.GMA.Connectors.DDI is
+
+ DDI_BUF_CTL_BUFFER_ENABLE : constant := 1 * 2 ** 31;
+ DDI_BUF_CTL_TRANS_SELECT_MASK : constant := 15 * 2 ** 24;
+ DDI_BUF_CTL_PORT_REVERSAL : constant := 1 * 2 ** 16;
+ DDI_BUF_CTL_IDLE_STATUS : constant := 1 * 2 ** 7;
+ DDI_BUF_CTL_DDI_A_LANE_CAP : constant := 1 * 2 ** 4;
+ DDI_BUF_CTL_PORT_WIDTH_MASK : constant := 7 * 2 ** 1;
+ DDI_BUF_CTL_PORT_WIDTH_1_LANE : constant := 0 * 2 ** 1;
+ DDI_BUF_CTL_PORT_WIDTH_2_LANES : constant := 1 * 2 ** 1;
+ DDI_BUF_CTL_PORT_WIDTH_4_LANES : constant := 3 * 2 ** 1;
+ DDI_BUF_CTL_INIT_DISPLAY_DETECT : constant := 1 * 2 ** 0;
+
+ subtype DDI_BUF_CTL_TRANS_SELECT_T is Natural range 0 .. 9;
+ function DDI_BUF_CTL_TRANS_SELECT
+ (Sel : DDI_BUF_CTL_TRANS_SELECT_T)
+ return Word32;
+
+ type DDI_BUF_CTL_PORT_WIDTH_T is array (HW.GFX.DP_Lane_Count) of Word32;
+ DDI_BUF_CTL_PORT_WIDTH : constant DDI_BUF_CTL_PORT_WIDTH_T :=
+ DDI_BUF_CTL_PORT_WIDTH_T'
+ (HW.GFX.DP_Lane_Count_1 => DDI_BUF_CTL_PORT_WIDTH_1_LANE,
+ HW.GFX.DP_Lane_Count_2 => DDI_BUF_CTL_PORT_WIDTH_2_LANES,
+ HW.GFX.DP_Lane_Count_4 => DDI_BUF_CTL_PORT_WIDTH_4_LANES);
+
+ DP_TP_CTL_TRANSPORT_ENABLE : constant := 1 * 2 ** 31;
+ DP_TP_CTL_MODE_SST : constant := 0 * 2 ** 27;
+ DP_TP_CTL_MODE_MST : constant := 1 * 2 ** 27;
+ DP_TP_CTL_FORCE_ACT : constant := 1 * 2 ** 25;
+ DP_TP_CTL_ENHANCED_FRAME_ENABLE : constant := 1 * 2 ** 18;
+ DP_TP_CTL_FDI_AUTOTRAIN : constant := 1 * 2 ** 15;
+ DP_TP_CTL_LINK_TRAIN_MASK : constant := 7 * 2 ** 8;
+ DP_TP_CTL_LINK_TRAIN_PAT1 : constant := 0 * 2 ** 8;
+ DP_TP_CTL_LINK_TRAIN_PAT2 : constant := 1 * 2 ** 8;
+ DP_TP_CTL_LINK_TRAIN_PAT3 : constant := 4 * 2 ** 8;
+ DP_TP_CTL_LINK_TRAIN_IDLE : constant := 2 * 2 ** 8;
+ DP_TP_CTL_LINK_TRAIN_NORMAL : constant := 3 * 2 ** 8;
+ DP_TP_CTL_SCRAMBLE_DISABLE : constant := 1 * 2 ** 7;
+ DP_TP_CTL_ALT_SCRAMBLER_RESET : constant := 1 * 2 ** 6;
+
+ type DP_TP_CTL_LINK_TRAIN_Array is
+ array (DP_Info.Training_Pattern) of Word32;
+ DP_TP_CTL_LINK_TRAIN : constant DP_TP_CTL_LINK_TRAIN_Array :=
+ DP_TP_CTL_LINK_TRAIN_Array'
+ (DP_Info.TP_1 => DP_TP_CTL_LINK_TRAIN_PAT1 or DP_TP_CTL_SCRAMBLE_DISABLE,
+ DP_Info.TP_2 => DP_TP_CTL_LINK_TRAIN_PAT2 or DP_TP_CTL_SCRAMBLE_DISABLE,
+ DP_Info.TP_3 => DP_TP_CTL_LINK_TRAIN_PAT3 or DP_TP_CTL_SCRAMBLE_DISABLE,
+ DP_Info.TP_Idle => DP_TP_CTL_LINK_TRAIN_IDLE,
+ DP_Info.TP_None => DP_TP_CTL_LINK_TRAIN_NORMAL);
+
+ DP_TP_STATUS_MIN_IDLES_SENT : constant := 1 * 2 ** 25;
+ DP_TP_STATUS_FDI_AUTO_TRAIN_DONE : constant := 1 * 2 ** 12;
+
+ PORT_CLK_SEL_LCPLL2700 : constant := 0 * 2 ** 29; -- not on ULX
+ PORT_CLK_SEL_LCPLL1350 : constant := 1 * 2 ** 29;
+ PORT_CLK_SEL_LCPLL810 : constant := 2 * 2 ** 29;
+ PORT_CLK_SEL_SPLL : constant := 3 * 2 ** 29;
+ PORT_CLK_SEL_WRPLL1 : constant := 4 * 2 ** 29;
+ PORT_CLK_SEL_WRPLL2 : constant := 5 * 2 ** 29;
+ PORT_CLK_SEL_NONE : constant := 7 * 2 ** 29;
+
+ type PORT_CLK_SEL_LCPLL_T is array (HW.GFX.DP_Bandwidth) of Word32;
+ PORT_CLK_SEL_LCPLL : constant PORT_CLK_SEL_LCPLL_T :=
+ PORT_CLK_SEL_LCPLL_T'
+ (HW.GFX.DP_Bandwidth_1_62 => PORT_CLK_SEL_LCPLL810,
+ HW.GFX.DP_Bandwidth_2_7 => PORT_CLK_SEL_LCPLL1350,
+ HW.GFX.DP_Bandwidth_5_4 => PORT_CLK_SEL_LCPLL2700);
+
+ type DDI_Registers is record
+ BUF_CTL : Registers.Registers_Index;
+ DP_TP_CTL : Registers.Registers_Index;
+ DP_TP_STATUS : Registers.Registers_Invalid_Index;
+ PORT_CLK_SEL : Registers.Registers_Index;
+ end record;
+
+ type DDI_Registers_Array is array (Digital_Port) of DDI_Registers;
+
+ DDI_Regs : constant DDI_Registers_Array := DDI_Registers_Array'
+ (DIGI_A => DDI_Registers'
+ (BUF_CTL => Registers.DDI_BUF_CTL_A,
+ DP_TP_CTL => Registers.DP_TP_CTL_A,
+ DP_TP_STATUS => Registers.Invalid_Register,
+ PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIA),
+ DIGI_B => DDI_Registers'
+ (BUF_CTL => Registers.DDI_BUF_CTL_B,
+ DP_TP_CTL => Registers.DP_TP_CTL_B,
+ DP_TP_STATUS => Registers.DP_TP_STATUS_B,
+ PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIB),
+ DIGI_C => DDI_Registers'
+ (BUF_CTL => Registers.DDI_BUF_CTL_C,
+ DP_TP_CTL => Registers.DP_TP_CTL_C,
+ DP_TP_STATUS => Registers.DP_TP_STATUS_C,
+ PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIC),
+ DIGI_D => DDI_Registers'
+ (BUF_CTL => Registers.DDI_BUF_CTL_D,
+ DP_TP_CTL => Registers.DP_TP_CTL_D,
+ DP_TP_STATUS => Registers.DP_TP_STATUS_D,
+ PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDID),
+ DIGI_E => DDI_Registers'
+ (BUF_CTL => Registers.DDI_BUF_CTL_E,
+ DP_TP_CTL => Registers.DP_TP_CTL_E,
+ DP_TP_STATUS => Registers.DP_TP_STATUS_E,
+ PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIE));
+
+ ----------------------------------------------------------------------------
+
+ type Values is array (Digital_Port) of Word32;
+ type Shifts is array (Digital_Port) of Natural;
+
+ DPLL_CTRL2_DDIx_CLOCK_OFF : constant Values := Values'
+ (DIGI_A => 1 * 2 ** 15,
+ DIGI_B => 1 * 2 ** 16,
+ DIGI_C => 1 * 2 ** 17,
+ DIGI_D => 1 * 2 ** 18,
+ DIGI_E => 1 * 2 ** 19);
+
+ DPLL_CTRL2_DDIx_SELECT_MASK : constant Values := Values'
+ (DIGI_A => 3 * 2 ** 1,
+ DIGI_B => 3 * 2 ** 4,
+ DIGI_C => 3 * 2 ** 7,
+ DIGI_D => 3 * 2 ** 10,
+ DIGI_E => 3 * 2 ** 13);
+ DPLL_CTRL2_DDIx_SELECT_SHIFT : constant Shifts := Shifts'
+ (DIGI_A => 1,
+ DIGI_B => 4,
+ DIGI_C => 7,
+ DIGI_D => 10,
+ DIGI_E => 13);
+
+ DPLL_CTRL2_DDIx_SELECT_OVERRIDE : constant Values := Values'
+ (DIGI_A => 1 * 2 ** 0,
+ DIGI_B => 1 * 2 ** 3,
+ DIGI_C => 1 * 2 ** 6,
+ DIGI_D => 1 * 2 ** 9,
+ DIGI_E => 1 * 2 ** 12);
+
+ ----------------------------------------------------------------------------
+
+ function DDI_BUF_CTL_TRANS_SELECT
+ (Sel : DDI_BUF_CTL_TRANS_SELECT_T)
+ return Word32
+ is
+ begin
+ return Word32 (Sel) * 2 ** 24;
+ end DDI_BUF_CTL_TRANS_SELECT;
+
+ ----------------------------------------------------------------------------
+
+ function Max_V_Swing
+ (Port : Digital_Port)
+ return DP_Info.DP_Voltage_Swing
+ is
+ begin
+ return
+ (if (Config.Has_Low_Voltage_Swing and Config.EDP_Low_Voltage_Swing)
+ and then Port = DIGI_A
+ then
+ DP_Info.VS_Level_3
+ else
+ DP_Info.VS_Level_2);
+ end Max_V_Swing;
+
+ pragma Warnings (GNATprove, Off, "unused variable ""Port""",
+ Reason => "Needed for a common interface");
+ function Max_Pre_Emph
+ (Port : Digital_Port;
+ Train_Set : DP_Info.Train_Set)
+ return DP_Info.DP_Pre_Emph
+ is
+ begin
+ return
+ (case Train_Set.Voltage_Swing is
+ when DP_Info.VS_Level_0 => DP_Info.Emph_Level_3,
+ when DP_Info.VS_Level_1 => DP_Info.Emph_Level_2,
+ when DP_Info.VS_Level_2 => DP_Info.Emph_Level_1,
+ when others => DP_Info.Emph_Level_0);
+ end Max_Pre_Emph;
+ pragma Warnings (GNATprove, On, "unused variable ""Port""");
+
+ ----------------------------------------------------------------------------
+
+ procedure Set_TP_CTL
+ (Port : Digital_Port;
+ Link : DP_Link;
+ Pattern : DP_Info.Training_Pattern)
+ is
+ DP_TP_CTL_Enhanced_Frame : Word32 := 0;
+ begin
+ if Link.Enhanced_Framing then
+ DP_TP_CTL_Enhanced_Frame := DP_TP_CTL_ENHANCED_FRAME_ENABLE;
+ end if;
+
+ Registers.Write
+ (Register => DDI_Regs (Port).DP_TP_CTL,
+ Value => DP_TP_CTL_TRANSPORT_ENABLE or
+ DP_TP_CTL_Enhanced_Frame or
+ DP_TP_CTL_LINK_TRAIN (Pattern));
+ end Set_TP_CTL;
+
+ procedure Set_Training_Pattern
+ (Port : Digital_Port;
+ Link : DP_Link;
+ Pattern : DP_Info.Training_Pattern)
+ is
+ use type DP_Info.Training_Pattern;
+ begin
+ if Pattern < DP_Info.TP_Idle then
+ Set_TP_CTL (Port, Link, Pattern);
+ else
+ -- send at least 5 idle patterns
+ Set_TP_CTL (Port, Link, DP_Info.TP_Idle);
+
+ -- switch to normal frame delivery
+ if Config.End_EDP_Training_Late and then Port = DIGI_A then
+ null; -- do it later in Post_On procedure
+ -- TODO: if there are problems getting the pipe up,
+ -- wait here some time
+ -- Time.U_Delay (100);
+ else
+ if Port /= DIGI_A then
+ Registers.Wait_Set_Mask
+ (Register => DDI_Regs (Port).DP_TP_STATUS,
+ Mask => DP_TP_STATUS_MIN_IDLES_SENT);
+ end if;
+ Set_TP_CTL (Port, Link, DP_Info.TP_None);
+ end if;
+ end if;
+ end Set_Training_Pattern;
+
+ procedure Set_Signal_Levels
+ (Port : Digital_Port;
+ Link : DP_Link;
+ Train_Set : DP_Info.Train_Set)
+ is
+ Was_Enabled : Boolean;
+ Trans_Select : DDI_BUF_CTL_TRANS_SELECT_T;
+ begin
+ case Train_Set.Voltage_Swing is
+ when DP_Info.VS_Level_0 =>
+ case Train_Set.Pre_Emph is
+ when DP_Info.Emph_Level_0 => Trans_Select := 0;
+ when DP_Info.Emph_Level_1 => Trans_Select := 1;
+ when DP_Info.Emph_Level_2 => Trans_Select := 2;
+ when DP_Info.Emph_Level_3 => Trans_Select := 3;
+ end case;
+ when DP_Info.VS_Level_1 =>
+ case Train_Set.Pre_Emph is
+ when DP_Info.Emph_Level_0 => Trans_Select := 4;
+ when DP_Info.Emph_Level_1 => Trans_Select := 5;
+ when DP_Info.Emph_Level_2 => Trans_Select := 6;
+ when others => Trans_Select := 0;
+ end case;
+ when DP_Info.VS_Level_2 =>
+ case Train_Set.Pre_Emph is
+ when DP_Info.Emph_Level_0 => Trans_Select := 7;
+ when DP_Info.Emph_Level_1 => Trans_Select := 8;
+ when others => Trans_Select := 0;
+ end case;
+ when DP_Info.VS_Level_3 =>
+ case Train_Set.Pre_Emph is
+ when DP_Info.Emph_Level_0 => Trans_Select := 9;
+ when others => Trans_Select := 0;
+ end case;
+ end case;
+
+ Registers.Is_Set_Mask
+ (Register => DDI_Regs (Port).BUF_CTL,
+ Mask => DDI_BUF_CTL_BUFFER_ENABLE,
+ Result => Was_Enabled);
+
+ -- enable DDI buffer
+ Registers.Unset_And_Set_Mask
+ (Register => DDI_Regs (Port).BUF_CTL,
+ Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
+ DDI_BUF_CTL_PORT_REVERSAL or
+ DDI_BUF_CTL_PORT_WIDTH_MASK,
+ Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE or
+ DDI_BUF_CTL_TRANS_SELECT (Trans_Select) or
+ DDI_BUF_CTL_PORT_WIDTH (Link.Lane_Count));
+ Registers.Posting_Read (DDI_Regs (Port).BUF_CTL);
+
+ if not Was_Enabled then
+ Time.U_Delay (600); -- wait >= 518us (intel spec)
+ end if;
+ end Set_Signal_Levels;
+
+ ----------------------------------------------------------------------------
+
+ procedure Digital_Off (Port : Digital_Port)
+ is
+ Enabled : Boolean;
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ Registers.Is_Set_Mask
+ (Register => DDI_Regs (Port).BUF_CTL,
+ Mask => DDI_BUF_CTL_BUFFER_ENABLE,
+ Result => Enabled);
+
+ if Enabled then
+ Registers.Unset_Mask
+ (Register => DDI_Regs (Port).BUF_CTL,
+ Mask => DDI_BUF_CTL_BUFFER_ENABLE);
+ end if;
+
+ Registers.Unset_Mask
+ (Register => DDI_Regs (Port).DP_TP_CTL,
+ Mask => DP_TP_CTL_TRANSPORT_ENABLE);
+
+ if Enabled then
+ Registers.Wait_Set_Mask
+ (Register => DDI_Regs (Port).BUF_CTL,
+ Mask => DDI_BUF_CTL_IDLE_STATUS);
+ end if;
+
+ if Config.Has_Per_DDI_Clock_Sel then
+ Registers.Write
+ (Register => DDI_Regs (Port).PORT_CLK_SEL,
+ Value => PORT_CLK_SEL_NONE);
+ else
+ Registers.Set_Mask
+ (Register => Registers.DPLL_CTRL2,
+ Mask => DPLL_CTRL2_DDIx_CLOCK_OFF (Port));
+ end if;
+ end Digital_Off;
+
+ ----------------------------------------------------------------------------
+
+ procedure Train_FDI
+ (Port_Cfg : in Port_Config;
+ Success : out Boolean)
+ is
+ begin
+ PCH.FDI.Pre_Train (PCH.FDI_A, Port_Cfg);
+
+ -- always use SPLL for FDI
+ SPLL.On;
+ Registers.Write
+ (Register => DDI_Regs (DIGI_E).PORT_CLK_SEL,
+ Value => PORT_CLK_SEL_SPLL);
+
+ -- try each preemph/voltage pair twice
+ for Trans2 in Natural range 0 .. DDI_BUF_CTL_TRANS_SELECT_T'Last * 2 + 1
+ loop
+ Registers.Write
+ (Register => DDI_Regs (DIGI_E).DP_TP_CTL,
+ Value => DP_TP_CTL_TRANSPORT_ENABLE or
+ DP_TP_CTL_ENHANCED_FRAME_ENABLE or
+ DP_TP_CTL_FDI_AUTOTRAIN or
+ DP_TP_CTL_LINK_TRAIN_PAT1);
+
+ Registers.Unset_And_Set_Mask
+ (Register => DDI_Regs (DIGI_E).BUF_CTL,
+ Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
+ DDI_BUF_CTL_PORT_REVERSAL or
+ DDI_BUF_CTL_PORT_WIDTH_MASK,
+ Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE or
+ DDI_BUF_CTL_TRANS_SELECT (Trans2 / 2) or
+ DDI_BUF_CTL_PORT_WIDTH (Port_Cfg.FDI.Lane_Count));
+ Registers.Posting_Read (DDI_Regs (DIGI_E).BUF_CTL);
+ Time.U_Delay (600); -- wait >= 518us (intel spec)
+
+ PCH.FDI.Auto_Train (PCH.FDI_A);
+ Registers.Is_Set_Mask
+ (Register => DDI_Regs (DIGI_E).DP_TP_STATUS,
+ Mask => DP_TP_STATUS_FDI_AUTO_TRAIN_DONE,
+ Result => Success);
+ exit when Success;
+
+ Registers.Unset_Mask
+ (Register => DDI_Regs (DIGI_E).BUF_CTL,
+ Mask => DDI_BUF_CTL_BUFFER_ENABLE);
+ Registers.Posting_Read (DDI_Regs (DIGI_E).BUF_CTL);
+
+ Registers.Unset_And_Set_Mask
+ (Register => DDI_Regs (DIGI_E).DP_TP_CTL,
+ Mask_Unset => DP_TP_CTL_TRANSPORT_ENABLE or
+ DP_TP_CTL_LINK_TRAIN_MASK,
+ Mask_Set => DP_TP_CTL_LINK_TRAIN_PAT1);
+ Registers.Posting_Read (DDI_Regs (DIGI_E).DP_TP_CTL);
+
+ Registers.Wait_Set_Mask
+ (Register => DDI_Regs (DIGI_E).BUF_CTL,
+ Mask => DDI_BUF_CTL_IDLE_STATUS);
+
+ PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Lanes_Off);
+ end loop;
+
+ if Success then
+ -- start normal frame delivery
+ Registers.Write
+ (Register => DDI_Regs (DIGI_E).DP_TP_CTL,
+ Value => DP_TP_CTL_TRANSPORT_ENABLE or
+ DP_TP_CTL_ENHANCED_FRAME_ENABLE or
+ DP_TP_CTL_FDI_AUTOTRAIN or
+ DP_TP_CTL_LINK_TRAIN_NORMAL);
+ else
+ Registers.Write
+ (Register => DDI_Regs (DIGI_E).PORT_CLK_SEL,
+ Value => PORT_CLK_SEL_NONE);
+ SPLL.Off;
+
+ PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Clock_Off);
+ end if;
+ end Train_FDI;
+
+ ----------------------------------------------------------------------------
+
+ procedure Pre_On
+ (Port_Cfg : in Port_Config;
+ PLL_Hint : in Word32;
+ Success : out Boolean)
+ is
+ function To_DP (Port : Digital_Port) return DP_Port
+ is
+ begin
+ return
+ (case Port is
+ when DIGI_A => DP_A,
+ when DIGI_B => DP_B,
+ when DIGI_C => DP_C,
+ when DIGI_D => DP_D,
+ when others => DP_Port'First);
+ end To_DP;
+ package Training is new DP_Training
+ (TPS3_Supported => True,
+ T => Digital_Port,
+ Aux_T => DP_Port,
+ Aux_Ch => DP_Aux_Ch,
+ DP_Info => DP_Info,
+ To_Aux => To_DP,
+ Max_V_Swing => Max_V_Swing,
+ Max_Pre_Emph => Max_Pre_Emph,
+ Set_Pattern => Set_Training_Pattern,
+ Set_Signal_Levels => Set_Signal_Levels,
+ Off => Digital_Off);
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ if Port_Cfg.Display = VGA then
+ Train_FDI (Port_Cfg, Success);
+ else
+ -- direct configured PLL output to this port
+ if Config.Has_Per_DDI_Clock_Sel then
+ Registers.Write
+ (Register => DDI_Regs (Port_Cfg.Port).PORT_CLK_SEL,
+ Value => PLL_Hint);
+ else
+ Registers.Unset_And_Set_Mask
+ (Register => Registers.DPLL_CTRL2,
+ Mask_Unset => DPLL_CTRL2_DDIx_CLOCK_OFF (Port_Cfg.Port) or
+ DPLL_CTRL2_DDIx_SELECT_MASK (Port_Cfg.Port),
+ Mask_Set => Shift_Left
+ (PLL_Hint,
+ DPLL_CTRL2_DDIx_SELECT_SHIFT (Port_Cfg.Port))
+ or
+ DPLL_CTRL2_DDIx_SELECT_OVERRIDE (Port_Cfg.Port));
+ end if;
+
+ if Port_Cfg.Display = DP then
+ Training.Train_DP
+ (Port => Port_Cfg.Port,
+ Link => Port_Cfg.DP,
+ Success => Success);
+ else
+ Success := True;
+ end if;
+ end if;
+ end Pre_On;
+
+ ----------------------------------------------------------------------------
+
+ procedure Post_On (Port_Cfg : Port_Config)
+ is
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ if Port_Cfg.Port = DIGI_A then
+ if Config.End_EDP_Training_Late then
+ Registers.Unset_And_Set_Mask
+ (Register => DDI_Regs (DIGI_A).DP_TP_CTL,
+ Mask_Unset => DP_TP_CTL_LINK_TRAIN_MASK,
+ Mask_Set => DP_TP_CTL_LINK_TRAIN_NORMAL);
+ end if;
+ end if;
+
+ case Port_Cfg.Display is
+ when HDMI =>
+ Registers.Unset_And_Set_Mask
+ (Register => DDI_Regs (Port_Cfg.Port).BUF_CTL,
+ Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
+ DDI_BUF_CTL_PORT_REVERSAL,
+ Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE);
+ Time.U_Delay (600); -- wait >= 518us (intel spec)
+ when VGA =>
+ PCH.VGA.Clock_On (Port_Cfg.Mode);
+ PCH.Transcoder.On (Port_Cfg, PCH.FDI_A, 0);
+ PCH.VGA.On
+ (Port => PCH.FDI_A,
+ Mode => Port_Cfg.Mode);
+ when others =>
+ null;
+ end case;
+ end Post_On;
+
+ ----------------------------------------------------------------------------
+
+ procedure Off (Port : Digital_Port)
+ is
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ if Port = DIGI_E then
+ PCH.VGA.Off;
+ PCH.Transcoder.Off (PCH.FDI_A);
+ -- PCH.VGA.Clock_Off; -- Can't tell what Linux does, if anything.
+ PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Rx_Off);
+ end if;
+
+ Digital_Off (Port);
+
+ if Port = DIGI_E then
+ SPLL.Off;
+ PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Clock_Off);
+ end if;
+ end Off;
+
+end HW.GFX.GMA.Connectors.DDI;
diff --git a/common/haswell_shared/hw-gfx-gma-connectors-ddi.ads b/common/haswell_shared/hw-gfx-gma-connectors-ddi.ads
new file mode 100644
index 0000000..337e77b
--- /dev/null
+++ b/common/haswell_shared/hw-gfx-gma-connectors-ddi.ads
@@ -0,0 +1,28 @@
+--
+-- 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.GFX.GMA.Registers;
+
+private package HW.GFX.GMA.Connectors.DDI
+is
+
+ procedure Pre_On
+ (Port_Cfg : in Port_Config;
+ PLL_Hint : in Word32;
+ Success : out Boolean);
+
+ procedure Post_On (Port_Cfg : Port_Config);
+
+ procedure Off (Port : Digital_Port);
+
+end HW.GFX.GMA.Connectors.DDI;
diff --git a/common/haswell_shared/hw-gfx-gma-connectors.adb b/common/haswell_shared/hw-gfx-gma-connectors.adb
new file mode 100644
index 0000000..e53902b
--- /dev/null
+++ b/common/haswell_shared/hw-gfx-gma-connectors.adb
@@ -0,0 +1,93 @@
+--
+-- 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.Config;
+with HW.GFX.GMA.Panel;
+with HW.GFX.GMA.Connectors.DDI;
+
+with HW.Debug;
+with GNAT.Source_Info;
+
+package body HW.GFX.GMA.Connectors is
+
+ procedure Pre_On
+ (Port_Cfg : in Port_Config;
+ PLL_Hint : in Word32;
+ Pipe_Hint : in Word32;
+ Success : out Boolean)
+ is
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ DDI.Pre_On (Port_Cfg, PLL_Hint, Success);
+ end Pre_On;
+
+ procedure Post_On
+ (Port_Cfg : in Port_Config;
+ PLL_Hint : in Word32;
+ Success : out Boolean)
+ is
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ DDI.Post_On (Port_Cfg);
+
+ if Port_Cfg.Port = DIGI_A then
+ Panel.Backlight_On;
+ end if;
+
+ Success := True;
+ end Post_On;
+
+ ----------------------------------------------------------------------------
+
+ procedure Pre_Off (Port_Cfg : Port_Config)
+ is
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ if Port_Cfg.Port = DIGI_A then
+ Panel.Backlight_Off;
+ Panel.Off;
+ end if;
+ end Pre_Off;
+
+ procedure Post_Off (Port_Cfg : Port_Config)
+ is
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ DDI.Off (Port_Cfg.Port);
+ end Post_Off;
+
+ ----------------------------------------------------------------------------
+
+ procedure Pre_All_Off
+ is
+ begin
+ Panel.Backlight_Off;
+ Panel.Off;
+ end Pre_All_Off;
+
+ procedure Post_All_Off
+ is
+ begin
+ for Port in Digital_Port range DIGI_A .. DIGI_D loop
+ DDI.Off (Port);
+ end loop;
+ if Config.FDI_Port (DIGI_E) then
+ DDI.Off (DIGI_E);
+ end if;
+ end Post_All_Off;
+
+end HW.GFX.GMA.Connectors;
diff --git a/common/haswell_shared/hw-gfx-gma-port_detect.adb b/common/haswell_shared/hw-gfx-gma-port_detect.adb
new file mode 100644
index 0000000..0becd2c
--- /dev/null
+++ b/common/haswell_shared/hw-gfx-gma-port_detect.adb
@@ -0,0 +1,189 @@
+--
+-- 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.Config;
+with HW.GFX.GMA.Registers;
+
+package body HW.GFX.GMA.Port_Detect
+is
+
+ PCH_ADPA_CRT_HPD_CHANNEL_MASK : constant := 3 * 2 ** 24;
+ PCH_ADPA_CRT_HPD_ENABLE : constant := 1 * 2 ** 23;
+
+ SFUSE_STRAP_CRT_DAC_CAP_DISABLE : constant := 1 * 2 ** 6;
+
+ HOTPLUG_CTL_DDI_A_HPD_INPUT_ENABLE : constant := 1 * 2 ** 4;
+ HOTPLUG_CTL_DDI_A_HPD_STATUS : constant := 3 * 2 ** 0;
+ HOTPLUG_CTL_DDI_A_HPD_LONG_DETECT : constant := 1 * 2 ** 1;
+
+ SHOTPLUG_CTL_DETECT_MASK : constant := 16#0303_0303#;
+
+ type Digital_Port_Value is array (Digital_Port) of Word32;
+ DDI_PORT_DETECTED : constant Digital_Port_Value :=
+ (DIGI_B => 1 * 2 ** 2,
+ DIGI_C => 1 * 2 ** 1,
+ DIGI_D => 1 * 2 ** 0,
+ DIGI_A => 1 * 2 ** 0,
+ others => 0);
+ SHOTPLUG_CTL_HPD_INPUT_ENABLE : constant Digital_Port_Value :=
+ (DIGI_B => 1 * 2 ** 4,
+ DIGI_C => 1 * 2 ** 12,
+ DIGI_D => 1 * 2 ** 20,
+ DIGI_A => 1 * 2 ** 28,
+ others => 0);
+ SHOTPLUG_CTL_HPD_STATUS : constant Digital_Port_Value :=
+ (DIGI_B => 3 * 2 ** 0,
+ DIGI_C => 3 * 2 ** 8,
+ DIGI_D => 3 * 2 ** 16,
+ DIGI_A => 3 * 2 ** 24,
+ others => 0);
+ SHOTPLUG_CTL_LONG_DETECT : constant Digital_Port_Value :=
+ (DIGI_B => 1 * 2 ** 1,
+ DIGI_C => 1 * 2 ** 9,
+ DIGI_D => 1 * 2 ** 17,
+ DIGI_A => 1 * 2 ** 25,
+ others => 0);
+
+ procedure Initialize
+ is
+ DAC_Disabled,
+ Internal_Detected,
+ DDI_Detected : Boolean;
+
+ Last_Digital_Port : constant Digital_Port :=
+ (if Config.Has_DDI_D then DIGI_D else DIGI_C);
+
+ subtype Ext_Digital_Port is
+ Digital_Port range DIGI_B .. DIGI_D;
+ type Digital_Port_To_GMA_Port is array (Ext_Digital_Port) of Port_Type;
+ To_HDMI_Port : constant Digital_Port_To_GMA_Port :=
+ (DIGI_B => Digital1,
+ DIGI_C => Digital2,
+ DIGI_D => Digital3);
+ To_DP_Port : constant Digital_Port_To_GMA_Port :=
+ (DIGI_B => DP1,
+ DIGI_C => DP2,
+ DIGI_D => DP3);
+ begin
+ if Config.Has_PCH_DAC then
+ -- PCH_DAC (_A)
+ Registers.Is_Set_Mask
+ (Register => Registers.SFUSE_STRAP,
+ Mask => SFUSE_STRAP_CRT_DAC_CAP_DISABLE,
+ Result => DAC_Disabled);
+ if not DAC_Disabled then
+ Registers.Set_Mask
+ (Register => Registers.PCH_ADPA,
+ Mask => PCH_ADPA_CRT_HPD_CHANNEL_MASK or -- clear status
+ PCH_ADPA_CRT_HPD_ENABLE);
+ end if;
+ Config.Valid_Port (Analog) := not DAC_Disabled;
+ end if;
+
+ if Config.Internal_Is_EDP then
+ -- DDI_A
+ Registers.Is_Set_Mask
+ (Register => Registers.DDI_BUF_CTL_A,
+ Mask => DDI_PORT_DETECTED (DIGI_A),
+ Result => Internal_Detected);
+ if Internal_Detected then
+ if Config.Has_HOTPLUG_CTL then
+ Registers.Set_Mask
+ (Register => Registers.HOTPLUG_CTL,
+ Mask => HOTPLUG_CTL_DDI_A_HPD_INPUT_ENABLE or
+ HOTPLUG_CTL_DDI_A_HPD_STATUS); -- clear status
+ if Config.Has_SHOTPLUG_CTL_A then
+ -- Have to enable south hotplug too on SoCs.
+ Registers.Unset_And_Set_Mask
+ (Register => Registers.SHOTPLUG_CTL,
+ Mask_Unset => SHOTPLUG_CTL_DETECT_MASK,
+ Mask_Set => SHOTPLUG_CTL_HPD_INPUT_ENABLE (DIGI_A));
+ end if;
+ else
+ Registers.Unset_And_Set_Mask
+ (Register => Registers.SHOTPLUG_CTL,
+ Mask_Unset => SHOTPLUG_CTL_DETECT_MASK,
+ Mask_Set => SHOTPLUG_CTL_HPD_INPUT_ENABLE (DIGI_A) or
+ SHOTPLUG_CTL_HPD_STATUS (DIGI_A)); -- clear
+ end if;
+ end if;
+ else
+ Internal_Detected := False;
+ end if;
+ Config.Valid_Port (Internal) := Internal_Detected;
+
+ -- DDI_[BCD]
+ for Port in Ext_Digital_Port range DIGI_B .. Last_Digital_Port loop
+ Registers.Is_Set_Mask
+ (Register => Registers.SFUSE_STRAP,
+ Mask => DDI_PORT_DETECTED (Port),
+ Result => DDI_Detected);
+ Config.Valid_Port (To_HDMI_Port (Port)) :=
+ Config.Valid_Port (To_HDMI_Port (Port)) and DDI_Detected;
+ Config.Valid_Port (To_DP_Port (Port)) :=
+ Config.Valid_Port (To_DP_Port (Port)) and DDI_Detected;
+
+ if DDI_Detected then
+ Registers.Unset_And_Set_Mask
+ (Register => Registers.SHOTPLUG_CTL,
+ Mask_Unset => SHOTPLUG_CTL_DETECT_MASK,
+ Mask_Set => SHOTPLUG_CTL_HPD_INPUT_ENABLE (Port) or
+ SHOTPLUG_CTL_HPD_STATUS (Port)); -- clear status
+ else
+ Registers.Unset_Mask
+ (Register => Registers.SHOTPLUG_CTL,
+ Mask => SHOTPLUG_CTL_DETECT_MASK or
+ SHOTPLUG_CTL_HPD_INPUT_ENABLE (Port));
+ end if;
+ end loop;
+ end Initialize;
+
+ procedure Hotplug_Detect (Port_Cfg : in Port_Config; Detected : out Boolean)
+ is
+ Ctl32 : Word32;
+ begin
+ if Port_Cfg.Display = VGA then
+ Registers.Read (Registers.PCH_ADPA, Ctl32, Verbose => False);
+ Ctl32 := Ctl32 and PCH_ADPA_CRT_HPD_CHANNEL_MASK;
+ Detected := Ctl32 = PCH_ADPA_CRT_HPD_CHANNEL_MASK;
+ if Ctl32 /= 0 then
+ Registers.Set_Mask
+ (Register => Registers.PCH_ADPA,
+ Mask => PCH_ADPA_CRT_HPD_CHANNEL_MASK);
+ end if;
+ elsif Config.Has_HOTPLUG_CTL and then Port_Cfg.Port = DIGI_A then
+ Registers.Read (Registers.HOTPLUG_CTL, Ctl32, Verbose => False);
+ Detected := (Ctl32 and HOTPLUG_CTL_DDI_A_HPD_LONG_DETECT) /= 0;
+
+ if (Ctl32 and HOTPLUG_CTL_DDI_A_HPD_STATUS) /= 0 then
+ Registers.Set_Mask
+ (Register => Registers.HOTPLUG_CTL,
+ Mask => HOTPLUG_CTL_DDI_A_HPD_STATUS);
+ end if;
+ elsif Port_Cfg.Port in DIGI_A .. DIGI_D then
+ Registers.Read (Registers.SHOTPLUG_CTL, Ctl32, Verbose => False);
+ Detected :=
+ (Ctl32 and SHOTPLUG_CTL_LONG_DETECT (Port_Cfg.Port)) /= 0;
+
+ if (Ctl32 and SHOTPLUG_CTL_HPD_STATUS (Port_Cfg.Port)) /= 0 then
+ Registers.Unset_And_Set_Mask
+ (Register => Registers.SHOTPLUG_CTL,
+ Mask_Unset => SHOTPLUG_CTL_DETECT_MASK,
+ Mask_Set => SHOTPLUG_CTL_HPD_STATUS (Port_Cfg.Port));
+ end if;
+ else
+ Detected := False;
+ end if;
+ end Hotplug_Detect;
+
+end HW.GFX.GMA.Port_Detect;
diff --git a/common/haswell_shared/hw-gfx-gma-power_and_clocks_haswell.adb b/common/haswell_shared/hw-gfx-gma-power_and_clocks_haswell.adb
new file mode 100644
index 0000000..b46c29d
--- /dev/null
+++ b/common/haswell_shared/hw-gfx-gma-power_and_clocks_haswell.adb
@@ -0,0 +1,235 @@
+--
+-- Copyright (C) 2014-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 GNAT.Source_Info;
+
+with HW.Time;
+with HW.Debug;
+with HW.GFX.GMA.Config;
+with HW.GFX.GMA.Registers;
+
+package body HW.GFX.GMA.Power_And_Clocks_Haswell is
+
+ PWR_WELL_CTL_ENABLE_REQUEST : constant := 1 * 2 ** 31;
+ PWR_WELL_CTL_DISABLE_REQUEST : constant := 0 * 2 ** 31;
+ PWR_WELL_CTL_STATE_ENABLED : constant := 1 * 2 ** 30;
+
+ ----------------------------------------------------------------------------
+
+ SRD_CTL_ENABLE : constant := 1 * 2 ** 31;
+ SRD_STATUS_STATE_MASK : constant := 7 * 2 ** 29;
+
+ type Pipe is (EDP, A, B, C);
+ type SRD_Regs is record
+ CTL : Registers.Registers_Index;
+ STATUS : Registers.Registers_Index;
+ end record;
+ type SRD_Per_Pipe_Regs is array (Pipe) of SRD_Regs;
+ SRD : constant SRD_Per_Pipe_Regs := SRD_Per_Pipe_Regs'
+ (A => SRD_Regs'
+ (CTL => Registers.SRD_CTL_A,
+ STATUS => Registers.SRD_STATUS_A),
+ B => SRD_Regs'
+ (CTL => Registers.SRD_CTL_B,
+ STATUS => Registers.SRD_STATUS_B),
+ C => SRD_Regs'
+ (CTL => Registers.SRD_CTL_C,
+ STATUS => Registers.SRD_STATUS_C),
+ EDP => SRD_Regs'
+ (CTL => Registers.SRD_CTL_EDP,
+ STATUS => Registers.SRD_STATUS_EDP));
+
+ ----------------------------------------------------------------------------
+
+ IPS_CTL_ENABLE : constant := 1 * 2 ** 31;
+ DISPLAY_IPS_CONTROL : constant := 16#19#;
+
+ GT_MAILBOX_READY : constant := 1 * 2 ** 31;
+
+ ----------------------------------------------------------------------------
+
+ procedure PSR_Off
+ is
+ Enabled : Boolean;
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ if Config.Has_Per_Pipe_SRD then
+ for P in Pipe loop
+ Registers.Is_Set_Mask (SRD (P).CTL, SRD_CTL_ENABLE, Enabled);
+ if Enabled then
+ Registers.Unset_Mask (SRD (P).CTL, SRD_CTL_ENABLE);
+ Registers.Wait_Unset_Mask (SRD (P).STATUS, SRD_STATUS_STATE_MASK);
+
+ pragma Debug (Debug.Put_Line ("Disabled PSR."));
+ end if;
+ end loop;
+ else
+ Registers.Is_Set_Mask (Registers.SRD_CTL, SRD_CTL_ENABLE, Enabled);
+ if Enabled then
+ Registers.Unset_Mask (Registers.SRD_CTL, SRD_CTL_ENABLE);
+ Registers.Wait_Unset_Mask (Registers.SRD_STATUS, SRD_STATUS_STATE_MASK);
+
+ pragma Debug (Debug.Put_Line ("Disabled PSR."));
+ end if;
+ end if;
+ end PSR_Off;
+
+ ----------------------------------------------------------------------------
+
+ procedure GT_Mailbox_Write (MBox : Word32; Value : Word32) is
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ Registers.Wait_Unset_Mask (Registers.GT_MAILBOX, GT_MAILBOX_READY);
+ Registers.Write (Registers.GT_MAILBOX_DATA, Value);
+ Registers.Write (Registers.GT_MAILBOX, GT_MAILBOX_READY or MBox);
+
+ Registers.Wait_Unset_Mask (Registers.GT_MAILBOX, GT_MAILBOX_READY);
+ Registers.Write (Registers.GT_MAILBOX_DATA, 0);
+ end GT_Mailbox_Write;
+
+ procedure IPS_Off
+ is
+ Enabled : Boolean;
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ if Config.Has_IPS then
+ Registers.Is_Set_Mask (Registers.IPS_CTL, IPS_CTL_ENABLE, Enabled);
+ if Enabled then
+ if Config.Has_IPS_CTL_Mailbox then
+ GT_Mailbox_Write (DISPLAY_IPS_CONTROL, 0);
+ -- May take up to 42ms.
+ Registers.Wait_Unset_Mask (Registers.IPS_CTL, IPS_CTL_ENABLE);
+ else
+ Registers.Unset_Mask (Registers.IPS_CTL, IPS_CTL_ENABLE);
+ end if;
+
+ pragma Debug (Debug.Put_Line ("Disabled IPS."));
+ -- We have to wait until the next vblank here.
+ -- 20ms should be enough.
+ Time.M_Delay (20);
+ end if;
+ end if;
+ end IPS_Off;
+
+ ----------------------------------------------------------------------------
+
+ procedure PDW_Off
+ is
+ Ctl1, Ctl2, Ctl3, Ctl4 : Word32;
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ Registers.Read (Registers.PWR_WELL_CTL_BIOS, Ctl1);
+ Registers.Read (Registers.PWR_WELL_CTL_DRIVER, Ctl2);
+ Registers.Read (Registers.PWR_WELL_CTL_KVMR, Ctl3);
+ Registers.Read (Registers.PWR_WELL_CTL_DEBUG, Ctl4);
+ pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL5)); -- Result for debugging only
+ pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL6)); -- Result for debugging only
+
+ if ((Ctl1 or Ctl2 or Ctl3 or Ctl4) and
+ PWR_WELL_CTL_ENABLE_REQUEST) /= 0
+ then
+ Registers.Wait_Set_Mask
+ (Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_STATE_ENABLED);
+ end if;
+
+ if (Ctl1 and PWR_WELL_CTL_ENABLE_REQUEST) /= 0 then
+ Registers.Write (Registers.PWR_WELL_CTL_BIOS, PWR_WELL_CTL_DISABLE_REQUEST);
+ end if;
+
+ if (Ctl2 and PWR_WELL_CTL_ENABLE_REQUEST) /= 0 then
+ Registers.Write (Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_DISABLE_REQUEST);
+ end if;
+ end PDW_Off;
+
+ procedure PDW_On
+ is
+ Ctl1, Ctl2, Ctl3, Ctl4 : Word32;
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ Registers.Read (Registers.PWR_WELL_CTL_BIOS, Ctl1);
+ Registers.Read (Registers.PWR_WELL_CTL_DRIVER, Ctl2);
+ Registers.Read (Registers.PWR_WELL_CTL_KVMR, Ctl3);
+ Registers.Read (Registers.PWR_WELL_CTL_DEBUG, Ctl4);
+ pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL5)); -- Result for debugging only
+ pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL6)); -- Result for debugging only
+
+ if ((Ctl1 or Ctl2 or Ctl3 or Ctl4) and
+ PWR_WELL_CTL_ENABLE_REQUEST) = 0
+ then
+ Registers.Wait_Unset_Mask
+ (Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_STATE_ENABLED);
+ end if;
+
+ if (Ctl2 and PWR_WELL_CTL_ENABLE_REQUEST) = 0 then
+ Registers.Write (Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_ENABLE_REQUEST);
+ Registers.Wait_Set_Mask
+ (Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_STATE_ENABLED);
+ end if;
+ end PDW_On;
+
+ function Need_PDW (Checked_Configs : Configs_Type) return Boolean is
+ begin
+ return (Checked_Configs (Primary).Port /= Disabled and
+ Checked_Configs (Primary).Port /= Internal) or
+ Checked_Configs (Secondary).Port /= Disabled or
+ Checked_Configs (Tertiary).Port /= Disabled;
+ end Need_PDW;
+
+ ----------------------------------------------------------------------------
+
+ procedure Pre_All_Off is
+ begin
+ -- HSW: disable panel self refresh (PSR) on eDP if enabled
+ -- wait for PSR idling
+ PSR_Off;
+ IPS_Off;
+ end Pre_All_Off;
+
+ procedure Initialize is
+ begin
+ -- HSW: disable power down well
+ PDW_Off;
+ end Initialize;
+
+ procedure Power_Set_To (Configs : Configs_Type) is
+ begin
+ if Need_PDW (Configs) then
+ PDW_On;
+ else
+ PDW_Off;
+ end if;
+ end Power_Set_To;
+
+ procedure Power_Up (Old_Configs, New_Configs : Configs_Type) is
+ begin
+ if not Need_PDW (Old_Configs) and Need_PDW (New_Configs) then
+ PDW_On;
+ end if;
+ end Power_Up;
+
+ procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Configs_Type)
+ is
+ begin
+ if (Need_PDW (Old_Configs) or Need_PDW (Tmp_Configs)) and
+ not Need_PDW (New_Configs)
+ then
+ PDW_Off;
+ end if;
+ end Power_Down;
+
+end HW.GFX.GMA.Power_And_Clocks_Haswell;
diff --git a/common/haswell_shared/hw-gfx-gma-power_and_clocks_haswell.ads b/common/haswell_shared/hw-gfx-gma-power_and_clocks_haswell.ads
new file mode 100644
index 0000000..84cf889
--- /dev/null
+++ b/common/haswell_shared/hw-gfx-gma-power_and_clocks_haswell.ads
@@ -0,0 +1,27 @@
+--
+-- 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.
+--
+
+private package HW.GFX.GMA.Power_And_Clocks_Haswell is
+
+ procedure PSR_Off;
+
+ procedure Pre_All_Off;
+ procedure Post_All_Off is null;
+
+ procedure Initialize;
+
+ procedure Power_Set_To (Configs : Configs_Type);
+ procedure Power_Up (Old_Configs, New_Configs : Configs_Type);
+ procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Configs_Type);
+
+end HW.GFX.GMA.Power_And_Clocks_Haswell;