blob: 7efb93f3718691181f5e025924996ad47a116ace [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 Huber58afc202017-06-12 21:34:55 +020098 DISPIO_CR_TX_BLNC_LEG_DISBL_MASK : constant := 16#1f# * 2 ** 23;
99 DISPIO_CR_TX_BLNC_LEG_SCTL_4_SHIFT : constant := 20;
100 DISPIO_CR_TX_BLNC_LEG_SCTL_4_MASK : constant := 16#07# * 2 ** 20;
101 DISPIO_CR_TX_BLNC_LEG_SCTL_3_SHIFT : constant := 17;
102 DISPIO_CR_TX_BLNC_LEG_SCTL_3_MASK : constant := 16#07# * 2 ** 17;
103 DISPIO_CR_TX_BLNC_LEG_SCTL_2_SHIFT : constant := 14;
104 DISPIO_CR_TX_BLNC_LEG_SCTL_2_MASK : constant := 16#07# * 2 ** 14;
105 DISPIO_CR_TX_BLNC_LEG_SCTL_1_SHIFT : constant := 11;
106 DISPIO_CR_TX_BLNC_LEG_SCTL_1_MASK : constant := 16#07# * 2 ** 11;
107 DISPIO_CR_TX_BLNC_LEG_SCTL_0_SHIFT : constant := 8;
108 DISPIO_CR_TX_BLNC_LEG_SCTL_0_MASK : constant := 16#07# * 2 ** 8;
109
Nico Huber01b680f2017-06-09 16:24:22 +0200110 type DDI_Buf_Trans_Regs_Array
111 is array (Buf_Trans_Range) of Registers.Registers_Index;
112
Nico Huber83693c82016-10-08 22:17:55 +0200113 type DDI_Registers is record
114 BUF_CTL : Registers.Registers_Index;
Nico Huber01b680f2017-06-09 16:24:22 +0200115 BUF_TRANS : DDI_Buf_Trans_Regs_Array;
Nico Huber83693c82016-10-08 22:17:55 +0200116 DP_TP_CTL : Registers.Registers_Index;
117 DP_TP_STATUS : Registers.Registers_Invalid_Index;
118 PORT_CLK_SEL : Registers.Registers_Index;
119 end record;
120
121 type DDI_Registers_Array is array (Digital_Port) of DDI_Registers;
122
123 DDI_Regs : constant DDI_Registers_Array := DDI_Registers_Array'
124 (DIGI_A => DDI_Registers'
125 (BUF_CTL => Registers.DDI_BUF_CTL_A,
Nico Huber01b680f2017-06-09 16:24:22 +0200126 BUF_TRANS => DDI_Buf_Trans_Regs_Array'
127 (Registers.DDI_BUF_TRANS_A_S0T1,
128 Registers.DDI_BUF_TRANS_A_S0T2,
129 Registers.DDI_BUF_TRANS_A_S1T1,
130 Registers.DDI_BUF_TRANS_A_S1T2,
131 Registers.DDI_BUF_TRANS_A_S2T1,
132 Registers.DDI_BUF_TRANS_A_S2T2,
133 Registers.DDI_BUF_TRANS_A_S3T1,
134 Registers.DDI_BUF_TRANS_A_S3T2,
135 Registers.DDI_BUF_TRANS_A_S4T1,
136 Registers.DDI_BUF_TRANS_A_S4T2,
137 Registers.DDI_BUF_TRANS_A_S5T1,
138 Registers.DDI_BUF_TRANS_A_S5T2,
139 Registers.DDI_BUF_TRANS_A_S6T1,
140 Registers.DDI_BUF_TRANS_A_S6T2,
141 Registers.DDI_BUF_TRANS_A_S7T1,
142 Registers.DDI_BUF_TRANS_A_S7T2,
143 Registers.DDI_BUF_TRANS_A_S8T1,
144 Registers.DDI_BUF_TRANS_A_S8T2,
145 Registers.DDI_BUF_TRANS_A_S9T1,
146 Registers.DDI_BUF_TRANS_A_S9T2),
Nico Huber83693c82016-10-08 22:17:55 +0200147 DP_TP_CTL => Registers.DP_TP_CTL_A,
148 DP_TP_STATUS => Registers.Invalid_Register,
149 PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIA),
150 DIGI_B => DDI_Registers'
151 (BUF_CTL => Registers.DDI_BUF_CTL_B,
Nico Huber01b680f2017-06-09 16:24:22 +0200152 BUF_TRANS => DDI_Buf_Trans_Regs_Array'
153 (Registers.DDI_BUF_TRANS_B_S0T1,
154 Registers.DDI_BUF_TRANS_B_S0T2,
155 Registers.DDI_BUF_TRANS_B_S1T1,
156 Registers.DDI_BUF_TRANS_B_S1T2,
157 Registers.DDI_BUF_TRANS_B_S2T1,
158 Registers.DDI_BUF_TRANS_B_S2T2,
159 Registers.DDI_BUF_TRANS_B_S3T1,
160 Registers.DDI_BUF_TRANS_B_S3T2,
161 Registers.DDI_BUF_TRANS_B_S4T1,
162 Registers.DDI_BUF_TRANS_B_S4T2,
163 Registers.DDI_BUF_TRANS_B_S5T1,
164 Registers.DDI_BUF_TRANS_B_S5T2,
165 Registers.DDI_BUF_TRANS_B_S6T1,
166 Registers.DDI_BUF_TRANS_B_S6T2,
167 Registers.DDI_BUF_TRANS_B_S7T1,
168 Registers.DDI_BUF_TRANS_B_S7T2,
169 Registers.DDI_BUF_TRANS_B_S8T1,
170 Registers.DDI_BUF_TRANS_B_S8T2,
171 Registers.DDI_BUF_TRANS_B_S9T1,
172 Registers.DDI_BUF_TRANS_B_S9T2),
Nico Huber83693c82016-10-08 22:17:55 +0200173 DP_TP_CTL => Registers.DP_TP_CTL_B,
174 DP_TP_STATUS => Registers.DP_TP_STATUS_B,
175 PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIB),
176 DIGI_C => DDI_Registers'
177 (BUF_CTL => Registers.DDI_BUF_CTL_C,
Nico Huber01b680f2017-06-09 16:24:22 +0200178 BUF_TRANS => DDI_Buf_Trans_Regs_Array'
179 (Registers.DDI_BUF_TRANS_C_S0T1,
180 Registers.DDI_BUF_TRANS_C_S0T2,
181 Registers.DDI_BUF_TRANS_C_S1T1,
182 Registers.DDI_BUF_TRANS_C_S1T2,
183 Registers.DDI_BUF_TRANS_C_S2T1,
184 Registers.DDI_BUF_TRANS_C_S2T2,
185 Registers.DDI_BUF_TRANS_C_S3T1,
186 Registers.DDI_BUF_TRANS_C_S3T2,
187 Registers.DDI_BUF_TRANS_C_S4T1,
188 Registers.DDI_BUF_TRANS_C_S4T2,
189 Registers.DDI_BUF_TRANS_C_S5T1,
190 Registers.DDI_BUF_TRANS_C_S5T2,
191 Registers.DDI_BUF_TRANS_C_S6T1,
192 Registers.DDI_BUF_TRANS_C_S6T2,
193 Registers.DDI_BUF_TRANS_C_S7T1,
194 Registers.DDI_BUF_TRANS_C_S7T2,
195 Registers.DDI_BUF_TRANS_C_S8T1,
196 Registers.DDI_BUF_TRANS_C_S8T2,
197 Registers.DDI_BUF_TRANS_C_S9T1,
198 Registers.DDI_BUF_TRANS_C_S9T2),
Nico Huber83693c82016-10-08 22:17:55 +0200199 DP_TP_CTL => Registers.DP_TP_CTL_C,
200 DP_TP_STATUS => Registers.DP_TP_STATUS_C,
201 PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIC),
202 DIGI_D => DDI_Registers'
203 (BUF_CTL => Registers.DDI_BUF_CTL_D,
Nico Huber01b680f2017-06-09 16:24:22 +0200204 BUF_TRANS => DDI_Buf_Trans_Regs_Array'
205 (Registers.DDI_BUF_TRANS_D_S0T1,
206 Registers.DDI_BUF_TRANS_D_S0T2,
207 Registers.DDI_BUF_TRANS_D_S1T1,
208 Registers.DDI_BUF_TRANS_D_S1T2,
209 Registers.DDI_BUF_TRANS_D_S2T1,
210 Registers.DDI_BUF_TRANS_D_S2T2,
211 Registers.DDI_BUF_TRANS_D_S3T1,
212 Registers.DDI_BUF_TRANS_D_S3T2,
213 Registers.DDI_BUF_TRANS_D_S4T1,
214 Registers.DDI_BUF_TRANS_D_S4T2,
215 Registers.DDI_BUF_TRANS_D_S5T1,
216 Registers.DDI_BUF_TRANS_D_S5T2,
217 Registers.DDI_BUF_TRANS_D_S6T1,
218 Registers.DDI_BUF_TRANS_D_S6T2,
219 Registers.DDI_BUF_TRANS_D_S7T1,
220 Registers.DDI_BUF_TRANS_D_S7T2,
221 Registers.DDI_BUF_TRANS_D_S8T1,
222 Registers.DDI_BUF_TRANS_D_S8T2,
223 Registers.DDI_BUF_TRANS_D_S9T1,
224 Registers.DDI_BUF_TRANS_D_S9T2),
Nico Huber83693c82016-10-08 22:17:55 +0200225 DP_TP_CTL => Registers.DP_TP_CTL_D,
226 DP_TP_STATUS => Registers.DP_TP_STATUS_D,
227 PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDID),
228 DIGI_E => DDI_Registers'
229 (BUF_CTL => Registers.DDI_BUF_CTL_E,
Nico Huber01b680f2017-06-09 16:24:22 +0200230 BUF_TRANS => DDI_Buf_Trans_Regs_Array'
231 (Registers.DDI_BUF_TRANS_E_S0T1,
232 Registers.DDI_BUF_TRANS_E_S0T2,
233 Registers.DDI_BUF_TRANS_E_S1T1,
234 Registers.DDI_BUF_TRANS_E_S1T2,
235 Registers.DDI_BUF_TRANS_E_S2T1,
236 Registers.DDI_BUF_TRANS_E_S2T2,
237 Registers.DDI_BUF_TRANS_E_S3T1,
238 Registers.DDI_BUF_TRANS_E_S3T2,
239 Registers.DDI_BUF_TRANS_E_S4T1,
240 Registers.DDI_BUF_TRANS_E_S4T2,
241 Registers.DDI_BUF_TRANS_E_S5T1,
242 Registers.DDI_BUF_TRANS_E_S5T2,
243 Registers.DDI_BUF_TRANS_E_S6T1,
244 Registers.DDI_BUF_TRANS_E_S6T2,
245 Registers.DDI_BUF_TRANS_E_S7T1,
246 Registers.DDI_BUF_TRANS_E_S7T2,
247 Registers.DDI_BUF_TRANS_E_S8T1,
248 Registers.DDI_BUF_TRANS_E_S8T2,
249 Registers.DDI_BUF_TRANS_E_S9T1,
250 Registers.DDI_BUF_TRANS_E_S9T2),
Nico Huber83693c82016-10-08 22:17:55 +0200251 DP_TP_CTL => Registers.DP_TP_CTL_E,
252 DP_TP_STATUS => Registers.DP_TP_STATUS_E,
253 PORT_CLK_SEL => Registers.PORT_CLK_SEL_DDIE));
254
255 ----------------------------------------------------------------------------
256
257 type Values is array (Digital_Port) of Word32;
258 type Shifts is array (Digital_Port) of Natural;
259
260 DPLL_CTRL2_DDIx_CLOCK_OFF : constant Values := Values'
261 (DIGI_A => 1 * 2 ** 15,
262 DIGI_B => 1 * 2 ** 16,
263 DIGI_C => 1 * 2 ** 17,
264 DIGI_D => 1 * 2 ** 18,
265 DIGI_E => 1 * 2 ** 19);
266
267 DPLL_CTRL2_DDIx_SELECT_MASK : constant Values := Values'
268 (DIGI_A => 3 * 2 ** 1,
269 DIGI_B => 3 * 2 ** 4,
270 DIGI_C => 3 * 2 ** 7,
271 DIGI_D => 3 * 2 ** 10,
272 DIGI_E => 3 * 2 ** 13);
273 DPLL_CTRL2_DDIx_SELECT_SHIFT : constant Shifts := Shifts'
274 (DIGI_A => 1,
275 DIGI_B => 4,
276 DIGI_C => 7,
277 DIGI_D => 10,
278 DIGI_E => 13);
279
280 DPLL_CTRL2_DDIx_SELECT_OVERRIDE : constant Values := Values'
281 (DIGI_A => 1 * 2 ** 0,
282 DIGI_B => 1 * 2 ** 3,
283 DIGI_C => 1 * 2 ** 6,
284 DIGI_D => 1 * 2 ** 9,
285 DIGI_E => 1 * 2 ** 12);
286
287 ----------------------------------------------------------------------------
288
289 function DDI_BUF_CTL_TRANS_SELECT
290 (Sel : DDI_BUF_CTL_TRANS_SELECT_T)
291 return Word32
292 is
293 begin
294 return Word32 (Sel) * 2 ** 24;
295 end DDI_BUF_CTL_TRANS_SELECT;
296
297 ----------------------------------------------------------------------------
298
Nico Huber01b680f2017-06-09 16:24:22 +0200299 procedure Initialize
300 is
Nico Huber25fdb152019-02-17 15:54:39 +0100301 Iboost_Value : constant Word32 := Word32 (Config.DDI_Buffer_Iboost);
Nico Huber01b680f2017-06-09 16:24:22 +0200302 begin
303 if Config.Has_DDI_Buffer_Trans then
Nico Huber98a673d2018-05-15 23:46:16 +0200304 declare
305 procedure Program_Buffer_Translations (Port : Digital_Port)
306 is
307 Buffer_Translations : Buf_Trans_Array;
308 begin
309 Buffers.Translations (Buffer_Translations, Port);
310 for I in Buf_Trans_Range loop
311 Registers.Write
312 (Register => DDI_Regs (Port).BUF_TRANS (I),
313 Value => Buffer_Translations (I));
314 end loop;
315 end Program_Buffer_Translations;
316 begin
317 for Port in Digital_Port range DIGI_A .. Config.Last_Digital_Port
318 loop
319 Program_Buffer_Translations (Port);
320 end loop;
321 if Config.Is_FDI_Port (Analog) then
322 Program_Buffer_Translations (DIGI_E);
323 end if;
324 end;
Nico Huber01b680f2017-06-09 16:24:22 +0200325 end if;
Nico Huber58afc202017-06-12 21:34:55 +0200326
327 if Config.Has_Iboost_Config then
328 Registers.Unset_And_Set_Mask
329 (Register => Registers.DISPIO_CR_TX_BMU_CR0,
330 Mask_Unset => DISPIO_CR_TX_BLNC_LEG_DISBL_MASK or
331 DISPIO_CR_TX_BLNC_LEG_SCTL_4_MASK or
332 DISPIO_CR_TX_BLNC_LEG_SCTL_3_MASK or
333 DISPIO_CR_TX_BLNC_LEG_SCTL_2_MASK or
334 DISPIO_CR_TX_BLNC_LEG_SCTL_1_MASK or
335 DISPIO_CR_TX_BLNC_LEG_SCTL_0_MASK,
336 Mask_Set =>
337 Shift_Left (Iboost_Value, DISPIO_CR_TX_BLNC_LEG_SCTL_4_SHIFT) or
338 Shift_Left (Iboost_Value, DISPIO_CR_TX_BLNC_LEG_SCTL_3_SHIFT) or
339 Shift_Left (Iboost_Value, DISPIO_CR_TX_BLNC_LEG_SCTL_2_SHIFT) or
340 Shift_Left (Iboost_Value, DISPIO_CR_TX_BLNC_LEG_SCTL_1_SHIFT) or
341 Shift_Left (Iboost_Value, DISPIO_CR_TX_BLNC_LEG_SCTL_0_SHIFT));
342 end if;
Nico Huber01b680f2017-06-09 16:24:22 +0200343 end Initialize;
344
345 ----------------------------------------------------------------------------
346
Nico Huber83693c82016-10-08 22:17:55 +0200347 function Max_V_Swing
348 (Port : Digital_Port)
349 return DP_Info.DP_Voltage_Swing
350 is
351 begin
352 return
Nico Huber1c3b9282017-02-09 13:57:04 +0100353 (if Config.Has_DDI_PHYs then
354 DDI_Phy.Max_V_Swing
355 elsif (Config.Has_Low_Voltage_Swing and Config.EDP_Low_Voltage_Swing)
Nico Huber83693c82016-10-08 22:17:55 +0200356 and then Port = DIGI_A
357 then
358 DP_Info.VS_Level_3
359 else
360 DP_Info.VS_Level_2);
361 end Max_V_Swing;
362
363 pragma Warnings (GNATprove, Off, "unused variable ""Port""",
364 Reason => "Needed for a common interface");
365 function Max_Pre_Emph
366 (Port : Digital_Port;
367 Train_Set : DP_Info.Train_Set)
368 return DP_Info.DP_Pre_Emph
369 is
370 begin
371 return
Nico Huber1c3b9282017-02-09 13:57:04 +0100372 (if Config.Has_DDI_PHYs then
373 DDI_Phy.Max_Pre_Emph (Train_Set.Voltage_Swing)
374 else
375 (case Train_Set.Voltage_Swing is
376 when DP_Info.VS_Level_0 => DP_Info.Emph_Level_3,
377 when DP_Info.VS_Level_1 => DP_Info.Emph_Level_2,
378 when DP_Info.VS_Level_2 => DP_Info.Emph_Level_1,
379 when others => DP_Info.Emph_Level_0));
Nico Huber83693c82016-10-08 22:17:55 +0200380 end Max_Pre_Emph;
381 pragma Warnings (GNATprove, On, "unused variable ""Port""");
382
383 ----------------------------------------------------------------------------
384
385 procedure Set_TP_CTL
386 (Port : Digital_Port;
387 Link : DP_Link;
388 Pattern : DP_Info.Training_Pattern)
389 is
390 DP_TP_CTL_Enhanced_Frame : Word32 := 0;
391 begin
392 if Link.Enhanced_Framing then
393 DP_TP_CTL_Enhanced_Frame := DP_TP_CTL_ENHANCED_FRAME_ENABLE;
394 end if;
395
396 Registers.Write
397 (Register => DDI_Regs (Port).DP_TP_CTL,
398 Value => DP_TP_CTL_TRANSPORT_ENABLE or
399 DP_TP_CTL_Enhanced_Frame or
400 DP_TP_CTL_LINK_TRAIN (Pattern));
401 end Set_TP_CTL;
402
403 procedure Set_Training_Pattern
404 (Port : Digital_Port;
405 Link : DP_Link;
406 Pattern : DP_Info.Training_Pattern)
407 is
408 use type DP_Info.Training_Pattern;
409 begin
410 if Pattern < DP_Info.TP_Idle then
411 Set_TP_CTL (Port, Link, Pattern);
412 else
413 -- send at least 5 idle patterns
414 Set_TP_CTL (Port, Link, DP_Info.TP_Idle);
415
416 -- switch to normal frame delivery
417 if Config.End_EDP_Training_Late and then Port = DIGI_A then
418 null; -- do it later in Post_On procedure
419 -- TODO: if there are problems getting the pipe up,
420 -- wait here some time
421 -- Time.U_Delay (100);
422 else
423 if Port /= DIGI_A then
424 Registers.Wait_Set_Mask
425 (Register => DDI_Regs (Port).DP_TP_STATUS,
426 Mask => DP_TP_STATUS_MIN_IDLES_SENT);
427 end if;
428 Set_TP_CTL (Port, Link, DP_Info.TP_None);
429 end if;
430 end if;
431 end Set_Training_Pattern;
432
433 procedure Set_Signal_Levels
434 (Port : Digital_Port;
435 Link : DP_Link;
436 Train_Set : DP_Info.Train_Set)
437 is
438 Was_Enabled : Boolean;
439 Trans_Select : DDI_BUF_CTL_TRANS_SELECT_T;
440 begin
Nico Huber83693c82016-10-08 22:17:55 +0200441 Registers.Is_Set_Mask
442 (Register => DDI_Regs (Port).BUF_CTL,
443 Mask => DDI_BUF_CTL_BUFFER_ENABLE,
444 Result => Was_Enabled);
445
Nico Huber1c3b9282017-02-09 13:57:04 +0100446 if Config.Has_DDI_PHYs then
447 Trans_Select := 0;
448 else
449 case Train_Set.Voltage_Swing is
450 when DP_Info.VS_Level_0 =>
451 case Train_Set.Pre_Emph is
452 when DP_Info.Emph_Level_0 => Trans_Select := 0;
453 when DP_Info.Emph_Level_1 => Trans_Select := 1;
454 when DP_Info.Emph_Level_2 => Trans_Select := 2;
455 when DP_Info.Emph_Level_3 => Trans_Select := 3;
456 end case;
457 when DP_Info.VS_Level_1 =>
458 case Train_Set.Pre_Emph is
459 when DP_Info.Emph_Level_0 => Trans_Select := 4;
460 when DP_Info.Emph_Level_1 => Trans_Select := 5;
461 when DP_Info.Emph_Level_2 => Trans_Select := 6;
462 when others => Trans_Select := 0;
463 end case;
464 when DP_Info.VS_Level_2 =>
465 case Train_Set.Pre_Emph is
466 when DP_Info.Emph_Level_0 => Trans_Select := 7;
467 when DP_Info.Emph_Level_1 => Trans_Select := 8;
468 when others => Trans_Select := 0;
469 end case;
470 when DP_Info.VS_Level_3 =>
471 case Train_Set.Pre_Emph is
472 when DP_Info.Emph_Level_0 => Trans_Select := 9;
473 when others => Trans_Select := 0;
474 end case;
475 end case;
476 end if;
477
Nico Huber83693c82016-10-08 22:17:55 +0200478 -- enable DDI buffer
479 Registers.Unset_And_Set_Mask
480 (Register => DDI_Regs (Port).BUF_CTL,
481 Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
482 DDI_BUF_CTL_PORT_REVERSAL or
483 DDI_BUF_CTL_PORT_WIDTH_MASK,
484 Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE or
485 DDI_BUF_CTL_TRANS_SELECT (Trans_Select) or
486 DDI_BUF_CTL_PORT_WIDTH (Link.Lane_Count));
487 Registers.Posting_Read (DDI_Regs (Port).BUF_CTL);
488
489 if not Was_Enabled then
490 Time.U_Delay (600); -- wait >= 518us (intel spec)
491 end if;
Nico Huber1c3b9282017-02-09 13:57:04 +0100492
493 if Config.Has_DDI_PHYs then
494 DDI_Phy.Set_DP_Signal_Levels (Port, Train_Set);
495 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200496 end Set_Signal_Levels;
497
498 ----------------------------------------------------------------------------
499
500 procedure Digital_Off (Port : Digital_Port)
501 is
502 Enabled : Boolean;
503 begin
504 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
505
506 Registers.Is_Set_Mask
507 (Register => DDI_Regs (Port).BUF_CTL,
508 Mask => DDI_BUF_CTL_BUFFER_ENABLE,
509 Result => Enabled);
510
511 if Enabled then
512 Registers.Unset_Mask
513 (Register => DDI_Regs (Port).BUF_CTL,
514 Mask => DDI_BUF_CTL_BUFFER_ENABLE);
515 end if;
516
517 Registers.Unset_Mask
518 (Register => DDI_Regs (Port).DP_TP_CTL,
519 Mask => DP_TP_CTL_TRANSPORT_ENABLE);
520
521 if Enabled then
522 Registers.Wait_Set_Mask
523 (Register => DDI_Regs (Port).BUF_CTL,
524 Mask => DDI_BUF_CTL_IDLE_STATUS);
525 end if;
526
527 if Config.Has_Per_DDI_Clock_Sel then
528 Registers.Write
529 (Register => DDI_Regs (Port).PORT_CLK_SEL,
530 Value => PORT_CLK_SEL_NONE);
Nico Huber1c3b9282017-02-09 13:57:04 +0100531 elsif not Config.Has_DDI_PHYs then
Nico Huber83693c82016-10-08 22:17:55 +0200532 Registers.Set_Mask
533 (Register => Registers.DPLL_CTRL2,
534 Mask => DPLL_CTRL2_DDIx_CLOCK_OFF (Port));
535 end if;
536 end Digital_Off;
537
538 ----------------------------------------------------------------------------
539
540 procedure Train_FDI
541 (Port_Cfg : in Port_Config;
542 Success : out Boolean)
543 is
544 begin
545 PCH.FDI.Pre_Train (PCH.FDI_A, Port_Cfg);
546
547 -- always use SPLL for FDI
548 SPLL.On;
549 Registers.Write
550 (Register => DDI_Regs (DIGI_E).PORT_CLK_SEL,
551 Value => PORT_CLK_SEL_SPLL);
552
553 -- try each preemph/voltage pair twice
554 for Trans2 in Natural range 0 .. DDI_BUF_CTL_TRANS_SELECT_T'Last * 2 + 1
555 loop
556 Registers.Write
557 (Register => DDI_Regs (DIGI_E).DP_TP_CTL,
558 Value => DP_TP_CTL_TRANSPORT_ENABLE or
559 DP_TP_CTL_ENHANCED_FRAME_ENABLE or
560 DP_TP_CTL_FDI_AUTOTRAIN or
561 DP_TP_CTL_LINK_TRAIN_PAT1);
562
563 Registers.Unset_And_Set_Mask
564 (Register => DDI_Regs (DIGI_E).BUF_CTL,
565 Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
566 DDI_BUF_CTL_PORT_REVERSAL or
567 DDI_BUF_CTL_PORT_WIDTH_MASK,
568 Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE or
569 DDI_BUF_CTL_TRANS_SELECT (Trans2 / 2) or
570 DDI_BUF_CTL_PORT_WIDTH (Port_Cfg.FDI.Lane_Count));
571 Registers.Posting_Read (DDI_Regs (DIGI_E).BUF_CTL);
572 Time.U_Delay (600); -- wait >= 518us (intel spec)
573
574 PCH.FDI.Auto_Train (PCH.FDI_A);
575 Registers.Is_Set_Mask
576 (Register => DDI_Regs (DIGI_E).DP_TP_STATUS,
577 Mask => DP_TP_STATUS_FDI_AUTO_TRAIN_DONE,
578 Result => Success);
579 exit when Success;
580
581 Registers.Unset_Mask
582 (Register => DDI_Regs (DIGI_E).BUF_CTL,
583 Mask => DDI_BUF_CTL_BUFFER_ENABLE);
584 Registers.Posting_Read (DDI_Regs (DIGI_E).BUF_CTL);
585
586 Registers.Unset_And_Set_Mask
587 (Register => DDI_Regs (DIGI_E).DP_TP_CTL,
588 Mask_Unset => DP_TP_CTL_TRANSPORT_ENABLE or
589 DP_TP_CTL_LINK_TRAIN_MASK,
590 Mask_Set => DP_TP_CTL_LINK_TRAIN_PAT1);
591 Registers.Posting_Read (DDI_Regs (DIGI_E).DP_TP_CTL);
592
593 Registers.Wait_Set_Mask
594 (Register => DDI_Regs (DIGI_E).BUF_CTL,
595 Mask => DDI_BUF_CTL_IDLE_STATUS);
596
597 PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Lanes_Off);
598 end loop;
599
600 if Success then
601 -- start normal frame delivery
602 Registers.Write
603 (Register => DDI_Regs (DIGI_E).DP_TP_CTL,
604 Value => DP_TP_CTL_TRANSPORT_ENABLE or
605 DP_TP_CTL_ENHANCED_FRAME_ENABLE or
606 DP_TP_CTL_FDI_AUTOTRAIN or
607 DP_TP_CTL_LINK_TRAIN_NORMAL);
608 else
609 Registers.Write
610 (Register => DDI_Regs (DIGI_E).PORT_CLK_SEL,
611 Value => PORT_CLK_SEL_NONE);
612 SPLL.Off;
613
614 PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Clock_Off);
615 end if;
616 end Train_FDI;
617
618 ----------------------------------------------------------------------------
619
620 procedure Pre_On
621 (Port_Cfg : in Port_Config;
622 PLL_Hint : in Word32;
623 Success : out Boolean)
624 is
625 function To_DP (Port : Digital_Port) return DP_Port
626 is
627 begin
628 return
629 (case Port is
630 when DIGI_A => DP_A,
631 when DIGI_B => DP_B,
632 when DIGI_C => DP_C,
633 when DIGI_D => DP_D,
634 when others => DP_Port'First);
635 end To_DP;
636 package Training is new DP_Training
637 (TPS3_Supported => True,
638 T => Digital_Port,
639 Aux_T => DP_Port,
640 Aux_Ch => DP_Aux_Ch,
641 DP_Info => DP_Info,
642 To_Aux => To_DP,
643 Max_V_Swing => Max_V_Swing,
644 Max_Pre_Emph => Max_Pre_Emph,
645 Set_Pattern => Set_Training_Pattern,
646 Set_Signal_Levels => Set_Signal_Levels,
647 Off => Digital_Off);
648 begin
649 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
650
651 if Port_Cfg.Display = VGA then
652 Train_FDI (Port_Cfg, Success);
653 else
654 -- direct configured PLL output to this port
655 if Config.Has_Per_DDI_Clock_Sel then
656 Registers.Write
657 (Register => DDI_Regs (Port_Cfg.Port).PORT_CLK_SEL,
658 Value => PLL_Hint);
Nico Huber1c3b9282017-02-09 13:57:04 +0100659 elsif not Config.Has_DDI_PHYs then
Nico Huber83693c82016-10-08 22:17:55 +0200660 Registers.Unset_And_Set_Mask
661 (Register => Registers.DPLL_CTRL2,
662 Mask_Unset => DPLL_CTRL2_DDIx_CLOCK_OFF (Port_Cfg.Port) or
663 DPLL_CTRL2_DDIx_SELECT_MASK (Port_Cfg.Port),
664 Mask_Set => Shift_Left
665 (PLL_Hint,
666 DPLL_CTRL2_DDIx_SELECT_SHIFT (Port_Cfg.Port))
667 or
668 DPLL_CTRL2_DDIx_SELECT_OVERRIDE (Port_Cfg.Port));
669 end if;
670
671 if Port_Cfg.Display = DP then
672 Training.Train_DP
673 (Port => Port_Cfg.Port,
674 Link => Port_Cfg.DP,
675 Success => Success);
Nico Huber1c3b9282017-02-09 13:57:04 +0100676 elsif Config.Has_DDI_PHYs and then
677 Port_Cfg.Display = HDMI and then
678 Port_Cfg.Port in DDI_Phy.DDI_Phy_Port
679 then
Nico Huber247adf32017-06-12 14:39:11 +0200680 declare
681 HDMI_Level : constant DDI_Phy.HDMI_Buf_Trans_Range :=
Nico Huber117db372018-06-09 17:56:05 +0200682 (if Config.Have_HDMI_Buf_Override
Nico Huber247adf32017-06-12 14:39:11 +0200683 then Config.DDI_HDMI_Buffer_Translation
684 else Config.Default_DDI_HDMI_Buffer_Translation);
685 begin
686 DDI_Phy.Set_HDMI_Signal_Levels (Port_Cfg.Port, HDMI_Level);
687 Success := True;
688 end;
Nico Huber83693c82016-10-08 22:17:55 +0200689 else
690 Success := True;
691 end if;
692 end if;
693 end Pre_On;
694
695 ----------------------------------------------------------------------------
696
697 procedure Post_On (Port_Cfg : Port_Config)
698 is
699 begin
700 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
701
702 if Port_Cfg.Port = DIGI_A then
703 if Config.End_EDP_Training_Late then
704 Registers.Unset_And_Set_Mask
705 (Register => DDI_Regs (DIGI_A).DP_TP_CTL,
706 Mask_Unset => DP_TP_CTL_LINK_TRAIN_MASK,
707 Mask_Set => DP_TP_CTL_LINK_TRAIN_NORMAL);
708 end if;
709 end if;
710
711 case Port_Cfg.Display is
712 when HDMI =>
713 Registers.Unset_And_Set_Mask
714 (Register => DDI_Regs (Port_Cfg.Port).BUF_CTL,
715 Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
716 DDI_BUF_CTL_PORT_REVERSAL,
717 Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE);
718 Time.U_Delay (600); -- wait >= 518us (intel spec)
719 when VGA =>
720 PCH.VGA.Clock_On (Port_Cfg.Mode);
721 PCH.Transcoder.On (Port_Cfg, PCH.FDI_A, 0);
722 PCH.VGA.On
723 (Port => PCH.FDI_A,
724 Mode => Port_Cfg.Mode);
725 when others =>
726 null;
727 end case;
728 end Post_On;
729
730 ----------------------------------------------------------------------------
731
732 procedure Off (Port : Digital_Port)
733 is
734 begin
735 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
736
Nico Huber208857d2017-07-29 21:30:24 +0200737 if Config.Has_PCH_DAC and then Port = DIGI_E then
Nico Huber83693c82016-10-08 22:17:55 +0200738 PCH.VGA.Off;
739 PCH.Transcoder.Off (PCH.FDI_A);
740 -- PCH.VGA.Clock_Off; -- Can't tell what Linux does, if anything.
741 PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Rx_Off);
742 end if;
743
744 Digital_Off (Port);
745
746 if Port = DIGI_E then
747 SPLL.Off;
Nico Huber208857d2017-07-29 21:30:24 +0200748 if Config.Has_PCH_DAC then
749 PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Clock_Off);
750 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200751 end if;
752 end Off;
753
Nico Huber3a0e2a02017-07-19 14:41:46 +0200754 ----------------------------------------------------------------------------
755
756 procedure Post_Reset_Off
757 is
758 Clocks_Off : Word32 := 0;
759 begin
760 if not Config.Has_Per_DDI_Clock_Sel and not Config.Has_DDI_PHYs then
761 for Port in Digital_Port loop
762 Clocks_Off := Clocks_Off or DPLL_CTRL2_DDIx_CLOCK_OFF (Port);
763 end loop;
764 Registers.Set_Mask (Registers.DPLL_CTRL2, Clocks_Off);
765 end if;
766 end Post_Reset_Off;
767
Nico Huber83693c82016-10-08 22:17:55 +0200768end HW.GFX.GMA.Connectors.DDI;