blob: 392fee13d291878d36604436ae87f638bf027b17 [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
Nico Huberaf9cc9e2017-01-09 13:11:32 +01002-- 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 Ada.Unchecked_Conversion;
16
17with HW.Debug;
18with GNAT.Source_Info;
19
20with HW.GFX.DP_Defs;
21
22use type HW.Word8;
Greg V3d3452f2019-10-08 02:05:05 +030023use type HW.Word16;
Nico Huber83693c82016-10-08 22:17:55 +020024
25package body HW.GFX.DP_Info is
26
27 procedure Read_Caps
28 (Link : in out DP_Link;
29 Port : in T;
30 Success : out Boolean)
31 is
32 Data : DP_Defs.Aux_Payload;
33 Length : DP_Defs.Aux_Payload_Length;
34
35 Caps_Size : constant := 15;
36 begin
37 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
38
39 Length := Caps_Size;
40 Aux_Ch.Aux_Read
41 (Port => Port,
42 Address => 16#00000#,
43 Length => Length,
44 Data => Data,
45 Success => Success);
46 Success := Success and Length = Caps_Size;
47
48 if Length = Caps_Size then
49 Link.Receiver_Caps.Rev := Data (0);
50 case Data (1) is
51 when 16#06# =>
52 Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_1_62;
53 when 16#0a# =>
54 Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
55 when 16#14# =>
56 Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_5_4;
57 when others =>
58 if Data (1) > 16#14# then
59 Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_5_4;
60 else
61 Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_1_62;
62 end if;
63 end case;
64 case Data (2) and 16#1f# is
65 when 0 | 1 =>
66 Link.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_1;
67 when 2 | 3 =>
68 Link.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_2;
69 when others =>
70 Link.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_4;
71 end case;
72 Link.Receiver_Caps.TPS3_Supported := (Data (2) and 16#40#) /= 0;
73 Link.Receiver_Caps.Enhanced_Framing := (Data (2) and 16#80#) /= 0;
74 Link.Receiver_Caps.No_Aux_Handshake := (Data (3) and 16#40#) /= 0;
Angel Pons7769b522022-09-08 17:55:20 +020075 Link.Receiver_Caps.Aux_RD_Interval := Data (14) and 16#7f#;
Nico Huber83693c82016-10-08 22:17:55 +020076
77 pragma Debug (Debug.New_Line);
78 pragma Debug (Debug.Put_Line ("DPCD:"));
79 pragma Debug (Debug.Put_Reg8 (" Rev ", Data (0)));
80 pragma Debug (Debug.Put_Reg8 (" Max_Link_Rate ", Data (1)));
81 pragma Debug (Debug.Put_Reg8 (" Max_Lane_Count ", Data (2) and 16#1f#));
82 pragma Debug (Debug.Put_Reg8 (" TPS3_Supported ", Data (2) and 16#40#));
83 pragma Debug (Debug.Put_Reg8 (" Enhanced_Framing", Data (2) and 16#80#));
84 pragma Debug (Debug.Put_Reg8 (" No_Aux_Handshake", Data (3) and 16#40#));
Angel Pons7769b522022-09-08 17:55:20 +020085 pragma Debug (Debug.Put_Reg8 (" Aux_RD_Interval ", Data (14) and 16#7f#));
Nico Huber83693c82016-10-08 22:17:55 +020086 pragma Debug (Debug.New_Line);
87 end if;
88 end Read_Caps;
89
Greg V3d3452f2019-10-08 02:05:05 +030090 function Read_LE16
91 (Raw_Payload : DP_Defs.Aux_Payload;
92 Offset : DP_Defs.Aux_Payload_Index)
93 return Word16
94 with
95 Pre => Offset < DP_Defs.Aux_Payload_Index'Last
96 is
97 begin
98 return Shift_Left (Word16 (Raw_Payload (Offset + 1)), 8) or
99 Word16 (Raw_Payload (Offset));
100 end Read_LE16;
101
102 procedure Read_eDP_Rates
103 (Link : in out DP_Link;
104 Port : in T)
105 is
106 Data : DP_Defs.Aux_Payload;
107 Length : DP_Defs.Aux_Payload_Length;
108 Max_Rate : Natural;
109 Success : Boolean;
110
111 Caps_Size : constant := 3;
112 Rates_Size : constant := 16;
113 eDP_Rev_1_4 : constant := 3;
114 begin
115 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
116
117 Length := Caps_Size;
118 Aux_Ch.Aux_Read
119 (Port => Port,
120 Address => 16#00700#,
121 Length => Length,
122 Data => Data,
123 Success => Success);
124 Success := Success and Length = Caps_Size;
125 if not Success or Data (0) < eDP_Rev_1_4 then
126 return;
127 end if;
128
129 Length := Rates_Size;
130 Aux_Ch.Aux_Read
131 (Port => Port,
132 Address => 16#00010#,
133 Length => Length,
134 Data => Data,
135 Success => Success);
136 Success := Success and Length = Rates_Size;
137 if not Success then
138 return;
139 end if;
140
141 pragma Debug (Debug.New_Line);
142 pragma Debug (Debug.Put_Line ("DPCD eDP 1.4+ link rates:"));
143
144 -- TODO: support individual link rates (storing them all)
145
146 Max_Rate := Natural'First;
147 for I in 0 .. Length / 2 - 1 loop
148 pragma Loop_Invariant (Max_Rate <= Natural (Word16'Last));
149 declare
150 Rate : constant Word16 := Read_LE16 (Data, I * 2);
151 begin
152 exit when Rate = 0; -- prematurely exit the loop
153 pragma Debug (Debug.Put (" - "));
154 pragma Debug (Debug.Put_Int8 (Int8 (I)));
155 pragma Debug (Debug.Put (": "));
156 pragma Debug (Debug.Put_Word16 (Rate));
157 pragma Debug (Debug.New_Line);
158 if Natural (Rate) > Max_Rate then
159 Max_Rate := Natural (Rate);
160 end if;
161 end;
162 end loop;
163 pragma Debug (Debug.New_Line);
164
165 -- convert to KHz
166 Max_Rate := Max_Rate * 20;
167
168 if Max_Rate >= 540_000 then
169 Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_5_4;
170 elsif Max_Rate >= 270_000 then
171 Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
172 elsif Max_Rate >= 162_000 then
173 Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_1_62;
174 end if;
175 end Read_eDP_Rates;
176
Nico Huber83693c82016-10-08 22:17:55 +0200177 procedure Minimum_Lane_Count
178 (Link : in out DP_Link;
179 Mode : in Mode_Type;
180 Success : out Boolean)
181 with
182 Depends => ((Link, Success) => (Link, Mode))
183 is
Nico Huber6c10d362019-10-02 00:28:19 +0200184 Lane_Pixel_Per_Second : constant Pos64 :=
185 (((DP_Symbol_Rate (Link.Bandwidth) * 8) / 3) / Mode.BPC);
186 Count : constant Pos64 :=
187 Div_Round_Up (Mode.Dotclock, Lane_Pixel_Per_Second);
Nico Huber83693c82016-10-08 22:17:55 +0200188 begin
Nico Huber83693c82016-10-08 22:17:55 +0200189 Success := True;
190 case Count is
191 when 1 => Link.Lane_Count := DP_Lane_Count_1;
192 when 2 => Link.Lane_Count := DP_Lane_Count_2;
193 when 3 | 4 => Link.Lane_Count := DP_Lane_Count_4;
194 when others => Success := False;
195 end case;
196 end Minimum_Lane_Count;
197
198 procedure Preferred_Link_Setting
199 (Link : in out DP_Link;
200 Mode : in Mode_Type;
201 Success : out Boolean)
202 is
203 begin
204 Link.Bandwidth := Link.Receiver_Caps.Max_Link_Rate;
205 Link.Enhanced_Framing := Link.Receiver_Caps.Enhanced_Framing;
206
207 Minimum_Lane_Count (Link, Mode, Success);
208
209 Success := Success and
210 Link.Lane_Count <= Link.Receiver_Caps.Max_Lane_Count;
211
Nico Huber83693c82016-10-08 22:17:55 +0200212 pragma Debug (not Success, Debug.Put_Line
213 ("Mode requirements exceed available bandwidth!"));
214 end Preferred_Link_Setting;
215
216 procedure Next_Link_Setting
217 (Link : in out DP_Link;
218 Mode : in Mode_Type;
219 Success : out Boolean)
220 is
221 begin
222 if Link.Bandwidth > DP_Bandwidth'First then
223 Link.Bandwidth := DP_Bandwidth'Pred (Link.Bandwidth);
224
225 Minimum_Lane_Count (Link, Mode, Success);
226
227 Success := Success and
228 Link.Lane_Count <= Link.Receiver_Caps.Max_Lane_Count;
229 else
230 Success := False;
231 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200232 end Next_Link_Setting;
233
Nico Huberaf9cc9e2017-01-09 13:11:32 +0100234 procedure Dump_Link_Setting (Link : DP_Link)
235 is
236 begin
237 Debug.Put ("Trying DP settings: Symbol Rate = ");
238 Debug.Put_Int32 (Int32 (DP_Symbol_Rate (Link.Bandwidth)));
239 Debug.Put ("; Lane Count = ");
240 Debug.Put_Int32 (Int32 (Lane_Count_As_Integer (Link.Lane_Count)));
241 Debug.New_Line;
242 Debug.New_Line;
243 end Dump_Link_Setting;
244
Nico Huber83693c82016-10-08 22:17:55 +0200245 ----------------------------------------------------------------------------
246
247 procedure Calculate_M_N
248 (Link : in DP_Link;
249 Mode : in Mode_Type;
250 Data_M : out M_Type;
251 Data_N : out N_Type;
252 Link_M : out M_Type;
253 Link_N : out N_Type)
254 is
255 DATA_N_MAX : constant := 16#800000#;
256 LINK_N_MAX : constant := 16#100000#;
257
Nico Huber6c10d362019-10-02 00:28:19 +0200258 subtype Calc_M_Type is Int64 range 0 .. 2 ** 38;
259 subtype Calc_N_Type is Int64 range 0 .. 2 ** 38;
Nico Huber83693c82016-10-08 22:17:55 +0200260 subtype N_Rounded_Type is Int64 range
261 0 .. Int64'Max (DATA_N_MAX, LINK_N_MAX);
262
263 M : Calc_M_Type;
264 N : Calc_N_Type;
265
266 procedure Cancel_M_N
267 (M : in out Calc_M_Type;
268 N : in out Calc_N_Type;
269 N_Max : in N_Rounded_Type)
270 with
271 Depends => ((M, N) => (M, N, N_max)),
272 Pre => (N > 0 and M in 0 .. Calc_M_Type'Last / 2),
273 Post => (M <= M_N_Max and N <= M_N_Max)
274 is
275 Orig_N : constant Calc_N_Type := N;
276
277 function Round_N (N : Calc_N_Type) return N_Rounded_Type
278 with
279 Post => (Round_N'Result <= N * 2)
280 is
281 RN : Calc_N_Type;
282 RN2 : Calc_N_Type := N_Max;
283 begin
284 loop
285 RN := RN2;
286 RN2 := RN2 / 2;
287 exit when RN2 < N;
288 pragma Loop_Invariant (RN2 = RN / 2 and RN2 in N .. N_Max);
289 end loop;
290 return RN;
291 end Round_N;
292 begin
293 N := Round_N (N);
294
295 -- The automatic provers need a little nudge here.
296 pragma Assert
297 (if M <= Calc_M_Type'Last/2 and
298 N <= Orig_N * 2 and
299 Orig_N > 0 and
300 M > 0
301 then
302 M * N / Orig_N <= Calc_M_Type'Last);
303
304 pragma Annotate (GNATprove, False_Positive,
305 "assertion might fail",
306 "The property cannot be proven automatically. An Isabelle proof is included as an axiom");
307
308 M := M * N / Orig_N;
309
310 -- This loop is never hit for sane values (i.e. M <= N) but
311 -- we have to make sure returned values are always in range.
312 while M > M_N_Max loop
313 pragma Loop_Invariant (N <= M_N_Max);
314 M := M / 2;
315 N := N / 2;
316 end loop;
317 end Cancel_M_N;
318 begin
319 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
320
321 pragma Assert (3
322 * Mode.BPC
323 * Mode.Dotclock
324 in Pos64);
325 M := 3
326 * Mode.BPC
327 * Mode.Dotclock;
328
329 pragma Assert (8
330 * DP_Symbol_Rate (Link.Bandwidth)
331 * Lane_Count_As_Integer (Link.Lane_Count)
332 in Pos64);
333 N := 8
334 * DP_Symbol_Rate (Link.Bandwidth)
335 * Lane_Count_As_Integer (Link.Lane_Count);
336
337 Cancel_M_N (M, N, DATA_N_MAX);
338 Data_M := M;
339 Data_N := N;
340
341 -------------------------------------------------------------------
342
343 M := Pos64 (Mode.Dotclock);
344 N := Pos64 (DP_Symbol_Rate (Link.Bandwidth));
345
346 Cancel_M_N (M, N, LINK_N_MAX);
347 Link_M := M;
348 Link_N := N;
349 end Calculate_M_N;
350
351 ----------------------------------------------------------------------------
352
353 procedure Read_Link_Status
354 (Port : in T;
355 Status : out Link_Status;
356 Success : out Boolean)
357 is
358 subtype Status_Index is DP_Defs.Aux_Payload_Index range 0 .. 5;
359 subtype Status_Buffer is Buffer (Status_Index);
360 function Buffer_As_Status is new Ada.Unchecked_Conversion
361 (Source => Status_Buffer, Target => Link_Status);
362
363 Data : DP_Defs.Aux_Payload;
364 Length : DP_Defs.Aux_Payload_Length;
365 begin
366 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
367
368 Length := Status_Index'Last + 1;
369 Aux_Ch.Aux_Read
370 (Port => Port,
371 Address => 16#00202#,
372 Length => Length,
373 Data => Data,
374 Success => Success);
375 Success := Success and Length = Status_Index'Last + 1;
376 Status := Buffer_As_Status (Data (Status_Index));
377 end Read_Link_Status;
378
379 function All_CR_Done
380 (Status : Link_Status;
381 Link : DP_Link)
382 return Boolean
383 is
384 CR_Done : Boolean := True;
385 begin
386 for Lane in Lane_Index
387 range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
388 loop
389 CR_Done := CR_Done and Status.Lanes (Lane).CR_Done;
390 end loop;
391 return CR_Done;
392 end All_CR_Done;
393
394 function All_EQ_Done
395 (Status : Link_Status;
396 Link : DP_Link)
397 return Boolean
398 is
399 EQ_Done : Boolean := True;
400 begin
401 for Lane in Lane_Index
402 range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
403 loop
404 EQ_Done := EQ_Done and Status.Lanes (Lane).CR_Done
405 and Status.Lanes (Lane).Channel_EQ_Done
406 and Status.Lanes (Lane).Symbol_Locked;
407 end loop;
408 return EQ_Done and Status.Interlane_Align_Done;
409 end All_EQ_Done;
410
411 function Max_Requested_VS
412 (Status : Link_Status;
413 Link : DP_Link)
414 return DP_Voltage_Swing
415 is
416 VS : DP_Voltage_Swing := DP_Voltage_Swing'First;
417 begin
418 for Lane in Lane_Index
419 range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
420 loop
421 if Status.Adjust_Requests (Lane).Voltage_Swing > VS then
422 VS := Status.Adjust_Requests (Lane).Voltage_Swing;
423 end if;
424 end loop;
425 return VS;
426 end Max_Requested_VS;
427
428 function Max_Requested_Emph
429 (Status : Link_Status;
430 Link : DP_Link)
431 return DP_Pre_Emph
432 is
433 Emph : DP_Pre_Emph := DP_Pre_Emph'First;
434 begin
435 for Lane in Lane_Index
436 range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
437 loop
438 if Status.Adjust_Requests (Lane).Pre_Emph > Emph then
439 Emph := Status.Adjust_Requests (Lane).Pre_Emph;
440 end if;
441 end loop;
442 return Emph;
443 end Max_Requested_Emph;
444
445end HW.GFX.DP_Info;