blob: 091f36db96d240f5f56fdb349a5e81d7698fd328 [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
Nico Huber01b680f2017-06-09 16:24:22 +02002-- Copyright (C) 2015-2017 secunet Security Networks AG
Nico Huber83693c82016-10-08 22:17:55 +02003--
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.DP_Training;
17with HW.GFX.GMA.Config;
18with HW.GFX.GMA.PCH.FDI;
19with HW.GFX.GMA.PCH.Transcoder;
20with HW.GFX.GMA.PCH.VGA;
21with HW.GFX.GMA.DP_Info;
22with HW.GFX.GMA.DP_Aux_Ch;
23with HW.GFX.GMA.SPLL;
Nico Huber1c3b9282017-02-09 13:57:04 +010024with HW.GFX.GMA.DDI_Phy;
Nico Huber01b680f2017-06-09 16:24:22 +020025with HW.GFX.GMA.Connectors.DDI.Buffers;
Nico Huber83693c82016-10-08 22:17:55 +020026
27with HW.Debug;
28with GNAT.Source_Info;
29
30package body HW.GFX.GMA.Connectors.DDI is
31
32 DDI_BUF_CTL_BUFFER_ENABLE : constant := 1 * 2 ** 31;
33 DDI_BUF_CTL_TRANS_SELECT_MASK : constant := 15 * 2 ** 24;
34 DDI_BUF_CTL_PORT_REVERSAL : constant := 1 * 2 ** 16;
35 DDI_BUF_CTL_IDLE_STATUS : constant := 1 * 2 ** 7;
36 DDI_BUF_CTL_DDI_A_LANE_CAP : constant := 1 * 2 ** 4;
37 DDI_BUF_CTL_PORT_WIDTH_MASK : constant := 7 * 2 ** 1;
38 DDI_BUF_CTL_PORT_WIDTH_1_LANE : constant := 0 * 2 ** 1;
39 DDI_BUF_CTL_PORT_WIDTH_2_LANES : constant := 1 * 2 ** 1;
40 DDI_BUF_CTL_PORT_WIDTH_4_LANES : constant := 3 * 2 ** 1;
41 DDI_BUF_CTL_INIT_DISPLAY_DETECT : constant := 1 * 2 ** 0;
42
43 subtype DDI_BUF_CTL_TRANS_SELECT_T is Natural range 0 .. 9;
44 function DDI_BUF_CTL_TRANS_SELECT
45 (Sel : DDI_BUF_CTL_TRANS_SELECT_T)
46 return Word32;
47
48 type DDI_BUF_CTL_PORT_WIDTH_T is array (HW.GFX.DP_Lane_Count) of Word32;
49 DDI_BUF_CTL_PORT_WIDTH : constant DDI_BUF_CTL_PORT_WIDTH_T :=
50 DDI_BUF_CTL_PORT_WIDTH_T'
51 (HW.GFX.DP_Lane_Count_1 => DDI_BUF_CTL_PORT_WIDTH_1_LANE,
52 HW.GFX.DP_Lane_Count_2 => DDI_BUF_CTL_PORT_WIDTH_2_LANES,
53 HW.GFX.DP_Lane_Count_4 => DDI_BUF_CTL_PORT_WIDTH_4_LANES);
54
55 DP_TP_CTL_TRANSPORT_ENABLE : constant := 1 * 2 ** 31;
56 DP_TP_CTL_MODE_SST : constant := 0 * 2 ** 27;
57 DP_TP_CTL_MODE_MST : constant := 1 * 2 ** 27;
58 DP_TP_CTL_FORCE_ACT : constant := 1 * 2 ** 25;
59 DP_TP_CTL_ENHANCED_FRAME_ENABLE : constant := 1 * 2 ** 18;
60 DP_TP_CTL_FDI_AUTOTRAIN : constant := 1 * 2 ** 15;
61 DP_TP_CTL_LINK_TRAIN_MASK : constant := 7 * 2 ** 8;
62 DP_TP_CTL_LINK_TRAIN_PAT1 : constant := 0 * 2 ** 8;
63 DP_TP_CTL_LINK_TRAIN_PAT2 : constant := 1 * 2 ** 8;
64 DP_TP_CTL_LINK_TRAIN_PAT3 : constant := 4 * 2 ** 8;
65 DP_TP_CTL_LINK_TRAIN_IDLE : constant := 2 * 2 ** 8;
66 DP_TP_CTL_LINK_TRAIN_NORMAL : constant := 3 * 2 ** 8;
67 DP_TP_CTL_SCRAMBLE_DISABLE : constant := 1 * 2 ** 7;
68 DP_TP_CTL_ALT_SCRAMBLER_RESET : constant := 1 * 2 ** 6;
69
70 type DP_TP_CTL_LINK_TRAIN_Array is
71 array (DP_Info.Training_Pattern) of Word32;
72 DP_TP_CTL_LINK_TRAIN : constant DP_TP_CTL_LINK_TRAIN_Array :=
73 DP_TP_CTL_LINK_TRAIN_Array'
74 (DP_Info.TP_1 => DP_TP_CTL_LINK_TRAIN_PAT1 or DP_TP_CTL_SCRAMBLE_DISABLE,
75 DP_Info.TP_2 => DP_TP_CTL_LINK_TRAIN_PAT2 or DP_TP_CTL_SCRAMBLE_DISABLE,
76 DP_Info.TP_3 => DP_TP_CTL_LINK_TRAIN_PAT3 or DP_TP_CTL_SCRAMBLE_DISABLE,
77 DP_Info.TP_Idle => DP_TP_CTL_LINK_TRAIN_IDLE,
78 DP_Info.TP_None => DP_TP_CTL_LINK_TRAIN_NORMAL);
79
80 DP_TP_STATUS_MIN_IDLES_SENT : constant := 1 * 2 ** 25;
81 DP_TP_STATUS_FDI_AUTO_TRAIN_DONE : constant := 1 * 2 ** 12;
82
83 PORT_CLK_SEL_LCPLL2700 : constant := 0 * 2 ** 29; -- not on ULX
84 PORT_CLK_SEL_LCPLL1350 : constant := 1 * 2 ** 29;
85 PORT_CLK_SEL_LCPLL810 : constant := 2 * 2 ** 29;
86 PORT_CLK_SEL_SPLL : constant := 3 * 2 ** 29;
87 PORT_CLK_SEL_WRPLL1 : constant := 4 * 2 ** 29;
88 PORT_CLK_SEL_WRPLL2 : constant := 5 * 2 ** 29;
89 PORT_CLK_SEL_NONE : constant := 7 * 2 ** 29;
90
91 type PORT_CLK_SEL_LCPLL_T is array (HW.GFX.DP_Bandwidth) of Word32;
92 PORT_CLK_SEL_LCPLL : constant PORT_CLK_SEL_LCPLL_T :=
93 PORT_CLK_SEL_LCPLL_T'
94 (HW.GFX.DP_Bandwidth_1_62 => PORT_CLK_SEL_LCPLL810,
95 HW.GFX.DP_Bandwidth_2_7 => PORT_CLK_SEL_LCPLL1350,
96 HW.GFX.DP_Bandwidth_5_4 => PORT_CLK_SEL_LCPLL2700);
97
Nico Huber01b680f2017-06-09 16:24:22 +020098 type DDI_Buf_Trans_Regs_Array
99 is array (Buf_Trans_Range) of Registers.Registers_Index;
100
Nico Huber83693c82016-10-08 22:17:55 +0200101 type DDI_Registers is record
102 BUF_CTL : Registers.Registers_Index;
Nico Huber01b680f2017-06-09 16:24:22 +0200103 BUF_TRANS : DDI_Buf_Trans_Regs_Array;
Nico Huber83693c82016-10-08 22:17:55 +0200104 DP_TP_CTL : Registers.Registers_Index;
105 DP_TP_STATUS : Registers.Registers_Invalid_Index;
106 PORT_CLK_SEL : Registers.Registers_Index;
107 end record;
108
109 type DDI_Registers_Array is array (Digital_Port) of DDI_Registers;
110
111 DDI_Regs : constant DDI_Registers_Array := DDI_Registers_Array'
112 (DIGI_A => DDI_Registers'
113 (BUF_CTL => Registers.DDI_BUF_CTL_A,
Nico Huber01b680f2017-06-09 16:24:22 +0200114 BUF_TRANS => DDI_Buf_Trans_Regs_Array'
115 (Registers.DDI_BUF_TRANS_A_S0T1,
116 Registers.DDI_BUF_TRANS_A_S0T2,
117 Registers.DDI_BUF_TRANS_A_S1T1,
118 Registers.DDI_BUF_TRANS_A_S1T2,
119 Registers.DDI_BUF_TRANS_A_S2T1,
120 Registers.DDI_BUF_TRANS_A_S2T2,
121 Registers.DDI_BUF_TRANS_A_S3T1,
122 Registers.DDI_BUF_TRANS_A_S3T2,
123 Registers.DDI_BUF_TRANS_A_S4T1,
124 Registers.DDI_BUF_TRANS_A_S4T2,
125 Registers.DDI_BUF_TRANS_A_S5T1,
126 Registers.DDI_BUF_TRANS_A_S5T2,
127 Registers.DDI_BUF_TRANS_A_S6T1,
128 Registers.DDI_BUF_TRANS_A_S6T2,
129 Registers.DDI_BUF_TRANS_A_S7T1,
130 Registers.DDI_BUF_TRANS_A_S7T2,
131 Registers.DDI_BUF_TRANS_A_S8T1,
132 Registers.DDI_BUF_TRANS_A_S8T2,
133 Registers.DDI_BUF_TRANS_A_S9T1,
134 Registers.DDI_BUF_TRANS_A_S9T2),
Nico Huber83693c82016-10-08 22:17:55 +0200135 DP_TP_CTL => Registers.DP_TP_CTL_A,
136 DP_TP_STATUS => Registers.Invalid_Register,
137 PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIA),
138 DIGI_B => DDI_Registers'
139 (BUF_CTL => Registers.DDI_BUF_CTL_B,
Nico Huber01b680f2017-06-09 16:24:22 +0200140 BUF_TRANS => DDI_Buf_Trans_Regs_Array'
141 (Registers.DDI_BUF_TRANS_B_S0T1,
142 Registers.DDI_BUF_TRANS_B_S0T2,
143 Registers.DDI_BUF_TRANS_B_S1T1,
144 Registers.DDI_BUF_TRANS_B_S1T2,
145 Registers.DDI_BUF_TRANS_B_S2T1,
146 Registers.DDI_BUF_TRANS_B_S2T2,
147 Registers.DDI_BUF_TRANS_B_S3T1,
148 Registers.DDI_BUF_TRANS_B_S3T2,
149 Registers.DDI_BUF_TRANS_B_S4T1,
150 Registers.DDI_BUF_TRANS_B_S4T2,
151 Registers.DDI_BUF_TRANS_B_S5T1,
152 Registers.DDI_BUF_TRANS_B_S5T2,
153 Registers.DDI_BUF_TRANS_B_S6T1,
154 Registers.DDI_BUF_TRANS_B_S6T2,
155 Registers.DDI_BUF_TRANS_B_S7T1,
156 Registers.DDI_BUF_TRANS_B_S7T2,
157 Registers.DDI_BUF_TRANS_B_S8T1,
158 Registers.DDI_BUF_TRANS_B_S8T2,
159 Registers.DDI_BUF_TRANS_B_S9T1,
160 Registers.DDI_BUF_TRANS_B_S9T2),
Nico Huber83693c82016-10-08 22:17:55 +0200161 DP_TP_CTL => Registers.DP_TP_CTL_B,
162 DP_TP_STATUS => Registers.DP_TP_STATUS_B,
163 PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIB),
164 DIGI_C => DDI_Registers'
165 (BUF_CTL => Registers.DDI_BUF_CTL_C,
Nico Huber01b680f2017-06-09 16:24:22 +0200166 BUF_TRANS => DDI_Buf_Trans_Regs_Array'
167 (Registers.DDI_BUF_TRANS_C_S0T1,
168 Registers.DDI_BUF_TRANS_C_S0T2,
169 Registers.DDI_BUF_TRANS_C_S1T1,
170 Registers.DDI_BUF_TRANS_C_S1T2,
171 Registers.DDI_BUF_TRANS_C_S2T1,
172 Registers.DDI_BUF_TRANS_C_S2T2,
173 Registers.DDI_BUF_TRANS_C_S3T1,
174 Registers.DDI_BUF_TRANS_C_S3T2,
175 Registers.DDI_BUF_TRANS_C_S4T1,
176 Registers.DDI_BUF_TRANS_C_S4T2,
177 Registers.DDI_BUF_TRANS_C_S5T1,
178 Registers.DDI_BUF_TRANS_C_S5T2,
179 Registers.DDI_BUF_TRANS_C_S6T1,
180 Registers.DDI_BUF_TRANS_C_S6T2,
181 Registers.DDI_BUF_TRANS_C_S7T1,
182 Registers.DDI_BUF_TRANS_C_S7T2,
183 Registers.DDI_BUF_TRANS_C_S8T1,
184 Registers.DDI_BUF_TRANS_C_S8T2,
185 Registers.DDI_BUF_TRANS_C_S9T1,
186 Registers.DDI_BUF_TRANS_C_S9T2),
Nico Huber83693c82016-10-08 22:17:55 +0200187 DP_TP_CTL => Registers.DP_TP_CTL_C,
188 DP_TP_STATUS => Registers.DP_TP_STATUS_C,
189 PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIC),
190 DIGI_D => DDI_Registers'
191 (BUF_CTL => Registers.DDI_BUF_CTL_D,
Nico Huber01b680f2017-06-09 16:24:22 +0200192 BUF_TRANS => DDI_Buf_Trans_Regs_Array'
193 (Registers.DDI_BUF_TRANS_D_S0T1,
194 Registers.DDI_BUF_TRANS_D_S0T2,
195 Registers.DDI_BUF_TRANS_D_S1T1,
196 Registers.DDI_BUF_TRANS_D_S1T2,
197 Registers.DDI_BUF_TRANS_D_S2T1,
198 Registers.DDI_BUF_TRANS_D_S2T2,
199 Registers.DDI_BUF_TRANS_D_S3T1,
200 Registers.DDI_BUF_TRANS_D_S3T2,
201 Registers.DDI_BUF_TRANS_D_S4T1,
202 Registers.DDI_BUF_TRANS_D_S4T2,
203 Registers.DDI_BUF_TRANS_D_S5T1,
204 Registers.DDI_BUF_TRANS_D_S5T2,
205 Registers.DDI_BUF_TRANS_D_S6T1,
206 Registers.DDI_BUF_TRANS_D_S6T2,
207 Registers.DDI_BUF_TRANS_D_S7T1,
208 Registers.DDI_BUF_TRANS_D_S7T2,
209 Registers.DDI_BUF_TRANS_D_S8T1,
210 Registers.DDI_BUF_TRANS_D_S8T2,
211 Registers.DDI_BUF_TRANS_D_S9T1,
212 Registers.DDI_BUF_TRANS_D_S9T2),
Nico Huber83693c82016-10-08 22:17:55 +0200213 DP_TP_CTL => Registers.DP_TP_CTL_D,
214 DP_TP_STATUS => Registers.DP_TP_STATUS_D,
215 PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDID),
216 DIGI_E => DDI_Registers'
217 (BUF_CTL => Registers.DDI_BUF_CTL_E,
Nico Huber01b680f2017-06-09 16:24:22 +0200218 BUF_TRANS => DDI_Buf_Trans_Regs_Array'
219 (Registers.DDI_BUF_TRANS_E_S0T1,
220 Registers.DDI_BUF_TRANS_E_S0T2,
221 Registers.DDI_BUF_TRANS_E_S1T1,
222 Registers.DDI_BUF_TRANS_E_S1T2,
223 Registers.DDI_BUF_TRANS_E_S2T1,
224 Registers.DDI_BUF_TRANS_E_S2T2,
225 Registers.DDI_BUF_TRANS_E_S3T1,
226 Registers.DDI_BUF_TRANS_E_S3T2,
227 Registers.DDI_BUF_TRANS_E_S4T1,
228 Registers.DDI_BUF_TRANS_E_S4T2,
229 Registers.DDI_BUF_TRANS_E_S5T1,
230 Registers.DDI_BUF_TRANS_E_S5T2,
231 Registers.DDI_BUF_TRANS_E_S6T1,
232 Registers.DDI_BUF_TRANS_E_S6T2,
233 Registers.DDI_BUF_TRANS_E_S7T1,
234 Registers.DDI_BUF_TRANS_E_S7T2,
235 Registers.DDI_BUF_TRANS_E_S8T1,
236 Registers.DDI_BUF_TRANS_E_S8T2,
237 Registers.DDI_BUF_TRANS_E_S9T1,
238 Registers.DDI_BUF_TRANS_E_S9T2),
Nico Huber83693c82016-10-08 22:17:55 +0200239 DP_TP_CTL => Registers.DP_TP_CTL_E,
240 DP_TP_STATUS => Registers.DP_TP_STATUS_E,
241 PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIE));
242
243 ----------------------------------------------------------------------------
244
245 type Values is array (Digital_Port) of Word32;
246 type Shifts is array (Digital_Port) of Natural;
247
248 DPLL_CTRL2_DDIx_CLOCK_OFF : constant Values := Values'
249 (DIGI_A => 1 * 2 ** 15,
250 DIGI_B => 1 * 2 ** 16,
251 DIGI_C => 1 * 2 ** 17,
252 DIGI_D => 1 * 2 ** 18,
253 DIGI_E => 1 * 2 ** 19);
254
255 DPLL_CTRL2_DDIx_SELECT_MASK : constant Values := Values'
256 (DIGI_A => 3 * 2 ** 1,
257 DIGI_B => 3 * 2 ** 4,
258 DIGI_C => 3 * 2 ** 7,
259 DIGI_D => 3 * 2 ** 10,
260 DIGI_E => 3 * 2 ** 13);
261 DPLL_CTRL2_DDIx_SELECT_SHIFT : constant Shifts := Shifts'
262 (DIGI_A => 1,
263 DIGI_B => 4,
264 DIGI_C => 7,
265 DIGI_D => 10,
266 DIGI_E => 13);
267
268 DPLL_CTRL2_DDIx_SELECT_OVERRIDE : constant Values := Values'
269 (DIGI_A => 1 * 2 ** 0,
270 DIGI_B => 1 * 2 ** 3,
271 DIGI_C => 1 * 2 ** 6,
272 DIGI_D => 1 * 2 ** 9,
273 DIGI_E => 1 * 2 ** 12);
274
275 ----------------------------------------------------------------------------
276
277 function DDI_BUF_CTL_TRANS_SELECT
278 (Sel : DDI_BUF_CTL_TRANS_SELECT_T)
279 return Word32
280 is
281 begin
282 return Word32 (Sel) * 2 ** 24;
283 end DDI_BUF_CTL_TRANS_SELECT;
284
285 ----------------------------------------------------------------------------
286
Nico Huber01b680f2017-06-09 16:24:22 +0200287 procedure Program_Buffer_Translations (Port : Digital_Port)
288 is
289 Buffer_Translations : Buf_Trans_Array;
290 begin
291 Buffers.Translations (Buffer_Translations, Port);
292 for I in Buf_Trans_Range loop
293 Registers.Write
294 (Register => DDI_Regs (Port).BUF_TRANS (I),
295 Value => Buffer_Translations (I));
296 end loop;
297 end Program_Buffer_Translations;
298
299 procedure Initialize
300 is
301 begin
302 if Config.Has_DDI_Buffer_Trans then
303 for Port in Digital_Port range DIGI_A .. Config.Last_Digital_Port loop
304 Program_Buffer_Translations (Port);
305 end loop;
306 if Config.Is_FDI_Port (Analog) then
307 Program_Buffer_Translations (DIGI_E);
308 end if;
309 end if;
310 end Initialize;
311
312 ----------------------------------------------------------------------------
313
Nico Huber83693c82016-10-08 22:17:55 +0200314 function Max_V_Swing
315 (Port : Digital_Port)
316 return DP_Info.DP_Voltage_Swing
317 is
318 begin
319 return
Nico Huber1c3b9282017-02-09 13:57:04 +0100320 (if Config.Has_DDI_PHYs then
321 DDI_Phy.Max_V_Swing
322 elsif (Config.Has_Low_Voltage_Swing and Config.EDP_Low_Voltage_Swing)
Nico Huber83693c82016-10-08 22:17:55 +0200323 and then Port = DIGI_A
324 then
325 DP_Info.VS_Level_3
326 else
327 DP_Info.VS_Level_2);
328 end Max_V_Swing;
329
330 pragma Warnings (GNATprove, Off, "unused variable ""Port""",
331 Reason => "Needed for a common interface");
332 function Max_Pre_Emph
333 (Port : Digital_Port;
334 Train_Set : DP_Info.Train_Set)
335 return DP_Info.DP_Pre_Emph
336 is
337 begin
338 return
Nico Huber1c3b9282017-02-09 13:57:04 +0100339 (if Config.Has_DDI_PHYs then
340 DDI_Phy.Max_Pre_Emph (Train_Set.Voltage_Swing)
341 else
342 (case Train_Set.Voltage_Swing is
343 when DP_Info.VS_Level_0 => DP_Info.Emph_Level_3,
344 when DP_Info.VS_Level_1 => DP_Info.Emph_Level_2,
345 when DP_Info.VS_Level_2 => DP_Info.Emph_Level_1,
346 when others => DP_Info.Emph_Level_0));
Nico Huber83693c82016-10-08 22:17:55 +0200347 end Max_Pre_Emph;
348 pragma Warnings (GNATprove, On, "unused variable ""Port""");
349
350 ----------------------------------------------------------------------------
351
352 procedure Set_TP_CTL
353 (Port : Digital_Port;
354 Link : DP_Link;
355 Pattern : DP_Info.Training_Pattern)
356 is
357 DP_TP_CTL_Enhanced_Frame : Word32 := 0;
358 begin
359 if Link.Enhanced_Framing then
360 DP_TP_CTL_Enhanced_Frame := DP_TP_CTL_ENHANCED_FRAME_ENABLE;
361 end if;
362
363 Registers.Write
364 (Register => DDI_Regs (Port).DP_TP_CTL,
365 Value => DP_TP_CTL_TRANSPORT_ENABLE or
366 DP_TP_CTL_Enhanced_Frame or
367 DP_TP_CTL_LINK_TRAIN (Pattern));
368 end Set_TP_CTL;
369
370 procedure Set_Training_Pattern
371 (Port : Digital_Port;
372 Link : DP_Link;
373 Pattern : DP_Info.Training_Pattern)
374 is
375 use type DP_Info.Training_Pattern;
376 begin
377 if Pattern < DP_Info.TP_Idle then
378 Set_TP_CTL (Port, Link, Pattern);
379 else
380 -- send at least 5 idle patterns
381 Set_TP_CTL (Port, Link, DP_Info.TP_Idle);
382
383 -- switch to normal frame delivery
384 if Config.End_EDP_Training_Late and then Port = DIGI_A then
385 null; -- do it later in Post_On procedure
386 -- TODO: if there are problems getting the pipe up,
387 -- wait here some time
388 -- Time.U_Delay (100);
389 else
390 if Port /= DIGI_A then
391 Registers.Wait_Set_Mask
392 (Register => DDI_Regs (Port).DP_TP_STATUS,
393 Mask => DP_TP_STATUS_MIN_IDLES_SENT);
394 end if;
395 Set_TP_CTL (Port, Link, DP_Info.TP_None);
396 end if;
397 end if;
398 end Set_Training_Pattern;
399
400 procedure Set_Signal_Levels
401 (Port : Digital_Port;
402 Link : DP_Link;
403 Train_Set : DP_Info.Train_Set)
404 is
405 Was_Enabled : Boolean;
406 Trans_Select : DDI_BUF_CTL_TRANS_SELECT_T;
407 begin
Nico Huber83693c82016-10-08 22:17:55 +0200408 Registers.Is_Set_Mask
409 (Register => DDI_Regs (Port).BUF_CTL,
410 Mask => DDI_BUF_CTL_BUFFER_ENABLE,
411 Result => Was_Enabled);
412
Nico Huber1c3b9282017-02-09 13:57:04 +0100413 if Config.Has_DDI_PHYs then
414 Trans_Select := 0;
415 else
416 case Train_Set.Voltage_Swing is
417 when DP_Info.VS_Level_0 =>
418 case Train_Set.Pre_Emph is
419 when DP_Info.Emph_Level_0 => Trans_Select := 0;
420 when DP_Info.Emph_Level_1 => Trans_Select := 1;
421 when DP_Info.Emph_Level_2 => Trans_Select := 2;
422 when DP_Info.Emph_Level_3 => Trans_Select := 3;
423 end case;
424 when DP_Info.VS_Level_1 =>
425 case Train_Set.Pre_Emph is
426 when DP_Info.Emph_Level_0 => Trans_Select := 4;
427 when DP_Info.Emph_Level_1 => Trans_Select := 5;
428 when DP_Info.Emph_Level_2 => Trans_Select := 6;
429 when others => Trans_Select := 0;
430 end case;
431 when DP_Info.VS_Level_2 =>
432 case Train_Set.Pre_Emph is
433 when DP_Info.Emph_Level_0 => Trans_Select := 7;
434 when DP_Info.Emph_Level_1 => Trans_Select := 8;
435 when others => Trans_Select := 0;
436 end case;
437 when DP_Info.VS_Level_3 =>
438 case Train_Set.Pre_Emph is
439 when DP_Info.Emph_Level_0 => Trans_Select := 9;
440 when others => Trans_Select := 0;
441 end case;
442 end case;
443 end if;
444
Nico Huber83693c82016-10-08 22:17:55 +0200445 -- enable DDI buffer
446 Registers.Unset_And_Set_Mask
447 (Register => DDI_Regs (Port).BUF_CTL,
448 Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
449 DDI_BUF_CTL_PORT_REVERSAL or
450 DDI_BUF_CTL_PORT_WIDTH_MASK,
451 Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE or
452 DDI_BUF_CTL_TRANS_SELECT (Trans_Select) or
453 DDI_BUF_CTL_PORT_WIDTH (Link.Lane_Count));
454 Registers.Posting_Read (DDI_Regs (Port).BUF_CTL);
455
456 if not Was_Enabled then
457 Time.U_Delay (600); -- wait >= 518us (intel spec)
458 end if;
Nico Huber1c3b9282017-02-09 13:57:04 +0100459
460 if Config.Has_DDI_PHYs then
461 DDI_Phy.Set_DP_Signal_Levels (Port, Train_Set);
462 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200463 end Set_Signal_Levels;
464
465 ----------------------------------------------------------------------------
466
467 procedure Digital_Off (Port : Digital_Port)
468 is
469 Enabled : Boolean;
470 begin
471 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
472
473 Registers.Is_Set_Mask
474 (Register => DDI_Regs (Port).BUF_CTL,
475 Mask => DDI_BUF_CTL_BUFFER_ENABLE,
476 Result => Enabled);
477
478 if Enabled then
479 Registers.Unset_Mask
480 (Register => DDI_Regs (Port).BUF_CTL,
481 Mask => DDI_BUF_CTL_BUFFER_ENABLE);
482 end if;
483
484 Registers.Unset_Mask
485 (Register => DDI_Regs (Port).DP_TP_CTL,
486 Mask => DP_TP_CTL_TRANSPORT_ENABLE);
487
488 if Enabled then
489 Registers.Wait_Set_Mask
490 (Register => DDI_Regs (Port).BUF_CTL,
491 Mask => DDI_BUF_CTL_IDLE_STATUS);
492 end if;
493
494 if Config.Has_Per_DDI_Clock_Sel then
495 Registers.Write
496 (Register => DDI_Regs (Port).PORT_CLK_SEL,
497 Value => PORT_CLK_SEL_NONE);
Nico Huber1c3b9282017-02-09 13:57:04 +0100498 elsif not Config.Has_DDI_PHYs then
Nico Huber83693c82016-10-08 22:17:55 +0200499 Registers.Set_Mask
500 (Register => Registers.DPLL_CTRL2,
501 Mask => DPLL_CTRL2_DDIx_CLOCK_OFF (Port));
502 end if;
503 end Digital_Off;
504
505 ----------------------------------------------------------------------------
506
507 procedure Train_FDI
508 (Port_Cfg : in Port_Config;
509 Success : out Boolean)
510 is
511 begin
512 PCH.FDI.Pre_Train (PCH.FDI_A, Port_Cfg);
513
514 -- always use SPLL for FDI
515 SPLL.On;
516 Registers.Write
517 (Register => DDI_Regs (DIGI_E).PORT_CLK_SEL,
518 Value => PORT_CLK_SEL_SPLL);
519
520 -- try each preemph/voltage pair twice
521 for Trans2 in Natural range 0 .. DDI_BUF_CTL_TRANS_SELECT_T'Last * 2 + 1
522 loop
523 Registers.Write
524 (Register => DDI_Regs (DIGI_E).DP_TP_CTL,
525 Value => DP_TP_CTL_TRANSPORT_ENABLE or
526 DP_TP_CTL_ENHANCED_FRAME_ENABLE or
527 DP_TP_CTL_FDI_AUTOTRAIN or
528 DP_TP_CTL_LINK_TRAIN_PAT1);
529
530 Registers.Unset_And_Set_Mask
531 (Register => DDI_Regs (DIGI_E).BUF_CTL,
532 Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
533 DDI_BUF_CTL_PORT_REVERSAL or
534 DDI_BUF_CTL_PORT_WIDTH_MASK,
535 Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE or
536 DDI_BUF_CTL_TRANS_SELECT (Trans2 / 2) or
537 DDI_BUF_CTL_PORT_WIDTH (Port_Cfg.FDI.Lane_Count));
538 Registers.Posting_Read (DDI_Regs (DIGI_E).BUF_CTL);
539 Time.U_Delay (600); -- wait >= 518us (intel spec)
540
541 PCH.FDI.Auto_Train (PCH.FDI_A);
542 Registers.Is_Set_Mask
543 (Register => DDI_Regs (DIGI_E).DP_TP_STATUS,
544 Mask => DP_TP_STATUS_FDI_AUTO_TRAIN_DONE,
545 Result => Success);
546 exit when Success;
547
548 Registers.Unset_Mask
549 (Register => DDI_Regs (DIGI_E).BUF_CTL,
550 Mask => DDI_BUF_CTL_BUFFER_ENABLE);
551 Registers.Posting_Read (DDI_Regs (DIGI_E).BUF_CTL);
552
553 Registers.Unset_And_Set_Mask
554 (Register => DDI_Regs (DIGI_E).DP_TP_CTL,
555 Mask_Unset => DP_TP_CTL_TRANSPORT_ENABLE or
556 DP_TP_CTL_LINK_TRAIN_MASK,
557 Mask_Set => DP_TP_CTL_LINK_TRAIN_PAT1);
558 Registers.Posting_Read (DDI_Regs (DIGI_E).DP_TP_CTL);
559
560 Registers.Wait_Set_Mask
561 (Register => DDI_Regs (DIGI_E).BUF_CTL,
562 Mask => DDI_BUF_CTL_IDLE_STATUS);
563
564 PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Lanes_Off);
565 end loop;
566
567 if Success then
568 -- start normal frame delivery
569 Registers.Write
570 (Register => DDI_Regs (DIGI_E).DP_TP_CTL,
571 Value => DP_TP_CTL_TRANSPORT_ENABLE or
572 DP_TP_CTL_ENHANCED_FRAME_ENABLE or
573 DP_TP_CTL_FDI_AUTOTRAIN or
574 DP_TP_CTL_LINK_TRAIN_NORMAL);
575 else
576 Registers.Write
577 (Register => DDI_Regs (DIGI_E).PORT_CLK_SEL,
578 Value => PORT_CLK_SEL_NONE);
579 SPLL.Off;
580
581 PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Clock_Off);
582 end if;
583 end Train_FDI;
584
585 ----------------------------------------------------------------------------
586
587 procedure Pre_On
588 (Port_Cfg : in Port_Config;
589 PLL_Hint : in Word32;
590 Success : out Boolean)
591 is
592 function To_DP (Port : Digital_Port) return DP_Port
593 is
594 begin
595 return
596 (case Port is
597 when DIGI_A => DP_A,
598 when DIGI_B => DP_B,
599 when DIGI_C => DP_C,
600 when DIGI_D => DP_D,
601 when others => DP_Port'First);
602 end To_DP;
603 package Training is new DP_Training
604 (TPS3_Supported => True,
605 T => Digital_Port,
606 Aux_T => DP_Port,
607 Aux_Ch => DP_Aux_Ch,
608 DP_Info => DP_Info,
609 To_Aux => To_DP,
610 Max_V_Swing => Max_V_Swing,
611 Max_Pre_Emph => Max_Pre_Emph,
612 Set_Pattern => Set_Training_Pattern,
613 Set_Signal_Levels => Set_Signal_Levels,
614 Off => Digital_Off);
615 begin
616 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
617
618 if Port_Cfg.Display = VGA then
619 Train_FDI (Port_Cfg, Success);
620 else
621 -- direct configured PLL output to this port
622 if Config.Has_Per_DDI_Clock_Sel then
623 Registers.Write
624 (Register => DDI_Regs (Port_Cfg.Port).PORT_CLK_SEL,
625 Value => PLL_Hint);
Nico Huber1c3b9282017-02-09 13:57:04 +0100626 elsif not Config.Has_DDI_PHYs then
Nico Huber83693c82016-10-08 22:17:55 +0200627 Registers.Unset_And_Set_Mask
628 (Register => Registers.DPLL_CTRL2,
629 Mask_Unset => DPLL_CTRL2_DDIx_CLOCK_OFF (Port_Cfg.Port) or
630 DPLL_CTRL2_DDIx_SELECT_MASK (Port_Cfg.Port),
631 Mask_Set => Shift_Left
632 (PLL_Hint,
633 DPLL_CTRL2_DDIx_SELECT_SHIFT (Port_Cfg.Port))
634 or
635 DPLL_CTRL2_DDIx_SELECT_OVERRIDE (Port_Cfg.Port));
636 end if;
637
638 if Port_Cfg.Display = DP then
639 Training.Train_DP
640 (Port => Port_Cfg.Port,
641 Link => Port_Cfg.DP,
642 Success => Success);
Nico Huber1c3b9282017-02-09 13:57:04 +0100643 elsif Config.Has_DDI_PHYs and then
644 Port_Cfg.Display = HDMI and then
645 Port_Cfg.Port in DDI_Phy.DDI_Phy_Port
646 then
Nico Huber247adf32017-06-12 14:39:11 +0200647 declare
648 HDMI_Level : constant DDI_Phy.HDMI_Buf_Trans_Range :=
649 (if Config.DDI_HDMI_Buffer_Translation
650 in DDI_Phy.HDMI_Buf_Trans_Range
651 then Config.DDI_HDMI_Buffer_Translation
652 else Config.Default_DDI_HDMI_Buffer_Translation);
653 begin
654 DDI_Phy.Set_HDMI_Signal_Levels (Port_Cfg.Port, HDMI_Level);
655 Success := True;
656 end;
Nico Huber83693c82016-10-08 22:17:55 +0200657 else
658 Success := True;
659 end if;
660 end if;
661 end Pre_On;
662
663 ----------------------------------------------------------------------------
664
665 procedure Post_On (Port_Cfg : Port_Config)
666 is
667 begin
668 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
669
670 if Port_Cfg.Port = DIGI_A then
671 if Config.End_EDP_Training_Late then
672 Registers.Unset_And_Set_Mask
673 (Register => DDI_Regs (DIGI_A).DP_TP_CTL,
674 Mask_Unset => DP_TP_CTL_LINK_TRAIN_MASK,
675 Mask_Set => DP_TP_CTL_LINK_TRAIN_NORMAL);
676 end if;
677 end if;
678
679 case Port_Cfg.Display is
680 when HDMI =>
681 Registers.Unset_And_Set_Mask
682 (Register => DDI_Regs (Port_Cfg.Port).BUF_CTL,
683 Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
684 DDI_BUF_CTL_PORT_REVERSAL,
685 Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE);
686 Time.U_Delay (600); -- wait >= 518us (intel spec)
687 when VGA =>
688 PCH.VGA.Clock_On (Port_Cfg.Mode);
689 PCH.Transcoder.On (Port_Cfg, PCH.FDI_A, 0);
690 PCH.VGA.On
691 (Port => PCH.FDI_A,
692 Mode => Port_Cfg.Mode);
693 when others =>
694 null;
695 end case;
696 end Post_On;
697
698 ----------------------------------------------------------------------------
699
700 procedure Off (Port : Digital_Port)
701 is
702 begin
703 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
704
705 if Port = DIGI_E then
706 PCH.VGA.Off;
707 PCH.Transcoder.Off (PCH.FDI_A);
708 -- PCH.VGA.Clock_Off; -- Can't tell what Linux does, if anything.
709 PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Rx_Off);
710 end if;
711
712 Digital_Off (Port);
713
714 if Port = DIGI_E then
715 SPLL.Off;
716 PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Clock_Off);
717 end if;
718 end Off;
719
720end HW.GFX.GMA.Connectors.DDI;