| Nico Huber | 83693c8 | 2016-10-08 22:17:55 +0200 | [diff] [blame] | 1 | -- |
| 2 | -- Copyright (C) 2015-2016 secunet Security Networks AG |
| 3 | -- |
| 4 | -- This program is free software; you can redistribute it and/or modify |
| 5 | -- it under the terms of the GNU General Public License as published by |
| Nico Huber | 125a29e | 2016-10-18 00:23:54 +0200 | [diff] [blame] | 6 | -- the Free Software Foundation; either version 2 of the License, or |
| 7 | -- (at your option) any later version. |
| Nico Huber | 83693c8 | 2016-10-08 22:17:55 +0200 | [diff] [blame] | 8 | -- |
| 9 | -- This program is distributed in the hope that it will be useful, |
| 10 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | -- GNU General Public License for more details. |
| 13 | -- |
| 14 | |
| 15 | with HW.Time; |
| 16 | with HW.GFX.GMA.Config; |
| 17 | with HW.GFX.GMA.Registers; |
| 18 | |
| 19 | package body HW.GFX.GMA.PCH.FDI is |
| 20 | |
| 21 | FDI_RX_CTL_FDI_RX_ENABLE : constant := 1 * 2 ** 31; |
| 22 | FDI_RX_CTL_FS_ERROR_CORRECTION_ENABLE : constant := 1 * 2 ** 27; |
| 23 | FDI_RX_CTL_FE_ERROR_CORRECTION_ENABLE : constant := 1 * 2 ** 26; |
| 24 | FDI_RX_CTL_PORT_WIDTH_SEL_SHIFT : constant := 19; |
| 25 | FDI_RX_CTL_FDI_PLL_ENABLE : constant := 1 * 2 ** 13; |
| 26 | FDI_RX_CTL_COMPOSITE_SYNC_SELECT : constant := 1 * 2 ** 11; |
| 27 | FDI_RX_CTL_FDI_AUTO_TRAIN : constant := 1 * 2 ** 10; |
| 28 | FDI_RX_CTL_ENHANCED_FRAMING_ENABLE : constant := 1 * 2 ** 6; |
| 29 | FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_MASK : constant := 1 * 2 ** 4; |
| 30 | FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_RAWCLK : constant := 0 * 2 ** 4; |
| 31 | FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_PCDCLK : constant := 1 * 2 ** 4; |
| 32 | |
| Nico Huber | 63dc919 | 2018-06-09 17:42:19 +0200 | [diff] [blame] | 33 | function TP_SHIFT return Natural is |
| 34 | (if Config.Has_New_FDI_Sink then 8 else 28); |
| Nico Huber | 83693c8 | 2016-10-08 22:17:55 +0200 | [diff] [blame] | 35 | |
| Nico Huber | 63dc919 | 2018-06-09 17:42:19 +0200 | [diff] [blame] | 36 | function FDI_RX_CTL_TRAINING_PATTERN_MASK |
| 37 | return Word32 is (Shift_Left (3, TP_SHIFT)); |
| 38 | |
| 39 | function FDI_RX_CTL_TRAINING_PATTERN (TP : Training_Pattern) return Word32 is |
| 40 | (case TP is |
| 41 | when TP_1 => Shift_Left (0, TP_SHIFT), |
| 42 | when TP_2 => Shift_Left (1, TP_SHIFT), |
| 43 | when TP_Idle => Shift_Left (2, TP_SHIFT), |
| 44 | when TP_None => Shift_Left (3, TP_SHIFT)); |
| Nico Huber | 83693c8 | 2016-10-08 22:17:55 +0200 | [diff] [blame] | 45 | |
| 46 | function FDI_RX_CTL_PORT_WIDTH_SEL (Lane_Count : DP_Lane_Count) return Word32 |
| 47 | is |
| 48 | begin |
| 49 | return Shift_Left |
| 50 | (Word32 (Lane_Count_As_Integer (Lane_Count)) - 1, |
| 51 | FDI_RX_CTL_PORT_WIDTH_SEL_SHIFT); |
| 52 | end FDI_RX_CTL_PORT_WIDTH_SEL; |
| 53 | |
| 54 | function FDI_RX_CTL_BPC (BPC : BPC_Type) return Word32 |
| 55 | with Pre => True |
| 56 | is |
| 57 | begin |
| 58 | return |
| 59 | (case BPC is |
| 60 | when 6 => 2 * 2 ** 16, |
| 61 | when 10 => 1 * 2 ** 16, |
| 62 | when 12 => 3 * 2 ** 16, |
| 63 | when others => 0 * 2 ** 16); |
| 64 | end FDI_RX_CTL_BPC; |
| 65 | |
| 66 | FDI_RX_MISC_FDI_RX_PWRDN_LANE1_SHIFT : constant := 26; |
| 67 | FDI_RX_MISC_FDI_RX_PWRDN_LANE1_MASK : constant := 3 * 2 ** 26; |
| 68 | FDI_RX_MISC_FDI_RX_PWRDN_LANE0_SHIFT : constant := 24; |
| 69 | FDI_RX_MISC_FDI_RX_PWRDN_LANE0_MASK : constant := 3 * 2 ** 24; |
| 70 | FDI_RX_MISC_TP1_TO_TP2_TIME_48 : constant := 2 * 2 ** 20; |
| 71 | FDI_RX_MISC_FDI_DELAY_90 : constant := 16#90# * 2 ** 0; |
| 72 | |
| 73 | function FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (Value : Word32) return Word32 |
| 74 | with Pre => True |
| 75 | is |
| 76 | begin |
| 77 | return Shift_Left (Value, FDI_RX_MISC_FDI_RX_PWRDN_LANE1_SHIFT); |
| 78 | end FDI_RX_MISC_FDI_RX_PWRDN_LANE1; |
| 79 | |
| 80 | function FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (Value : Word32) return Word32 |
| 81 | with Pre => True |
| 82 | is |
| 83 | begin |
| 84 | return Shift_Left (Value, FDI_RX_MISC_FDI_RX_PWRDN_LANE0_SHIFT); |
| 85 | end FDI_RX_MISC_FDI_RX_PWRDN_LANE0; |
| 86 | |
| 87 | FDI_RX_TUSIZE_SHIFT : constant := 25; |
| 88 | |
| 89 | function FDI_RX_TUSIZE (Value : Word32) return Word32 is |
| 90 | begin |
| 91 | return Shift_Left (Value - 1, FDI_RX_TUSIZE_SHIFT); |
| 92 | end FDI_RX_TUSIZE; |
| 93 | |
| 94 | FDI_RX_INTERLANE_ALIGNMENT : constant := 1 * 2 ** 10; |
| 95 | FDI_RX_SYMBOL_LOCK : constant := 1 * 2 ** 9; |
| 96 | FDI_RX_BIT_LOCK : constant := 1 * 2 ** 8; |
| 97 | |
| 98 | ---------------------------------------------------------------------------- |
| 99 | |
| 100 | type FDI_Registers is record |
| 101 | RX_CTL : Registers.Registers_Index; |
| 102 | RX_MISC : Registers.Registers_Index; |
| 103 | RX_TUSIZE : Registers.Registers_Index; |
| 104 | RX_IMR : Registers.Registers_Index; |
| 105 | RX_IIR : Registers.Registers_Index; |
| 106 | end record; |
| 107 | type FDI_Registers_Array is array (PCH.FDI_Port_Type) of FDI_Registers; |
| 108 | FDI_Regs : constant FDI_Registers_Array := FDI_Registers_Array' |
| 109 | (PCH.FDI_A => FDI_Registers' |
| 110 | (RX_CTL => Registers.FDI_RXA_CTL, |
| 111 | RX_MISC => Registers.FDI_RX_MISC_A, |
| 112 | RX_TUSIZE => Registers.FDI_RXA_TUSIZE1, |
| 113 | RX_IMR => Registers.FDI_RXA_IMR, |
| 114 | RX_IIR => Registers.FDI_RXA_IIR), |
| 115 | PCH.FDI_B => FDI_Registers' |
| 116 | (RX_CTL => Registers.FDI_RXB_CTL, |
| 117 | RX_MISC => Registers.FDI_RX_MISC_B, |
| 118 | RX_TUSIZE => Registers.FDI_RXB_TUSIZE1, |
| 119 | RX_IMR => Registers.FDI_RXB_IMR, |
| 120 | RX_IIR => Registers.FDI_RXB_IIR), |
| 121 | PCH.FDI_C => FDI_Registers' |
| 122 | (RX_CTL => Registers.FDI_RXC_CTL, |
| 123 | RX_MISC => Registers.FDI_RX_MISC_C, |
| 124 | RX_TUSIZE => Registers.FDI_RXC_TUSIZE1, |
| 125 | RX_IMR => Registers.FDI_RXC_IMR, |
| 126 | RX_IIR => Registers.FDI_RXC_IIR)); |
| 127 | |
| 128 | ---------------------------------------------------------------------------- |
| 129 | |
| 130 | procedure Pre_Train (Port : PCH.FDI_Port_Type; Port_Cfg : Port_Config) |
| 131 | is |
| 132 | Power_Down_Lane_Bits : constant Word32 := |
| 133 | (if Config.Has_FDI_RX_Power_Down then |
| 134 | FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (2) or |
| 135 | FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (2) |
| 136 | else 0); |
| 137 | RX_CTL_Settings : constant Word32 := |
| 138 | FDI_RX_CTL_PORT_WIDTH_SEL (Port_Cfg.FDI.Lane_Count) or |
| 139 | (if Config.Has_FDI_BPC then |
| 140 | FDI_RX_CTL_BPC (Port_Cfg.Mode.BPC) else 0) or |
| 141 | (if Config.Has_FDI_Composite_Sel then |
| 142 | FDI_RX_CTL_COMPOSITE_SYNC_SELECT else 0) or |
| 143 | (if Port_Cfg.FDI.Enhanced_Framing then |
| 144 | FDI_RX_CTL_ENHANCED_FRAMING_ENABLE else 0); |
| 145 | begin |
| 146 | -- TODO: HSW: check DISPIO_CR_TX_BMU_CR4, seems Linux doesn't know it |
| 147 | |
| 148 | Registers.Write |
| 149 | (Register => FDI_Regs (Port).RX_MISC, |
| 150 | Value => Power_Down_Lane_Bits or |
| 151 | FDI_RX_MISC_TP1_TO_TP2_TIME_48 or |
| 152 | FDI_RX_MISC_FDI_DELAY_90); |
| 153 | |
| 154 | Registers.Write |
| 155 | (Register => FDI_Regs (Port).RX_TUSIZE, |
| 156 | Value => FDI_RX_TUSIZE (64)); |
| 157 | |
| 158 | Registers.Unset_Mask |
| 159 | (Register => FDI_Regs (Port).RX_IMR, |
| 160 | Mask => FDI_RX_INTERLANE_ALIGNMENT or |
| 161 | FDI_RX_SYMBOL_LOCK or |
| 162 | FDI_RX_BIT_LOCK); |
| 163 | Registers.Posting_Read (FDI_Regs (Port).RX_IMR); |
| 164 | -- clear stale lock bits |
| 165 | Registers.Write |
| 166 | (Register => FDI_Regs (Port).RX_IIR, |
| 167 | Value => FDI_RX_INTERLANE_ALIGNMENT or |
| 168 | FDI_RX_SYMBOL_LOCK or |
| 169 | FDI_RX_BIT_LOCK); |
| 170 | |
| 171 | Registers.Write |
| 172 | (Register => FDI_Regs (Port).RX_CTL, |
| 173 | Value => FDI_RX_CTL_FDI_PLL_ENABLE or |
| 174 | RX_CTL_Settings); |
| 175 | Registers.Posting_Read (FDI_Regs (Port).RX_CTL); |
| 176 | Time.U_Delay (220); |
| 177 | |
| 178 | Registers.Set_Mask |
| 179 | (Register => FDI_Regs (Port).RX_CTL, |
| 180 | Mask => FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_PCDCLK); |
| 181 | end Pre_Train; |
| 182 | |
| 183 | procedure Train |
| 184 | (Port : in PCH.FDI_Port_Type; |
| 185 | TP : in Training_Pattern; |
| 186 | Success : out Boolean) |
| 187 | is |
| 188 | Lock_Bit : constant Word32 := |
| 189 | (if TP = TP_1 then FDI_RX_BIT_LOCK else FDI_RX_SYMBOL_LOCK); |
| 190 | |
| 191 | procedure Check_Lock (Lock_Bit : Word32) |
| 192 | is |
| 193 | begin |
| 194 | for I in 1 .. 5 loop |
| 195 | Registers.Is_Set_Mask |
| 196 | (Register => FDI_Regs (Port).RX_IIR, |
| 197 | Mask => Lock_Bit, |
| 198 | Result => Success); |
| 199 | if Success then |
| 200 | -- clear the lock bit |
| 201 | Registers.Write |
| 202 | (Register => FDI_Regs (Port).RX_IIR, |
| 203 | Value => Lock_Bit); |
| 204 | end if; |
| 205 | exit when Success; |
| 206 | Time.U_Delay (1); |
| 207 | end loop; |
| 208 | end Check_Lock; |
| 209 | begin |
| 210 | Registers.Unset_And_Set_Mask |
| 211 | (Register => FDI_Regs (Port).RX_CTL, |
| 212 | Mask_Unset => FDI_RX_CTL_TRAINING_PATTERN_MASK, |
| 213 | Mask_Set => FDI_RX_CTL_FDI_RX_ENABLE or |
| 214 | FDI_RX_CTL_TRAINING_PATTERN (TP)); |
| 215 | Registers.Posting_Read (FDI_Regs (Port).RX_CTL); |
| 216 | |
| 217 | if TP <= TP_2 then |
| 218 | Time.U_Delay (1); |
| 219 | if TP = TP_1 then |
| 220 | Check_Lock (FDI_RX_BIT_LOCK); |
| 221 | else |
| 222 | Check_Lock (FDI_RX_SYMBOL_LOCK); |
| 223 | if Success then |
| 224 | Check_Lock (FDI_RX_INTERLANE_ALIGNMENT); |
| 225 | end if; |
| 226 | end if; |
| 227 | else |
| 228 | Time.U_Delay (31); |
| 229 | Success := True; |
| 230 | end if; |
| 231 | end Train; |
| 232 | |
| 233 | procedure Auto_Train (Port : PCH.FDI_Port_Type) |
| 234 | is |
| 235 | begin |
| 236 | Registers.Set_Mask |
| 237 | (Register => FDI_Regs (Port).RX_CTL, |
| 238 | Mask => FDI_RX_CTL_FDI_RX_ENABLE or |
| 239 | FDI_RX_CTL_FDI_AUTO_TRAIN); |
| 240 | Registers.Posting_Read (FDI_Regs (Port).RX_CTL); |
| 241 | |
| 242 | if Config.Has_FDI_RX_Power_Down then |
| 243 | Time.U_Delay (30); |
| 244 | Registers.Unset_And_Set_Mask |
| 245 | (Register => FDI_Regs (Port).RX_MISC, |
| 246 | Mask_Unset => FDI_RX_MISC_FDI_RX_PWRDN_LANE1_MASK or |
| 247 | FDI_RX_MISC_FDI_RX_PWRDN_LANE0_MASK, |
| 248 | Mask_Set => FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (0) or |
| 249 | FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (0)); |
| 250 | Registers.Posting_Read (FDI_Regs (Port).RX_MISC); |
| 251 | end if; |
| 252 | |
| 253 | Time.U_Delay (5); |
| 254 | end Auto_Train; |
| 255 | |
| 256 | procedure Enable_EC (Port : PCH.FDI_Port_Type) |
| 257 | is |
| 258 | begin |
| 259 | Registers.Set_Mask |
| 260 | (Register => FDI_Regs (Port).RX_CTL, |
| 261 | Mask => FDI_RX_CTL_FS_ERROR_CORRECTION_ENABLE or |
| 262 | FDI_RX_CTL_FE_ERROR_CORRECTION_ENABLE); |
| 263 | end Enable_EC; |
| 264 | |
| 265 | ---------------------------------------------------------------------------- |
| 266 | |
| 267 | procedure Off (Port : PCH.FDI_Port_Type; OT : Off_Type) |
| 268 | is |
| 269 | begin |
| 270 | Registers.Unset_Mask |
| 271 | (Register => FDI_Regs (Port).RX_CTL, |
| 272 | Mask => FDI_RX_CTL_FDI_RX_ENABLE or |
| 273 | FDI_RX_CTL_FDI_AUTO_TRAIN); |
| 274 | |
| 275 | if Config.Has_FDI_RX_Power_Down and then OT >= Lanes_Off then |
| 276 | Registers.Unset_And_Set_Mask |
| 277 | (Register => FDI_Regs (Port).RX_MISC, |
| 278 | Mask_Unset => FDI_RX_MISC_FDI_RX_PWRDN_LANE1_MASK or |
| 279 | FDI_RX_MISC_FDI_RX_PWRDN_LANE0_MASK, |
| 280 | Mask_Set => FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (2) or |
| 281 | FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (2)); |
| 282 | Registers.Posting_Read (FDI_Regs (Port).RX_MISC); |
| 283 | end if; |
| 284 | |
| 285 | if OT >= Clock_Off then |
| 286 | Registers.Unset_And_Set_Mask |
| 287 | (Register => FDI_Regs (Port).RX_CTL, |
| 288 | Mask_Unset => FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_MASK, |
| 289 | Mask_Set => FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_RAWCLK); |
| 290 | |
| 291 | Registers.Unset_Mask |
| 292 | (Register => FDI_Regs (Port).RX_CTL, |
| 293 | Mask => FDI_RX_CTL_FDI_PLL_ENABLE); |
| 294 | end if; |
| 295 | end Off; |
| 296 | |
| 297 | end HW.GFX.GMA.PCH.FDI; |