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