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