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/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;