blob: d45826df3982bf3b99a98ab6ca9bbdc3473ce3fb [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;
23
24package body HW.GFX.DP_Info is
25
26 procedure Read_Caps
27 (Link : in out DP_Link;
28 Port : in T;
29 Success : out Boolean)
30 is
31 Data : DP_Defs.Aux_Payload;
32 Length : DP_Defs.Aux_Payload_Length;
33
34 Caps_Size : constant := 15;
35 begin
36 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
37
38 Length := Caps_Size;
39 Aux_Ch.Aux_Read
40 (Port => Port,
41 Address => 16#00000#,
42 Length => Length,
43 Data => Data,
44 Success => Success);
45 Success := Success and Length = Caps_Size;
46
47 if Length = Caps_Size then
48 Link.Receiver_Caps.Rev := Data (0);
49 case Data (1) is
50 when 16#06# =>
51 Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_1_62;
52 when 16#0a# =>
53 Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
54 when 16#14# =>
55 Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_5_4;
56 when others =>
57 if Data (1) > 16#14# then
58 Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_5_4;
59 else
60 Link.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_1_62;
61 end if;
62 end case;
63 case Data (2) and 16#1f# is
64 when 0 | 1 =>
65 Link.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_1;
66 when 2 | 3 =>
67 Link.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_2;
68 when others =>
69 Link.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_4;
70 end case;
71 Link.Receiver_Caps.TPS3_Supported := (Data (2) and 16#40#) /= 0;
72 Link.Receiver_Caps.Enhanced_Framing := (Data (2) and 16#80#) /= 0;
73 Link.Receiver_Caps.No_Aux_Handshake := (Data (3) and 16#40#) /= 0;
74 Link.Receiver_Caps.Aux_RD_Interval := Data (14);
75
76 pragma Debug (Debug.New_Line);
77 pragma Debug (Debug.Put_Line ("DPCD:"));
78 pragma Debug (Debug.Put_Reg8 (" Rev ", Data (0)));
79 pragma Debug (Debug.Put_Reg8 (" Max_Link_Rate ", Data (1)));
80 pragma Debug (Debug.Put_Reg8 (" Max_Lane_Count ", Data (2) and 16#1f#));
81 pragma Debug (Debug.Put_Reg8 (" TPS3_Supported ", Data (2) and 16#40#));
82 pragma Debug (Debug.Put_Reg8 (" Enhanced_Framing", Data (2) and 16#80#));
83 pragma Debug (Debug.Put_Reg8 (" No_Aux_Handshake", Data (3) and 16#40#));
84 pragma Debug (Debug.Put_Reg8 (" Aux_RD_Interval ", Data (14)));
85 pragma Debug (Debug.New_Line);
86 end if;
87 end Read_Caps;
88
89 procedure Minimum_Lane_Count
90 (Link : in out DP_Link;
91 Mode : in Mode_Type;
92 Success : out Boolean)
93 with
94 Depends => ((Link, Success) => (Link, Mode))
95 is
Nico Huber6c10d362019-10-02 00:28:19 +020096 Lane_Pixel_Per_Second : constant Pos64 :=
97 (((DP_Symbol_Rate (Link.Bandwidth) * 8) / 3) / Mode.BPC);
98 Count : constant Pos64 :=
99 Div_Round_Up (Mode.Dotclock, Lane_Pixel_Per_Second);
Nico Huber83693c82016-10-08 22:17:55 +0200100 begin
Nico Huber83693c82016-10-08 22:17:55 +0200101 Success := True;
102 case Count is
103 when 1 => Link.Lane_Count := DP_Lane_Count_1;
104 when 2 => Link.Lane_Count := DP_Lane_Count_2;
105 when 3 | 4 => Link.Lane_Count := DP_Lane_Count_4;
106 when others => Success := False;
107 end case;
108 end Minimum_Lane_Count;
109
110 procedure Preferred_Link_Setting
111 (Link : in out DP_Link;
112 Mode : in Mode_Type;
113 Success : out Boolean)
114 is
115 begin
116 Link.Bandwidth := Link.Receiver_Caps.Max_Link_Rate;
117 Link.Enhanced_Framing := Link.Receiver_Caps.Enhanced_Framing;
118
119 Minimum_Lane_Count (Link, Mode, Success);
120
121 Success := Success and
122 Link.Lane_Count <= Link.Receiver_Caps.Max_Lane_Count;
123
Nico Huber83693c82016-10-08 22:17:55 +0200124 pragma Debug (not Success, Debug.Put_Line
125 ("Mode requirements exceed available bandwidth!"));
126 end Preferred_Link_Setting;
127
128 procedure Next_Link_Setting
129 (Link : in out DP_Link;
130 Mode : in Mode_Type;
131 Success : out Boolean)
132 is
133 begin
134 if Link.Bandwidth > DP_Bandwidth'First then
135 Link.Bandwidth := DP_Bandwidth'Pred (Link.Bandwidth);
136
137 Minimum_Lane_Count (Link, Mode, Success);
138
139 Success := Success and
140 Link.Lane_Count <= Link.Receiver_Caps.Max_Lane_Count;
141 else
142 Success := False;
143 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200144 end Next_Link_Setting;
145
Nico Huberaf9cc9e2017-01-09 13:11:32 +0100146 procedure Dump_Link_Setting (Link : DP_Link)
147 is
148 begin
149 Debug.Put ("Trying DP settings: Symbol Rate = ");
150 Debug.Put_Int32 (Int32 (DP_Symbol_Rate (Link.Bandwidth)));
151 Debug.Put ("; Lane Count = ");
152 Debug.Put_Int32 (Int32 (Lane_Count_As_Integer (Link.Lane_Count)));
153 Debug.New_Line;
154 Debug.New_Line;
155 end Dump_Link_Setting;
156
Nico Huber83693c82016-10-08 22:17:55 +0200157 ----------------------------------------------------------------------------
158
159 procedure Calculate_M_N
160 (Link : in DP_Link;
161 Mode : in Mode_Type;
162 Data_M : out M_Type;
163 Data_N : out N_Type;
164 Link_M : out M_Type;
165 Link_N : out N_Type)
166 is
167 DATA_N_MAX : constant := 16#800000#;
168 LINK_N_MAX : constant := 16#100000#;
169
Nico Huber6c10d362019-10-02 00:28:19 +0200170 subtype Calc_M_Type is Int64 range 0 .. 2 ** 38;
171 subtype Calc_N_Type is Int64 range 0 .. 2 ** 38;
Nico Huber83693c82016-10-08 22:17:55 +0200172 subtype N_Rounded_Type is Int64 range
173 0 .. Int64'Max (DATA_N_MAX, LINK_N_MAX);
174
175 M : Calc_M_Type;
176 N : Calc_N_Type;
177
178 procedure Cancel_M_N
179 (M : in out Calc_M_Type;
180 N : in out Calc_N_Type;
181 N_Max : in N_Rounded_Type)
182 with
183 Depends => ((M, N) => (M, N, N_max)),
184 Pre => (N > 0 and M in 0 .. Calc_M_Type'Last / 2),
185 Post => (M <= M_N_Max and N <= M_N_Max)
186 is
187 Orig_N : constant Calc_N_Type := N;
188
189 function Round_N (N : Calc_N_Type) return N_Rounded_Type
190 with
191 Post => (Round_N'Result <= N * 2)
192 is
193 RN : Calc_N_Type;
194 RN2 : Calc_N_Type := N_Max;
195 begin
196 loop
197 RN := RN2;
198 RN2 := RN2 / 2;
199 exit when RN2 < N;
200 pragma Loop_Invariant (RN2 = RN / 2 and RN2 in N .. N_Max);
201 end loop;
202 return RN;
203 end Round_N;
204 begin
205 N := Round_N (N);
206
207 -- The automatic provers need a little nudge here.
208 pragma Assert
209 (if M <= Calc_M_Type'Last/2 and
210 N <= Orig_N * 2 and
211 Orig_N > 0 and
212 M > 0
213 then
214 M * N / Orig_N <= Calc_M_Type'Last);
215
216 pragma Annotate (GNATprove, False_Positive,
217 "assertion might fail",
218 "The property cannot be proven automatically. An Isabelle proof is included as an axiom");
219
220 M := M * N / Orig_N;
221
222 -- This loop is never hit for sane values (i.e. M <= N) but
223 -- we have to make sure returned values are always in range.
224 while M > M_N_Max loop
225 pragma Loop_Invariant (N <= M_N_Max);
226 M := M / 2;
227 N := N / 2;
228 end loop;
229 end Cancel_M_N;
230 begin
231 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
232
233 pragma Assert (3
234 * Mode.BPC
235 * Mode.Dotclock
236 in Pos64);
237 M := 3
238 * Mode.BPC
239 * Mode.Dotclock;
240
241 pragma Assert (8
242 * DP_Symbol_Rate (Link.Bandwidth)
243 * Lane_Count_As_Integer (Link.Lane_Count)
244 in Pos64);
245 N := 8
246 * DP_Symbol_Rate (Link.Bandwidth)
247 * Lane_Count_As_Integer (Link.Lane_Count);
248
249 Cancel_M_N (M, N, DATA_N_MAX);
250 Data_M := M;
251 Data_N := N;
252
253 -------------------------------------------------------------------
254
255 M := Pos64 (Mode.Dotclock);
256 N := Pos64 (DP_Symbol_Rate (Link.Bandwidth));
257
258 Cancel_M_N (M, N, LINK_N_MAX);
259 Link_M := M;
260 Link_N := N;
261 end Calculate_M_N;
262
263 ----------------------------------------------------------------------------
264
265 procedure Read_Link_Status
266 (Port : in T;
267 Status : out Link_Status;
268 Success : out Boolean)
269 is
270 subtype Status_Index is DP_Defs.Aux_Payload_Index range 0 .. 5;
271 subtype Status_Buffer is Buffer (Status_Index);
272 function Buffer_As_Status is new Ada.Unchecked_Conversion
273 (Source => Status_Buffer, Target => Link_Status);
274
275 Data : DP_Defs.Aux_Payload;
276 Length : DP_Defs.Aux_Payload_Length;
277 begin
278 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
279
280 Length := Status_Index'Last + 1;
281 Aux_Ch.Aux_Read
282 (Port => Port,
283 Address => 16#00202#,
284 Length => Length,
285 Data => Data,
286 Success => Success);
287 Success := Success and Length = Status_Index'Last + 1;
288 Status := Buffer_As_Status (Data (Status_Index));
289 end Read_Link_Status;
290
291 function All_CR_Done
292 (Status : Link_Status;
293 Link : DP_Link)
294 return Boolean
295 is
296 CR_Done : Boolean := True;
297 begin
298 for Lane in Lane_Index
299 range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
300 loop
301 CR_Done := CR_Done and Status.Lanes (Lane).CR_Done;
302 end loop;
303 return CR_Done;
304 end All_CR_Done;
305
306 function All_EQ_Done
307 (Status : Link_Status;
308 Link : DP_Link)
309 return Boolean
310 is
311 EQ_Done : Boolean := True;
312 begin
313 for Lane in Lane_Index
314 range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
315 loop
316 EQ_Done := EQ_Done and Status.Lanes (Lane).CR_Done
317 and Status.Lanes (Lane).Channel_EQ_Done
318 and Status.Lanes (Lane).Symbol_Locked;
319 end loop;
320 return EQ_Done and Status.Interlane_Align_Done;
321 end All_EQ_Done;
322
323 function Max_Requested_VS
324 (Status : Link_Status;
325 Link : DP_Link)
326 return DP_Voltage_Swing
327 is
328 VS : DP_Voltage_Swing := DP_Voltage_Swing'First;
329 begin
330 for Lane in Lane_Index
331 range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
332 loop
333 if Status.Adjust_Requests (Lane).Voltage_Swing > VS then
334 VS := Status.Adjust_Requests (Lane).Voltage_Swing;
335 end if;
336 end loop;
337 return VS;
338 end Max_Requested_VS;
339
340 function Max_Requested_Emph
341 (Status : Link_Status;
342 Link : DP_Link)
343 return DP_Pre_Emph
344 is
345 Emph : DP_Pre_Emph := DP_Pre_Emph'First;
346 begin
347 for Lane in Lane_Index
348 range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
349 loop
350 if Status.Adjust_Requests (Lane).Pre_Emph > Emph then
351 Emph := Status.Adjust_Requests (Lane).Pre_Emph;
352 end if;
353 end loop;
354 return Emph;
355 end Max_Requested_Emph;
356
357end HW.GFX.DP_Info;