298 lines
11 KiB
Ada
298 lines
11 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; 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.Registers;
|
||
|
|
||
|
package body HW.GFX.GMA.PCH.FDI is
|
||
|
|
||
|
FDI_RX_CTL_FDI_RX_ENABLE : constant := 1 * 2 ** 31;
|
||
|
FDI_RX_CTL_FS_ERROR_CORRECTION_ENABLE : constant := 1 * 2 ** 27;
|
||
|
FDI_RX_CTL_FE_ERROR_CORRECTION_ENABLE : constant := 1 * 2 ** 26;
|
||
|
FDI_RX_CTL_PORT_WIDTH_SEL_SHIFT : constant := 19;
|
||
|
FDI_RX_CTL_FDI_PLL_ENABLE : constant := 1 * 2 ** 13;
|
||
|
FDI_RX_CTL_COMPOSITE_SYNC_SELECT : constant := 1 * 2 ** 11;
|
||
|
FDI_RX_CTL_FDI_AUTO_TRAIN : constant := 1 * 2 ** 10;
|
||
|
FDI_RX_CTL_ENHANCED_FRAMING_ENABLE : constant := 1 * 2 ** 6;
|
||
|
FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_MASK : constant := 1 * 2 ** 4;
|
||
|
FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_RAWCLK : constant := 0 * 2 ** 4;
|
||
|
FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_PCDCLK : constant := 1 * 2 ** 4;
|
||
|
|
||
|
function TP_SHIFT return Natural is
|
||
|
(if Config.Has_New_FDI_Sink then 8 else 28);
|
||
|
|
||
|
function FDI_RX_CTL_TRAINING_PATTERN_MASK
|
||
|
return Word32 is (Shift_Left (3, TP_SHIFT));
|
||
|
|
||
|
function FDI_RX_CTL_TRAINING_PATTERN (TP : Training_Pattern) return Word32 is
|
||
|
(case TP is
|
||
|
when TP_1 => Shift_Left (0, TP_SHIFT),
|
||
|
when TP_2 => Shift_Left (1, TP_SHIFT),
|
||
|
when TP_Idle => Shift_Left (2, TP_SHIFT),
|
||
|
when TP_None => Shift_Left (3, TP_SHIFT));
|
||
|
|
||
|
function FDI_RX_CTL_PORT_WIDTH_SEL (Lane_Count : DP_Lane_Count) return Word32
|
||
|
is
|
||
|
begin
|
||
|
return Shift_Left
|
||
|
(Word32 (Lane_Count_As_Integer (Lane_Count)) - 1,
|
||
|
FDI_RX_CTL_PORT_WIDTH_SEL_SHIFT);
|
||
|
end FDI_RX_CTL_PORT_WIDTH_SEL;
|
||
|
|
||
|
function FDI_RX_CTL_BPC (BPC : BPC_Type) return Word32
|
||
|
with Pre => True
|
||
|
is
|
||
|
begin
|
||
|
return
|
||
|
(case BPC is
|
||
|
when 6 => 2 * 2 ** 16,
|
||
|
when 10 => 1 * 2 ** 16,
|
||
|
when 12 => 3 * 2 ** 16,
|
||
|
when others => 0 * 2 ** 16);
|
||
|
end FDI_RX_CTL_BPC;
|
||
|
|
||
|
FDI_RX_MISC_FDI_RX_PWRDN_LANE1_SHIFT : constant := 26;
|
||
|
FDI_RX_MISC_FDI_RX_PWRDN_LANE1_MASK : constant := 3 * 2 ** 26;
|
||
|
FDI_RX_MISC_FDI_RX_PWRDN_LANE0_SHIFT : constant := 24;
|
||
|
FDI_RX_MISC_FDI_RX_PWRDN_LANE0_MASK : constant := 3 * 2 ** 24;
|
||
|
FDI_RX_MISC_TP1_TO_TP2_TIME_48 : constant := 2 * 2 ** 20;
|
||
|
FDI_RX_MISC_FDI_DELAY_90 : constant := 16#90# * 2 ** 0;
|
||
|
|
||
|
function FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (Value : Word32) return Word32
|
||
|
with Pre => True
|
||
|
is
|
||
|
begin
|
||
|
return Shift_Left (Value, FDI_RX_MISC_FDI_RX_PWRDN_LANE1_SHIFT);
|
||
|
end FDI_RX_MISC_FDI_RX_PWRDN_LANE1;
|
||
|
|
||
|
function FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (Value : Word32) return Word32
|
||
|
with Pre => True
|
||
|
is
|
||
|
begin
|
||
|
return Shift_Left (Value, FDI_RX_MISC_FDI_RX_PWRDN_LANE0_SHIFT);
|
||
|
end FDI_RX_MISC_FDI_RX_PWRDN_LANE0;
|
||
|
|
||
|
FDI_RX_TUSIZE_SHIFT : constant := 25;
|
||
|
|
||
|
function FDI_RX_TUSIZE (Value : Word32) return Word32 is
|
||
|
begin
|
||
|
return Shift_Left (Value - 1, FDI_RX_TUSIZE_SHIFT);
|
||
|
end FDI_RX_TUSIZE;
|
||
|
|
||
|
FDI_RX_INTERLANE_ALIGNMENT : constant := 1 * 2 ** 10;
|
||
|
FDI_RX_SYMBOL_LOCK : constant := 1 * 2 ** 9;
|
||
|
FDI_RX_BIT_LOCK : constant := 1 * 2 ** 8;
|
||
|
|
||
|
----------------------------------------------------------------------------
|
||
|
|
||
|
type FDI_Registers is record
|
||
|
RX_CTL : Registers.Registers_Index;
|
||
|
RX_MISC : Registers.Registers_Index;
|
||
|
RX_TUSIZE : Registers.Registers_Index;
|
||
|
RX_IMR : Registers.Registers_Index;
|
||
|
RX_IIR : Registers.Registers_Index;
|
||
|
end record;
|
||
|
type FDI_Registers_Array is array (PCH.FDI_Port_Type) of FDI_Registers;
|
||
|
FDI_Regs : constant FDI_Registers_Array := FDI_Registers_Array'
|
||
|
(PCH.FDI_A => FDI_Registers'
|
||
|
(RX_CTL => Registers.FDI_RXA_CTL,
|
||
|
RX_MISC => Registers.FDI_RX_MISC_A,
|
||
|
RX_TUSIZE => Registers.FDI_RXA_TUSIZE1,
|
||
|
RX_IMR => Registers.FDI_RXA_IMR,
|
||
|
RX_IIR => Registers.FDI_RXA_IIR),
|
||
|
PCH.FDI_B => FDI_Registers'
|
||
|
(RX_CTL => Registers.FDI_RXB_CTL,
|
||
|
RX_MISC => Registers.FDI_RX_MISC_B,
|
||
|
RX_TUSIZE => Registers.FDI_RXB_TUSIZE1,
|
||
|
RX_IMR => Registers.FDI_RXB_IMR,
|
||
|
RX_IIR => Registers.FDI_RXB_IIR),
|
||
|
PCH.FDI_C => FDI_Registers'
|
||
|
(RX_CTL => Registers.FDI_RXC_CTL,
|
||
|
RX_MISC => Registers.FDI_RX_MISC_C,
|
||
|
RX_TUSIZE => Registers.FDI_RXC_TUSIZE1,
|
||
|
RX_IMR => Registers.FDI_RXC_IMR,
|
||
|
RX_IIR => Registers.FDI_RXC_IIR));
|
||
|
|
||
|
----------------------------------------------------------------------------
|
||
|
|
||
|
procedure Pre_Train (Port : PCH.FDI_Port_Type; Port_Cfg : Port_Config)
|
||
|
is
|
||
|
Power_Down_Lane_Bits : constant Word32 :=
|
||
|
(if Config.Has_FDI_RX_Power_Down then
|
||
|
FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (2) or
|
||
|
FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (2)
|
||
|
else 0);
|
||
|
RX_CTL_Settings : constant Word32 :=
|
||
|
FDI_RX_CTL_PORT_WIDTH_SEL (Port_Cfg.FDI.Lane_Count) or
|
||
|
(if Config.Has_FDI_BPC then
|
||
|
FDI_RX_CTL_BPC (Port_Cfg.Mode.BPC) else 0) or
|
||
|
(if Config.Has_FDI_Composite_Sel then
|
||
|
FDI_RX_CTL_COMPOSITE_SYNC_SELECT else 0) or
|
||
|
(if Port_Cfg.FDI.Enhanced_Framing then
|
||
|
FDI_RX_CTL_ENHANCED_FRAMING_ENABLE else 0);
|
||
|
begin
|
||
|
-- TODO: HSW: check DISPIO_CR_TX_BMU_CR4, seems Linux doesn't know it
|
||
|
|
||
|
Registers.Write
|
||
|
(Register => FDI_Regs (Port).RX_MISC,
|
||
|
Value => Power_Down_Lane_Bits or
|
||
|
FDI_RX_MISC_TP1_TO_TP2_TIME_48 or
|
||
|
FDI_RX_MISC_FDI_DELAY_90);
|
||
|
|
||
|
Registers.Write
|
||
|
(Register => FDI_Regs (Port).RX_TUSIZE,
|
||
|
Value => FDI_RX_TUSIZE (64));
|
||
|
|
||
|
Registers.Unset_Mask
|
||
|
(Register => FDI_Regs (Port).RX_IMR,
|
||
|
Mask => FDI_RX_INTERLANE_ALIGNMENT or
|
||
|
FDI_RX_SYMBOL_LOCK or
|
||
|
FDI_RX_BIT_LOCK);
|
||
|
Registers.Posting_Read (FDI_Regs (Port).RX_IMR);
|
||
|
-- clear stale lock bits
|
||
|
Registers.Write
|
||
|
(Register => FDI_Regs (Port).RX_IIR,
|
||
|
Value => FDI_RX_INTERLANE_ALIGNMENT or
|
||
|
FDI_RX_SYMBOL_LOCK or
|
||
|
FDI_RX_BIT_LOCK);
|
||
|
|
||
|
Registers.Write
|
||
|
(Register => FDI_Regs (Port).RX_CTL,
|
||
|
Value => FDI_RX_CTL_FDI_PLL_ENABLE or
|
||
|
RX_CTL_Settings);
|
||
|
Registers.Posting_Read (FDI_Regs (Port).RX_CTL);
|
||
|
Time.U_Delay (220);
|
||
|
|
||
|
Registers.Set_Mask
|
||
|
(Register => FDI_Regs (Port).RX_CTL,
|
||
|
Mask => FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_PCDCLK);
|
||
|
end Pre_Train;
|
||
|
|
||
|
procedure Train
|
||
|
(Port : in PCH.FDI_Port_Type;
|
||
|
TP : in Training_Pattern;
|
||
|
Success : out Boolean)
|
||
|
is
|
||
|
Lock_Bit : constant Word32 :=
|
||
|
(if TP = TP_1 then FDI_RX_BIT_LOCK else FDI_RX_SYMBOL_LOCK);
|
||
|
|
||
|
procedure Check_Lock (Lock_Bit : Word32)
|
||
|
is
|
||
|
begin
|
||
|
for I in 1 .. 5 loop
|
||
|
Registers.Is_Set_Mask
|
||
|
(Register => FDI_Regs (Port).RX_IIR,
|
||
|
Mask => Lock_Bit,
|
||
|
Result => Success);
|
||
|
if Success then
|
||
|
-- clear the lock bit
|
||
|
Registers.Write
|
||
|
(Register => FDI_Regs (Port).RX_IIR,
|
||
|
Value => Lock_Bit);
|
||
|
end if;
|
||
|
exit when Success;
|
||
|
Time.U_Delay (1);
|
||
|
end loop;
|
||
|
end Check_Lock;
|
||
|
begin
|
||
|
Registers.Unset_And_Set_Mask
|
||
|
(Register => FDI_Regs (Port).RX_CTL,
|
||
|
Mask_Unset => FDI_RX_CTL_TRAINING_PATTERN_MASK,
|
||
|
Mask_Set => FDI_RX_CTL_FDI_RX_ENABLE or
|
||
|
FDI_RX_CTL_TRAINING_PATTERN (TP));
|
||
|
Registers.Posting_Read (FDI_Regs (Port).RX_CTL);
|
||
|
|
||
|
if TP <= TP_2 then
|
||
|
Time.U_Delay (1);
|
||
|
if TP = TP_1 then
|
||
|
Check_Lock (FDI_RX_BIT_LOCK);
|
||
|
else
|
||
|
Check_Lock (FDI_RX_SYMBOL_LOCK);
|
||
|
if Success then
|
||
|
Check_Lock (FDI_RX_INTERLANE_ALIGNMENT);
|
||
|
end if;
|
||
|
end if;
|
||
|
else
|
||
|
Time.U_Delay (31);
|
||
|
Success := True;
|
||
|
end if;
|
||
|
end Train;
|
||
|
|
||
|
procedure Auto_Train (Port : PCH.FDI_Port_Type)
|
||
|
is
|
||
|
begin
|
||
|
Registers.Set_Mask
|
||
|
(Register => FDI_Regs (Port).RX_CTL,
|
||
|
Mask => FDI_RX_CTL_FDI_RX_ENABLE or
|
||
|
FDI_RX_CTL_FDI_AUTO_TRAIN);
|
||
|
Registers.Posting_Read (FDI_Regs (Port).RX_CTL);
|
||
|
|
||
|
if Config.Has_FDI_RX_Power_Down then
|
||
|
Time.U_Delay (30);
|
||
|
Registers.Unset_And_Set_Mask
|
||
|
(Register => FDI_Regs (Port).RX_MISC,
|
||
|
Mask_Unset => FDI_RX_MISC_FDI_RX_PWRDN_LANE1_MASK or
|
||
|
FDI_RX_MISC_FDI_RX_PWRDN_LANE0_MASK,
|
||
|
Mask_Set => FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (0) or
|
||
|
FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (0));
|
||
|
Registers.Posting_Read (FDI_Regs (Port).RX_MISC);
|
||
|
end if;
|
||
|
|
||
|
Time.U_Delay (5);
|
||
|
end Auto_Train;
|
||
|
|
||
|
procedure Enable_EC (Port : PCH.FDI_Port_Type)
|
||
|
is
|
||
|
begin
|
||
|
Registers.Set_Mask
|
||
|
(Register => FDI_Regs (Port).RX_CTL,
|
||
|
Mask => FDI_RX_CTL_FS_ERROR_CORRECTION_ENABLE or
|
||
|
FDI_RX_CTL_FE_ERROR_CORRECTION_ENABLE);
|
||
|
end Enable_EC;
|
||
|
|
||
|
----------------------------------------------------------------------------
|
||
|
|
||
|
procedure Off (Port : PCH.FDI_Port_Type; OT : Off_Type)
|
||
|
is
|
||
|
begin
|
||
|
Registers.Unset_Mask
|
||
|
(Register => FDI_Regs (Port).RX_CTL,
|
||
|
Mask => FDI_RX_CTL_FDI_RX_ENABLE or
|
||
|
FDI_RX_CTL_FDI_AUTO_TRAIN);
|
||
|
|
||
|
if Config.Has_FDI_RX_Power_Down and then OT >= Lanes_Off then
|
||
|
Registers.Unset_And_Set_Mask
|
||
|
(Register => FDI_Regs (Port).RX_MISC,
|
||
|
Mask_Unset => FDI_RX_MISC_FDI_RX_PWRDN_LANE1_MASK or
|
||
|
FDI_RX_MISC_FDI_RX_PWRDN_LANE0_MASK,
|
||
|
Mask_Set => FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (2) or
|
||
|
FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (2));
|
||
|
Registers.Posting_Read (FDI_Regs (Port).RX_MISC);
|
||
|
end if;
|
||
|
|
||
|
if OT >= Clock_Off then
|
||
|
Registers.Unset_And_Set_Mask
|
||
|
(Register => FDI_Regs (Port).RX_CTL,
|
||
|
Mask_Unset => FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_MASK,
|
||
|
Mask_Set => FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_RAWCLK);
|
||
|
|
||
|
Registers.Unset_Mask
|
||
|
(Register => FDI_Regs (Port).RX_CTL,
|
||
|
Mask => FDI_RX_CTL_FDI_PLL_ENABLE);
|
||
|
end if;
|
||
|
end Off;
|
||
|
|
||
|
end HW.GFX.GMA.PCH.FDI;
|