blob: b6d7284f8f25a1f965d80fba004050d413ab44e9 [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 Program_Buffer_Translations (Port : Digital_Port)
300 is
301 Buffer_Translations : Buf_Trans_Array;
302 begin
303 Buffers.Translations (Buffer_Translations, Port);
304 for I in Buf_Trans_Range loop
305 Registers.Write
306 (Register => DDI_Regs (Port).BUF_TRANS (I),
307 Value => Buffer_Translations (I));
308 end loop;
309 end Program_Buffer_Translations;
310
311 procedure Initialize
312 is
Nico Huber58afc202017-06-12 21:34:55 +0200313 Iboost_Value : constant Word32 := 1;
Nico Huber01b680f2017-06-09 16:24:22 +0200314 begin
315 if Config.Has_DDI_Buffer_Trans then
316 for Port in Digital_Port range DIGI_A .. Config.Last_Digital_Port loop
317 Program_Buffer_Translations (Port);
318 end loop;
319 if Config.Is_FDI_Port (Analog) then
320 Program_Buffer_Translations (DIGI_E);
321 end if;
322 end if;
Nico Huber58afc202017-06-12 21:34:55 +0200323
324 if Config.Has_Iboost_Config then
325 Registers.Unset_And_Set_Mask
326 (Register => Registers.DISPIO_CR_TX_BMU_CR0,
327 Mask_Unset => DISPIO_CR_TX_BLNC_LEG_DISBL_MASK or
328 DISPIO_CR_TX_BLNC_LEG_SCTL_4_MASK or
329 DISPIO_CR_TX_BLNC_LEG_SCTL_3_MASK or
330 DISPIO_CR_TX_BLNC_LEG_SCTL_2_MASK or
331 DISPIO_CR_TX_BLNC_LEG_SCTL_1_MASK or
332 DISPIO_CR_TX_BLNC_LEG_SCTL_0_MASK,
333 Mask_Set =>
334 Shift_Left (Iboost_Value, DISPIO_CR_TX_BLNC_LEG_SCTL_4_SHIFT) or
335 Shift_Left (Iboost_Value, DISPIO_CR_TX_BLNC_LEG_SCTL_3_SHIFT) or
336 Shift_Left (Iboost_Value, DISPIO_CR_TX_BLNC_LEG_SCTL_2_SHIFT) or
337 Shift_Left (Iboost_Value, DISPIO_CR_TX_BLNC_LEG_SCTL_1_SHIFT) or
338 Shift_Left (Iboost_Value, DISPIO_CR_TX_BLNC_LEG_SCTL_0_SHIFT));
339 end if;
Nico Huber01b680f2017-06-09 16:24:22 +0200340 end Initialize;
341
342 ----------------------------------------------------------------------------
343
Nico Huber83693c82016-10-08 22:17:55 +0200344 function Max_V_Swing
345 (Port : Digital_Port)
346 return DP_Info.DP_Voltage_Swing
347 is
348 begin
349 return
Nico Huber1c3b9282017-02-09 13:57:04 +0100350 (if Config.Has_DDI_PHYs then
351 DDI_Phy.Max_V_Swing
352 elsif (Config.Has_Low_Voltage_Swing and Config.EDP_Low_Voltage_Swing)
Nico Huber83693c82016-10-08 22:17:55 +0200353 and then Port = DIGI_A
354 then
355 DP_Info.VS_Level_3
356 else
357 DP_Info.VS_Level_2);
358 end Max_V_Swing;
359
360 pragma Warnings (GNATprove, Off, "unused variable ""Port""",
361 Reason => "Needed for a common interface");
362 function Max_Pre_Emph
363 (Port : Digital_Port;
364 Train_Set : DP_Info.Train_Set)
365 return DP_Info.DP_Pre_Emph
366 is
367 begin
368 return
Nico Huber1c3b9282017-02-09 13:57:04 +0100369 (if Config.Has_DDI_PHYs then
370 DDI_Phy.Max_Pre_Emph (Train_Set.Voltage_Swing)
371 else
372 (case Train_Set.Voltage_Swing is
373 when DP_Info.VS_Level_0 => DP_Info.Emph_Level_3,
374 when DP_Info.VS_Level_1 => DP_Info.Emph_Level_2,
375 when DP_Info.VS_Level_2 => DP_Info.Emph_Level_1,
376 when others => DP_Info.Emph_Level_0));
Nico Huber83693c82016-10-08 22:17:55 +0200377 end Max_Pre_Emph;
378 pragma Warnings (GNATprove, On, "unused variable ""Port""");
379
380 ----------------------------------------------------------------------------
381
382 procedure Set_TP_CTL
383 (Port : Digital_Port;
384 Link : DP_Link;
385 Pattern : DP_Info.Training_Pattern)
386 is
387 DP_TP_CTL_Enhanced_Frame : Word32 := 0;
388 begin
389 if Link.Enhanced_Framing then
390 DP_TP_CTL_Enhanced_Frame := DP_TP_CTL_ENHANCED_FRAME_ENABLE;
391 end if;
392
393 Registers.Write
394 (Register => DDI_Regs (Port).DP_TP_CTL,
395 Value => DP_TP_CTL_TRANSPORT_ENABLE or
396 DP_TP_CTL_Enhanced_Frame or
397 DP_TP_CTL_LINK_TRAIN (Pattern));
398 end Set_TP_CTL;
399
400 procedure Set_Training_Pattern
401 (Port : Digital_Port;
402 Link : DP_Link;
403 Pattern : DP_Info.Training_Pattern)
404 is
405 use type DP_Info.Training_Pattern;
406 begin
407 if Pattern < DP_Info.TP_Idle then
408 Set_TP_CTL (Port, Link, Pattern);
409 else
410 -- send at least 5 idle patterns
411 Set_TP_CTL (Port, Link, DP_Info.TP_Idle);
412
413 -- switch to normal frame delivery
414 if Config.End_EDP_Training_Late and then Port = DIGI_A then
415 null; -- do it later in Post_On procedure
416 -- TODO: if there are problems getting the pipe up,
417 -- wait here some time
418 -- Time.U_Delay (100);
419 else
420 if Port /= DIGI_A then
421 Registers.Wait_Set_Mask
422 (Register => DDI_Regs (Port).DP_TP_STATUS,
423 Mask => DP_TP_STATUS_MIN_IDLES_SENT);
424 end if;
425 Set_TP_CTL (Port, Link, DP_Info.TP_None);
426 end if;
427 end if;
428 end Set_Training_Pattern;
429
430 procedure Set_Signal_Levels
431 (Port : Digital_Port;
432 Link : DP_Link;
433 Train_Set : DP_Info.Train_Set)
434 is
435 Was_Enabled : Boolean;
436 Trans_Select : DDI_BUF_CTL_TRANS_SELECT_T;
437 begin
Nico Huber83693c82016-10-08 22:17:55 +0200438 Registers.Is_Set_Mask
439 (Register => DDI_Regs (Port).BUF_CTL,
440 Mask => DDI_BUF_CTL_BUFFER_ENABLE,
441 Result => Was_Enabled);
442
Nico Huber1c3b9282017-02-09 13:57:04 +0100443 if Config.Has_DDI_PHYs then
444 Trans_Select := 0;
445 else
446 case Train_Set.Voltage_Swing is
447 when DP_Info.VS_Level_0 =>
448 case Train_Set.Pre_Emph is
449 when DP_Info.Emph_Level_0 => Trans_Select := 0;
450 when DP_Info.Emph_Level_1 => Trans_Select := 1;
451 when DP_Info.Emph_Level_2 => Trans_Select := 2;
452 when DP_Info.Emph_Level_3 => Trans_Select := 3;
453 end case;
454 when DP_Info.VS_Level_1 =>
455 case Train_Set.Pre_Emph is
456 when DP_Info.Emph_Level_0 => Trans_Select := 4;
457 when DP_Info.Emph_Level_1 => Trans_Select := 5;
458 when DP_Info.Emph_Level_2 => Trans_Select := 6;
459 when others => Trans_Select := 0;
460 end case;
461 when DP_Info.VS_Level_2 =>
462 case Train_Set.Pre_Emph is
463 when DP_Info.Emph_Level_0 => Trans_Select := 7;
464 when DP_Info.Emph_Level_1 => Trans_Select := 8;
465 when others => Trans_Select := 0;
466 end case;
467 when DP_Info.VS_Level_3 =>
468 case Train_Set.Pre_Emph is
469 when DP_Info.Emph_Level_0 => Trans_Select := 9;
470 when others => Trans_Select := 0;
471 end case;
472 end case;
473 end if;
474
Nico Huber83693c82016-10-08 22:17:55 +0200475 -- enable DDI buffer
476 Registers.Unset_And_Set_Mask
477 (Register => DDI_Regs (Port).BUF_CTL,
478 Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
479 DDI_BUF_CTL_PORT_REVERSAL or
480 DDI_BUF_CTL_PORT_WIDTH_MASK,
481 Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE or
482 DDI_BUF_CTL_TRANS_SELECT (Trans_Select) or
483 DDI_BUF_CTL_PORT_WIDTH (Link.Lane_Count));
484 Registers.Posting_Read (DDI_Regs (Port).BUF_CTL);
485
486 if not Was_Enabled then
487 Time.U_Delay (600); -- wait >= 518us (intel spec)
488 end if;
Nico Huber1c3b9282017-02-09 13:57:04 +0100489
490 if Config.Has_DDI_PHYs then
491 DDI_Phy.Set_DP_Signal_Levels (Port, Train_Set);
492 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200493 end Set_Signal_Levels;
494
495 ----------------------------------------------------------------------------
496
497 procedure Digital_Off (Port : Digital_Port)
498 is
499 Enabled : Boolean;
500 begin
501 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
502
503 Registers.Is_Set_Mask
504 (Register => DDI_Regs (Port).BUF_CTL,
505 Mask => DDI_BUF_CTL_BUFFER_ENABLE,
506 Result => Enabled);
507
508 if Enabled then
509 Registers.Unset_Mask
510 (Register => DDI_Regs (Port).BUF_CTL,
511 Mask => DDI_BUF_CTL_BUFFER_ENABLE);
512 end if;
513
514 Registers.Unset_Mask
515 (Register => DDI_Regs (Port).DP_TP_CTL,
516 Mask => DP_TP_CTL_TRANSPORT_ENABLE);
517
518 if Enabled then
519 Registers.Wait_Set_Mask
520 (Register => DDI_Regs (Port).BUF_CTL,
521 Mask => DDI_BUF_CTL_IDLE_STATUS);
522 end if;
523
524 if Config.Has_Per_DDI_Clock_Sel then
525 Registers.Write
526 (Register => DDI_Regs (Port).PORT_CLK_SEL,
527 Value => PORT_CLK_SEL_NONE);
Nico Huber1c3b9282017-02-09 13:57:04 +0100528 elsif not Config.Has_DDI_PHYs then
Nico Huber83693c82016-10-08 22:17:55 +0200529 Registers.Set_Mask
530 (Register => Registers.DPLL_CTRL2,
531 Mask => DPLL_CTRL2_DDIx_CLOCK_OFF (Port));
532 end if;
533 end Digital_Off;
534
535 ----------------------------------------------------------------------------
536
537 procedure Train_FDI
538 (Port_Cfg : in Port_Config;
539 Success : out Boolean)
540 is
541 begin
542 PCH.FDI.Pre_Train (PCH.FDI_A, Port_Cfg);
543
544 -- always use SPLL for FDI
545 SPLL.On;
546 Registers.Write
547 (Register => DDI_Regs (DIGI_E).PORT_CLK_SEL,
548 Value => PORT_CLK_SEL_SPLL);
549
550 -- try each preemph/voltage pair twice
551 for Trans2 in Natural range 0 .. DDI_BUF_CTL_TRANS_SELECT_T'Last * 2 + 1
552 loop
553 Registers.Write
554 (Register => DDI_Regs (DIGI_E).DP_TP_CTL,
555 Value => DP_TP_CTL_TRANSPORT_ENABLE or
556 DP_TP_CTL_ENHANCED_FRAME_ENABLE or
557 DP_TP_CTL_FDI_AUTOTRAIN or
558 DP_TP_CTL_LINK_TRAIN_PAT1);
559
560 Registers.Unset_And_Set_Mask
561 (Register => DDI_Regs (DIGI_E).BUF_CTL,
562 Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
563 DDI_BUF_CTL_PORT_REVERSAL or
564 DDI_BUF_CTL_PORT_WIDTH_MASK,
565 Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE or
566 DDI_BUF_CTL_TRANS_SELECT (Trans2 / 2) or
567 DDI_BUF_CTL_PORT_WIDTH (Port_Cfg.FDI.Lane_Count));
568 Registers.Posting_Read (DDI_Regs (DIGI_E).BUF_CTL);
569 Time.U_Delay (600); -- wait >= 518us (intel spec)
570
571 PCH.FDI.Auto_Train (PCH.FDI_A);
572 Registers.Is_Set_Mask
573 (Register => DDI_Regs (DIGI_E).DP_TP_STATUS,
574 Mask => DP_TP_STATUS_FDI_AUTO_TRAIN_DONE,
575 Result => Success);
576 exit when Success;
577
578 Registers.Unset_Mask
579 (Register => DDI_Regs (DIGI_E).BUF_CTL,
580 Mask => DDI_BUF_CTL_BUFFER_ENABLE);
581 Registers.Posting_Read (DDI_Regs (DIGI_E).BUF_CTL);
582
583 Registers.Unset_And_Set_Mask
584 (Register => DDI_Regs (DIGI_E).DP_TP_CTL,
585 Mask_Unset => DP_TP_CTL_TRANSPORT_ENABLE or
586 DP_TP_CTL_LINK_TRAIN_MASK,
587 Mask_Set => DP_TP_CTL_LINK_TRAIN_PAT1);
588 Registers.Posting_Read (DDI_Regs (DIGI_E).DP_TP_CTL);
589
590 Registers.Wait_Set_Mask
591 (Register => DDI_Regs (DIGI_E).BUF_CTL,
592 Mask => DDI_BUF_CTL_IDLE_STATUS);
593
594 PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Lanes_Off);
595 end loop;
596
597 if Success then
598 -- start normal frame delivery
599 Registers.Write
600 (Register => DDI_Regs (DIGI_E).DP_TP_CTL,
601 Value => DP_TP_CTL_TRANSPORT_ENABLE or
602 DP_TP_CTL_ENHANCED_FRAME_ENABLE or
603 DP_TP_CTL_FDI_AUTOTRAIN or
604 DP_TP_CTL_LINK_TRAIN_NORMAL);
605 else
606 Registers.Write
607 (Register => DDI_Regs (DIGI_E).PORT_CLK_SEL,
608 Value => PORT_CLK_SEL_NONE);
609 SPLL.Off;
610
611 PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Clock_Off);
612 end if;
613 end Train_FDI;
614
615 ----------------------------------------------------------------------------
616
617 procedure Pre_On
618 (Port_Cfg : in Port_Config;
619 PLL_Hint : in Word32;
620 Success : out Boolean)
621 is
622 function To_DP (Port : Digital_Port) return DP_Port
623 is
624 begin
625 return
626 (case Port is
627 when DIGI_A => DP_A,
628 when DIGI_B => DP_B,
629 when DIGI_C => DP_C,
630 when DIGI_D => DP_D,
631 when others => DP_Port'First);
632 end To_DP;
633 package Training is new DP_Training
634 (TPS3_Supported => True,
635 T => Digital_Port,
636 Aux_T => DP_Port,
637 Aux_Ch => DP_Aux_Ch,
638 DP_Info => DP_Info,
639 To_Aux => To_DP,
640 Max_V_Swing => Max_V_Swing,
641 Max_Pre_Emph => Max_Pre_Emph,
642 Set_Pattern => Set_Training_Pattern,
643 Set_Signal_Levels => Set_Signal_Levels,
644 Off => Digital_Off);
645 begin
646 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
647
648 if Port_Cfg.Display = VGA then
649 Train_FDI (Port_Cfg, Success);
650 else
651 -- direct configured PLL output to this port
652 if Config.Has_Per_DDI_Clock_Sel then
653 Registers.Write
654 (Register => DDI_Regs (Port_Cfg.Port).PORT_CLK_SEL,
655 Value => PLL_Hint);
Nico Huber1c3b9282017-02-09 13:57:04 +0100656 elsif not Config.Has_DDI_PHYs then
Nico Huber83693c82016-10-08 22:17:55 +0200657 Registers.Unset_And_Set_Mask
658 (Register => Registers.DPLL_CTRL2,
659 Mask_Unset => DPLL_CTRL2_DDIx_CLOCK_OFF (Port_Cfg.Port) or
660 DPLL_CTRL2_DDIx_SELECT_MASK (Port_Cfg.Port),
661 Mask_Set => Shift_Left
662 (PLL_Hint,
663 DPLL_CTRL2_DDIx_SELECT_SHIFT (Port_Cfg.Port))
664 or
665 DPLL_CTRL2_DDIx_SELECT_OVERRIDE (Port_Cfg.Port));
666 end if;
667
668 if Port_Cfg.Display = DP then
669 Training.Train_DP
670 (Port => Port_Cfg.Port,
671 Link => Port_Cfg.DP,
672 Success => Success);
Nico Huber1c3b9282017-02-09 13:57:04 +0100673 elsif Config.Has_DDI_PHYs and then
674 Port_Cfg.Display = HDMI and then
675 Port_Cfg.Port in DDI_Phy.DDI_Phy_Port
676 then
Nico Huber247adf32017-06-12 14:39:11 +0200677 declare
678 HDMI_Level : constant DDI_Phy.HDMI_Buf_Trans_Range :=
679 (if Config.DDI_HDMI_Buffer_Translation
680 in DDI_Phy.HDMI_Buf_Trans_Range
681 then Config.DDI_HDMI_Buffer_Translation
682 else Config.Default_DDI_HDMI_Buffer_Translation);
683 begin
684 DDI_Phy.Set_HDMI_Signal_Levels (Port_Cfg.Port, HDMI_Level);
685 Success := True;
686 end;
Nico Huber83693c82016-10-08 22:17:55 +0200687 else
688 Success := True;
689 end if;
690 end if;
691 end Pre_On;
692
693 ----------------------------------------------------------------------------
694
695 procedure Post_On (Port_Cfg : Port_Config)
696 is
697 begin
698 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
699
700 if Port_Cfg.Port = DIGI_A then
701 if Config.End_EDP_Training_Late then
702 Registers.Unset_And_Set_Mask
703 (Register => DDI_Regs (DIGI_A).DP_TP_CTL,
704 Mask_Unset => DP_TP_CTL_LINK_TRAIN_MASK,
705 Mask_Set => DP_TP_CTL_LINK_TRAIN_NORMAL);
706 end if;
707 end if;
708
709 case Port_Cfg.Display is
710 when HDMI =>
711 Registers.Unset_And_Set_Mask
712 (Register => DDI_Regs (Port_Cfg.Port).BUF_CTL,
713 Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
714 DDI_BUF_CTL_PORT_REVERSAL,
715 Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE);
716 Time.U_Delay (600); -- wait >= 518us (intel spec)
717 when VGA =>
718 PCH.VGA.Clock_On (Port_Cfg.Mode);
719 PCH.Transcoder.On (Port_Cfg, PCH.FDI_A, 0);
720 PCH.VGA.On
721 (Port => PCH.FDI_A,
722 Mode => Port_Cfg.Mode);
723 when others =>
724 null;
725 end case;
726 end Post_On;
727
728 ----------------------------------------------------------------------------
729
730 procedure Off (Port : Digital_Port)
731 is
732 begin
733 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
734
Nico Huber208857d2017-07-29 21:30:24 +0200735 if Config.Has_PCH_DAC and then Port = DIGI_E then
Nico Huber83693c82016-10-08 22:17:55 +0200736 PCH.VGA.Off;
737 PCH.Transcoder.Off (PCH.FDI_A);
738 -- PCH.VGA.Clock_Off; -- Can't tell what Linux does, if anything.
739 PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Rx_Off);
740 end if;
741
742 Digital_Off (Port);
743
744 if Port = DIGI_E then
745 SPLL.Off;
Nico Huber208857d2017-07-29 21:30:24 +0200746 if Config.Has_PCH_DAC then
747 PCH.FDI.Off (PCH.FDI_A, PCH.FDI.Clock_Off);
748 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200749 end if;
750 end Off;
751
Nico Huber3a0e2a02017-07-19 14:41:46 +0200752 ----------------------------------------------------------------------------
753
754 procedure Post_Reset_Off
755 is
756 Clocks_Off : Word32 := 0;
757 begin
758 if not Config.Has_Per_DDI_Clock_Sel and not Config.Has_DDI_PHYs then
759 for Port in Digital_Port loop
760 Clocks_Off := Clocks_Off or DPLL_CTRL2_DDIx_CLOCK_OFF (Port);
761 end loop;
762 Registers.Set_Mask (Registers.DPLL_CTRL2, Clocks_Off);
763 end if;
764 end Post_Reset_Off;
765
Nico Huber83693c82016-10-08 22:17:55 +0200766end HW.GFX.GMA.Connectors.DDI;