555 lines
20 KiB
Ada
555 lines
20 KiB
Ada
--
|
|
-- 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;
|