blob: 27c8d8afae0b12026092a7f1b070943d0bf30057 [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;
16
17with HW.Debug;
18with GNAT.Source_Info;
19
20with HW.GFX.GMA.Config;
21with HW.GFX.GMA.Registers;
Arthur Heymansd1988d12018-03-28 16:27:57 +020022with HW.GFX.GMA.Power_And_Clocks;
Nico Huber83693c82016-10-08 22:17:55 +020023
24use type HW.Word8;
25use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
26
27package body HW.GFX.GMA.DP_Aux_Request is
28
29 DP_AUX_CTL_SEND_BUSY : constant := 1 * 2 ** 31;
30 DP_AUX_CTL_DONE : constant := 1 * 2 ** 30;
31 DP_AUX_CTL_INTERRUPT_ON_DONE : constant := 1 * 2 ** 29;
32 DP_AUX_CTL_TIME_OUT_ERROR : constant := 1 * 2 ** 28;
33 DP_AUX_CTL_TIME_OUT_TIMER_MASK : constant := 3 * 2 ** 26;
34 DP_AUX_CTL_TIME_OUT_TIMER_400US : constant := 0 * 2 ** 26;
35 DP_AUX_CTL_TIME_OUT_TIMER_600US : constant := 1 * 2 ** 26;
36 DP_AUX_CTL_TIME_OUT_TIMER_800US : constant := 2 * 2 ** 26;
37 DP_AUX_CTL_TIME_OUT_TIMER_1600US : constant := 3 * 2 ** 26;
38 DP_AUX_CTL_RECEIVE_ERROR : constant := 1 * 2 ** 25;
39 DP_AUX_CTL_MESSAGE_SIZE_MASK : constant := 31 * 2 ** 20;
40 DP_AUX_CTL_MESSAGE_SIZE_SHIFT : constant := 2 ** 20;
41 DP_AUX_CTL_PRECHARGE_TIME_MASK : constant := 15 * 2 ** 16;
42 DP_AUX_CTL_PRECHARGE_TIME_SHIFT : constant := 2 ** 16;
43 DP_AUX_CTL_2X_BIT_CLOCK_DIV_MASK : constant := 2047 * 2 ** 0;
Nico Huberabe3de22016-10-20 15:03:46 +020044 -- TODO: HSW/BDW with LPT-H might need a workaround for the 2x bit clock.
Nico Huber83693c82016-10-08 22:17:55 +020045
46 subtype DP_AUX_CTL_MESSAGE_SIZE_T is Natural range 1 .. 20;
47 function DP_AUX_CTL_MESSAGE_SIZE
48 (Message_Length : DP_AUX_CTL_MESSAGE_SIZE_T)
49 return Word32;
50
51 DDI_AUX_MUTEX_MUTEX_ENABLE : constant := 1 * 2 ** 31;
52 DDI_AUX_MUTEX_MUTEX_STATUS : constant := 1 * 2 ** 30;
53
54 type AUX_CH_Data_Regs is new Positive range 1 .. 5;
55
56 type AUX_CH_Data_Regs_Array is
Tim Wawrzynczak24748f32022-09-09 10:54:05 -060057 array (AUX_CH_Data_Regs) of Registers.Registers_Invalid_Index;
Nico Huber83693c82016-10-08 22:17:55 +020058
59 type AUX_CH_Registers is record
Tim Wawrzynczak24748f32022-09-09 10:54:05 -060060 CTL : Registers.Registers_Invalid_Index;
Nico Huber83693c82016-10-08 22:17:55 +020061 DATA : AUX_CH_Data_Regs_Array;
62 MUTEX : Registers.Registers_Invalid_Index;
63 end record;
64
65 type AUX_CH_Registers_Array is array (DP_Port) of AUX_CH_Registers;
66
67 AUX_CH : constant AUX_CH_Registers_Array :=
Tim Wawrzynczak24748f32022-09-09 10:54:05 -060068 (if Config.Has_Type_C_Ports then
69 AUX_CH_Registers_Array'
70 (DP_A => AUX_CH_Registers'
71 (CTL => Registers.DDI_AUX_CTL_A,
72 DATA => AUX_CH_Data_Regs_Array'
73 (1 => Registers.DDI_AUX_DATA_A_1,
74 2 => Registers.DDI_AUX_DATA_A_2,
75 3 => Registers.DDI_AUX_DATA_A_3,
76 4 => Registers.DDI_AUX_DATA_A_4,
77 5 => Registers.DDI_AUX_DATA_A_5),
78 MUTEX => Registers.Invalid_Register),
79 DP_B => AUX_CH_Registers'
80 (CTL => Registers.DDI_AUX_CTL_B,
81 DATA => AUX_CH_Data_Regs_Array'
82 (1 => Registers.DDI_AUX_DATA_B_1,
83 2 => Registers.DDI_AUX_DATA_B_2,
84 3 => Registers.DDI_AUX_DATA_B_3,
85 4 => Registers.DDI_AUX_DATA_B_4,
86 5 => Registers.DDI_AUX_DATA_B_5),
87 MUTEX => Registers.Invalid_Register),
88 DP_C => AUX_CH_Registers'
89 (CTL => Registers.DDI_AUX_CTL_C,
90 DATA => AUX_CH_Data_Regs_Array'
91 (1 => Registers.DDI_AUX_DATA_C_1,
92 2 => Registers.DDI_AUX_DATA_C_2,
93 3 => Registers.DDI_AUX_DATA_C_3,
94 4 => Registers.DDI_AUX_DATA_C_4,
95 5 => Registers.DDI_AUX_DATA_C_5),
96 MUTEX => Registers.Invalid_Register),
97 DP_D => AUX_CH_Registers'
98 (CTL => Registers.DDI_AUX_CTL_USBC1,
99 DATA => AUX_CH_Data_Regs_Array'
100 (1 => Registers.DDI_AUX_DATA_USBC1_1,
101 2 => Registers.DDI_AUX_DATA_USBC1_2,
102 3 => Registers.DDI_AUX_DATA_USBC1_3,
103 4 => Registers.DDI_AUX_DATA_USBC1_4,
104 5 => Registers.DDI_AUX_DATA_USBC1_5),
105 MUTEX => Registers.Invalid_Register),
106 DP_E => AUX_CH_Registers'
107 (CTL => Registers.DDI_AUX_CTL_USBC2,
108 DATA => AUX_CH_Data_Regs_Array'
109 (1 => Registers.DDI_AUX_DATA_USBC2_1,
110 2 => Registers.DDI_AUX_DATA_USBC2_2,
111 3 => Registers.DDI_AUX_DATA_USBC2_3,
112 4 => Registers.DDI_AUX_DATA_USBC2_4,
113 5 => Registers.DDI_AUX_DATA_USBC2_5),
114 MUTEX => Registers.Invalid_Register),
115 DP_F => AUX_CH_Registers'
116 (CTL => Registers.DDI_AUX_CTL_USBC3,
117 DATA => AUX_CH_Data_Regs_Array'
118 (1 => Registers.DDI_AUX_DATA_USBC3_1,
119 2 => Registers.DDI_AUX_DATA_USBC3_2,
120 3 => Registers.DDI_AUX_DATA_USBC3_3,
121 4 => Registers.DDI_AUX_DATA_USBC3_4,
122 5 => Registers.DDI_AUX_DATA_USBC3_5),
123 MUTEX => Registers.Invalid_Register),
124 DP_G => AUX_CH_Registers'
125 (CTL => Registers.DDI_AUX_CTL_USBC4,
126 DATA => AUX_CH_Data_Regs_Array'
127 (1 => Registers.DDI_AUX_DATA_USBC4_1,
128 2 => Registers.DDI_AUX_DATA_USBC4_2,
129 3 => Registers.DDI_AUX_DATA_USBC4_3,
130 4 => Registers.DDI_AUX_DATA_USBC4_4,
131 5 => Registers.DDI_AUX_DATA_USBC5_5),
132 MUTEX => Registers.Invalid_Register),
133 DP_H => AUX_CH_Registers'
134 (CTL => Registers.DDI_AUX_CTL_USBC5,
135 DATA => AUX_CH_Data_Regs_Array'
136 (1 => Registers.DDI_AUX_DATA_USBC5_1,
137 2 => Registers.DDI_AUX_DATA_USBC5_2,
138 3 => Registers.DDI_AUX_DATA_USBC5_3,
139 4 => Registers.DDI_AUX_DATA_USBC5_4,
140 5 => Registers.DDI_AUX_DATA_USBC5_5),
141 MUTEX => Registers.Invalid_Register),
142 DP_I => AUX_CH_Registers'
143 (CTL => Registers.DDI_AUX_CTL_USBC6,
144 DATA => AUX_CH_Data_Regs_Array'
145 (1 => Registers.DDI_AUX_DATA_USBC6_1,
146 2 => Registers.DDI_AUX_DATA_USBC6_2,
147 3 => Registers.DDI_AUX_DATA_USBC6_3,
148 4 => Registers.DDI_AUX_DATA_USBC6_4,
149 5 => Registers.DDI_AUX_DATA_USBC6_5),
150 MUTEX => Registers.Invalid_Register))
151 elsif Config.Has_PCH_Aux_Channels then
Nico Huber83693c82016-10-08 22:17:55 +0200152 AUX_CH_Registers_Array'
153 (DP_A => AUX_CH_Registers'
154 (CTL => Registers.DP_AUX_CTL_A,
155 DATA => AUX_CH_Data_Regs_Array'
156 (1 => Registers.DP_AUX_DATA_A_1,
157 2 => Registers.DP_AUX_DATA_A_2,
158 3 => Registers.DP_AUX_DATA_A_3,
159 4 => Registers.DP_AUX_DATA_A_4,
160 5 => Registers.DP_AUX_DATA_A_5),
161 MUTEX => Registers.Invalid_Register),
162 DP_B => AUX_CH_Registers'
163 (CTL => Registers.PCH_DP_AUX_CTL_B,
164 DATA => AUX_CH_Data_Regs_Array'
165 (1 => Registers.PCH_DP_AUX_DATA_B_1,
166 2 => Registers.PCH_DP_AUX_DATA_B_2,
167 3 => Registers.PCH_DP_AUX_DATA_B_3,
168 4 => Registers.PCH_DP_AUX_DATA_B_4,
169 5 => Registers.PCH_DP_AUX_DATA_B_5),
170 MUTEX => Registers.Invalid_Register),
171 DP_C => AUX_CH_Registers'
172 (CTL => Registers.PCH_DP_AUX_CTL_C,
173 DATA => AUX_CH_Data_Regs_Array'
174 (1 => Registers.PCH_DP_AUX_DATA_C_1,
175 2 => Registers.PCH_DP_AUX_DATA_C_2,
176 3 => Registers.PCH_DP_AUX_DATA_C_3,
177 4 => Registers.PCH_DP_AUX_DATA_C_4,
178 5 => Registers.PCH_DP_AUX_DATA_C_5),
179 MUTEX => Registers.Invalid_Register),
180 DP_D => AUX_CH_Registers'
181 (CTL => Registers.PCH_DP_AUX_CTL_D,
182 DATA => AUX_CH_Data_Regs_Array'
183 (1 => Registers.PCH_DP_AUX_DATA_D_1,
184 2 => Registers.PCH_DP_AUX_DATA_D_2,
185 3 => Registers.PCH_DP_AUX_DATA_D_3,
186 4 => Registers.PCH_DP_AUX_DATA_D_4,
187 5 => Registers.PCH_DP_AUX_DATA_D_5),
Tim Wawrzynczak24748f32022-09-09 10:54:05 -0600188 MUTEX => Registers.Invalid_Register),
189 others => AUX_CH_Registers'
190 (DATA => AUX_CH_Data_Regs_Array'
191 (others => Registers.Invalid_Register),
192 others => Registers.Invalid_Register))
Nico Huber83693c82016-10-08 22:17:55 +0200193 else
194 AUX_CH_Registers_Array'
195 (DP_A => AUX_CH_Registers'
196 (CTL => Registers.DDI_AUX_CTL_A,
197 DATA => AUX_CH_Data_Regs_Array'
198 (1 => Registers.DDI_AUX_DATA_A_1,
199 2 => Registers.DDI_AUX_DATA_A_2,
200 3 => Registers.DDI_AUX_DATA_A_3,
201 4 => Registers.DDI_AUX_DATA_A_4,
202 5 => Registers.DDI_AUX_DATA_A_5),
203 MUTEX => Registers.DDI_AUX_MUTEX_A),
204 DP_B => AUX_CH_Registers'
205 (CTL => Registers.DDI_AUX_CTL_B,
206 DATA => AUX_CH_Data_Regs_Array'
207 (1 => Registers.DDI_AUX_DATA_B_1,
208 2 => Registers.DDI_AUX_DATA_B_2,
209 3 => Registers.DDI_AUX_DATA_B_3,
210 4 => Registers.DDI_AUX_DATA_B_4,
211 5 => Registers.DDI_AUX_DATA_B_5),
212 MUTEX => Registers.DDI_AUX_MUTEX_B),
213 DP_C => AUX_CH_Registers'
214 (CTL => Registers.DDI_AUX_CTL_C,
215 DATA => AUX_CH_Data_Regs_Array'
216 (1 => Registers.DDI_AUX_DATA_C_1,
217 2 => Registers.DDI_AUX_DATA_C_2,
218 3 => Registers.DDI_AUX_DATA_C_3,
219 4 => Registers.DDI_AUX_DATA_C_4,
220 5 => Registers.DDI_AUX_DATA_C_5),
221 MUTEX => Registers.DDI_AUX_MUTEX_C),
222 DP_D => AUX_CH_Registers'
223 (CTL => Registers.DDI_AUX_CTL_D,
224 DATA => AUX_CH_Data_Regs_Array'
225 (1 => Registers.DDI_AUX_DATA_D_1,
226 2 => Registers.DDI_AUX_DATA_D_2,
227 3 => Registers.DDI_AUX_DATA_D_3,
228 4 => Registers.DDI_AUX_DATA_D_4,
229 5 => Registers.DDI_AUX_DATA_D_5),
Tim Wawrzynczak24748f32022-09-09 10:54:05 -0600230 MUTEX => Registers.DDI_AUX_MUTEX_D),
231 others => AUX_CH_Registers'
232 (DATA => AUX_CH_Data_Regs_Array'
233 (others => Registers.Invalid_Register),
234 others => Registers.Invalid_Register)));
Nico Huber83693c82016-10-08 22:17:55 +0200235
236 ----------------------------------------------------------------------------
237
238 function DP_AUX_CTL_MESSAGE_SIZE
239 (Message_Length : DP_AUX_CTL_MESSAGE_SIZE_T)
240 return Word32
241 is
242 begin
243 return Word32 (Message_Length) * DP_AUX_CTL_MESSAGE_SIZE_SHIFT;
244 end DP_AUX_CTL_MESSAGE_SIZE;
245
246 ----------------------------------------------------------------------------
247
248 procedure Aux_Request_Low
249 (Port : in DP_Port;
250 Request : in DP_Defs.Aux_Request;
251 Request_Length : in DP_Defs.Aux_Request_Length;
252 Response : out DP_Defs.Aux_Response;
253 Response_Length : out DP_Defs.Aux_Response_Length;
254 Success : out Boolean)
255 with
256 Global => (In_Out => Registers.Register_State,
Nico Huber30e84082018-06-10 13:28:05 +0200257 Input => (Time.State, Config.Variable)),
Nico Huber83693c82016-10-08 22:17:55 +0200258 Depends =>
259 ((Registers.Register_State,
260 Response,
261 Response_Length,
262 Success)
263 =>
264 (Registers.Register_State,
Nico Huber30e84082018-06-10 13:28:05 +0200265 Config.Variable,
Nico Huber83693c82016-10-08 22:17:55 +0200266 Time.State,
267 Port,
268 Request,
269 Request_Length))
270 is
271 procedure Write_Data_Reg
272 (Register : in Registers.Registers_Index;
273 Buf : in DP_Defs.Aux_Request;
274 Length : in DP_Defs.Aux_Request_Length;
275 Offset : in DP_Defs.Aux_Request_Index)
276 is
277 Value : Word32;
278 Count : Natural;
279 begin
280 if Offset < Length then
281 if Length - Offset > 4 then
282 Count := 4;
283 else
284 Count := Length - Offset;
285 end if;
286
287 Value := 0;
288 for Idx in DP_Defs.Aux_Request_Index range 0 .. Count - 1 loop
289 Value := Value or
290 Shift_Left (Word32 (Buf (Offset + Idx)), (3 - Idx) * 8);
291 end loop;
292 Registers.Write (Register => Register, Value => Value);
293 end if;
294 end Write_Data_Reg;
295
296 procedure Read_Data_Reg
297 (Register : in Registers.Registers_Index;
298 Buf : in out DP_Defs.Aux_Response;
299 Length : in DP_Defs.Aux_Response_Length;
300 Offset : in DP_Defs.Aux_Response_Index)
301 is
302 Value : Word32;
303 Count : DP_Defs.Aux_Response_Length;
304 begin
305 if Offset < Length then
306 if Length - Offset > 4 then
307 Count := 4;
308 else
309 Count := Length - Offset;
310 end if;
311
312 Registers.Read (Register => Register, Value => Value);
313 for Idx in 0 .. Count - 1 loop
314 Buf (Offset + Idx) :=
315 Word8 (Shift_Right (Value, (3 - Idx) * 8) and 16#ff#);
316 end loop;
317 end if;
318 end Read_Data_Reg;
319
Nico Huberabe3de22016-10-20 15:03:46 +0200320 DP_AUX_CTL_2x_Clock_Mask : constant :=
321 (if Config.Has_PCH_Aux_Channels then
322 DP_AUX_CTL_2X_BIT_CLOCK_DIV_MASK else 0);
323 DP_AUX_CTL_2x_Clock : constant Word32 :=
324 (if Config.Has_PCH_Aux_Channels then
325 (if Port = DP_A then
Nico Huberd0f84b92019-09-22 21:31:52 +0200326 Word32 ((Config.CDClk + 1_000_000) / 2_000_000)
Nico Huberabe3de22016-10-20 15:03:46 +0200327 else
Arthur Heymansd1988d12018-03-28 16:27:57 +0200328 Word32 ((Config.Raw_Clock + 1_000_000) / 2_000_000))
Arthur Heymans73ea0322018-03-28 17:17:07 +0200329 elsif Config.Has_GMCH_RawClk then
330 Word32 (Div_Round_Closest (Config.Raw_Clock, 2_000_000))
Nico Huberabe3de22016-10-20 15:03:46 +0200331 else 0);
332
Nico Huber83693c82016-10-08 22:17:55 +0200333 Busy : Boolean;
334 Status : Word32;
335 begin
336 Response := (others => 0); -- Don't care
337 Response_Length := DP_Defs.Aux_Response_Length'First;
338
Tim Wawrzynczak24748f32022-09-09 10:54:05 -0600339 if not Config.Has_Type_C_Ports and Port > DP_D then
340 Success := False;
341 return;
342 end if;
343
Nico Huber83693c82016-10-08 22:17:55 +0200344 if Config.Need_DP_Aux_Mutex then
345 Registers.Set_Mask
346 (Register => AUX_CH (Port).MUTEX,
347 Mask => DDI_AUX_MUTEX_MUTEX_ENABLE);
348 Registers.Wait_Set_Mask
349 (Register => AUX_CH (Port).MUTEX,
350 Mask => DDI_AUX_MUTEX_MUTEX_STATUS);
351 end if;
352
353 Registers.Is_Set_Mask
354 (Register => AUX_CH (Port).CTL,
355 Mask => DP_AUX_CTL_SEND_BUSY,
356 Result => Busy);
357 if Busy then
358 Success := False;
359 else
360 for Idx in AUX_CH_Data_Regs loop
361 Write_Data_Reg
362 (Register => AUX_CH (Port).DATA (Idx),
363 Buf => Request,
364 Length => Request_Length,
365 Offset => (Natural (Idx) - 1) * 4);
366 end loop;
367
368 Registers.Unset_And_Set_Mask
369 (Register => AUX_CH (Port).CTL,
370 Mask_Unset => DP_AUX_CTL_INTERRUPT_ON_DONE or
371 DP_AUX_CTL_TIME_OUT_TIMER_MASK or
Nico Huberabe3de22016-10-20 15:03:46 +0200372 DP_AUX_CTL_MESSAGE_SIZE_MASK or
373 DP_AUX_CTL_2x_Clock_Mask,
Nico Huber83693c82016-10-08 22:17:55 +0200374 Mask_Set => DP_AUX_CTL_SEND_BUSY or -- starts transfer
375 DP_AUX_CTL_DONE or -- clears the status
376 DP_AUX_CTL_TIME_OUT_ERROR or -- clears the status
377 DP_AUX_CTL_RECEIVE_ERROR or -- clears the status
378 DP_AUX_CTL_TIME_OUT_TIMER_600US or
Nico Huberabe3de22016-10-20 15:03:46 +0200379 DP_AUX_CTL_MESSAGE_SIZE (Request_Length) or
380 DP_AUX_CTL_2x_Clock);
Nico Huber83693c82016-10-08 22:17:55 +0200381
382 Registers.Wait_Unset_Mask
383 (Register => AUX_CH (Port).CTL,
384 Mask => DP_AUX_CTL_SEND_BUSY);
385 Registers.Read (Register => AUX_CH (Port).CTL, Value => Status);
386 Success := (Status and
387 (DP_AUX_CTL_TIME_OUT_ERROR or DP_AUX_CTL_RECEIVE_ERROR))
388 = 0;
389
390 if Success then
391 Status := (Status and DP_AUX_CTL_MESSAGE_SIZE_MASK)
392 / DP_AUX_CTL_MESSAGE_SIZE_SHIFT;
393 if Natural (Status) < DP_Defs.Aux_Response_Length'First then
394 Success := False;
395 elsif Natural (Status) > DP_Defs.Aux_Response_Length'Last then
396 Response_Length := DP_Defs.Aux_Response_Length'Last;
397 else
398 Response_Length := Natural (Status);
399 end if;
400 end if;
401
402 if Success then
403 for Idx in AUX_CH_Data_Regs loop
404 Read_Data_Reg
405 (Register => AUX_CH (Port).DATA (Idx),
406 Buf => Response,
407 Length => Response_Length,
408 Offset => (Natural (Idx) - 1) * 4);
409 end loop;
410 end if;
411 end if;
412
413 if Config.Need_DP_Aux_Mutex then
414 Registers.Unset_And_Set_Mask
415 (Register => AUX_CH (Port).MUTEX,
416 Mask_Unset => DDI_AUX_MUTEX_MUTEX_ENABLE,
417 Mask_Set => DDI_AUX_MUTEX_MUTEX_STATUS); -- frees the mutex
418 end if;
419 end Aux_Request_Low;
420
421 ----------------------------------------------------------------------------
422
423 procedure Do_Aux_Request
424 (Port : in DP_Port;
425 Request : in DP_Defs.Aux_Request;
426 Request_Length : in DP_Defs.Aux_Request_Length;
427 Response : out DP_Defs.Aux_Response;
428 Response_Length : out DP_Defs.Aux_Response_Length;
429 Success : out Boolean)
430 is
431 begin
432 for Try in Positive range 1 .. 3 loop
433 Aux_Request_Low
434 (Port => Port,
435 Request => Request,
436 Request_Length => Request_Length,
437 Response => Response,
438 Response_Length => Response_Length,
439 Success => Success);
440 exit when Success;
441 end loop;
442 end Do_Aux_Request;
443
444end HW.GFX.GMA.DP_Aux_Request;