blob: 95bc19fc4f54816eac8cd35bdcd0dd09a0858a84 [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
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 Huber125a29e2016-10-18 00:23:54 +02006-- the Free Software Foundation; either version 2 of the License, or
7-- (at your option) any later version.
Nico Huber83693c82016-10-08 22:17:55 +02008--
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
15with HW.Time;
16with HW.GFX.GMA.Config;
17with HW.GFX.GMA.Registers;
18
19package 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
294end HW.GFX.GMA.PCH.FDI;