blob: 0427f48d1f23dbc80f4bc01c52c99b091943e47b [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 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
96 function Link_Pixel_Per_Second
97 (Link_Rate : DP_Bandwidth)
98 return Positive
99 with
100 Post => Pos64 (Link_Pixel_Per_Second'Result) <=
101 ((DP_Symbol_Rate_Type'Last * 8) / 3) / BPC_Type'First
102 is
103 begin
104 -- Link_Rate is brutto with 8/10 bit symbols; three colors
105 pragma Assert (Positive (DP_Symbol_Rate (Link_Rate)) <= (Positive'Last / 8) * 3);
106 pragma Assert ((Int64 (DP_Symbol_Rate (Link_Rate)) * 8) / 3
107 >= Int64 (BPC_Type'Last));
108 return Positive
109 (((Int64 (DP_Symbol_Rate (Link_Rate)) * 8) / 3)
110 / Int64 (Mode.BPC));
111 end Link_Pixel_Per_Second;
112
113 Count : Natural;
114 begin
115 Count := Link_Pixel_Per_Second (Link.Bandwidth);
116 Count := (Positive (Mode.Dotclock) + Count - 1) / Count;
117
118 Success := True;
119 case Count is
120 when 1 => Link.Lane_Count := DP_Lane_Count_1;
121 when 2 => Link.Lane_Count := DP_Lane_Count_2;
122 when 3 | 4 => Link.Lane_Count := DP_Lane_Count_4;
123 when others => Success := False;
124 end case;
125 end Minimum_Lane_Count;
126
127 procedure Preferred_Link_Setting
128 (Link : in out DP_Link;
129 Mode : in Mode_Type;
130 Success : out Boolean)
131 is
132 begin
133 Link.Bandwidth := Link.Receiver_Caps.Max_Link_Rate;
134 Link.Enhanced_Framing := Link.Receiver_Caps.Enhanced_Framing;
135
136 Minimum_Lane_Count (Link, Mode, Success);
137
138 Success := Success and
139 Link.Lane_Count <= Link.Receiver_Caps.Max_Lane_Count;
140
141 pragma Debug (Success, Debug.Put ("Trying DP settings: Symbol Rate = "));
142 pragma Debug (Success, Debug.Put_Int32
143 (Int32 (DP_Symbol_Rate (Link.Bandwidth))));
144 pragma Debug (Success, Debug.Put ("; Lane Count = "));
145 pragma Debug (Success, Debug.Put_Int32
146 (Int32 (Lane_Count_As_Integer (Link.Lane_Count))));
147 pragma Debug (Success, Debug.New_Line);
148 pragma Debug (Success, Debug.New_Line);
149
150 pragma Debug (not Success, Debug.Put_Line
151 ("Mode requirements exceed available bandwidth!"));
152 end Preferred_Link_Setting;
153
154 procedure Next_Link_Setting
155 (Link : in out DP_Link;
156 Mode : in Mode_Type;
157 Success : out Boolean)
158 is
159 begin
160 if Link.Bandwidth > DP_Bandwidth'First then
161 Link.Bandwidth := DP_Bandwidth'Pred (Link.Bandwidth);
162
163 Minimum_Lane_Count (Link, Mode, Success);
164
165 Success := Success and
166 Link.Lane_Count <= Link.Receiver_Caps.Max_Lane_Count;
167 else
168 Success := False;
169 end if;
170
171 pragma Debug (Success, Debug.Put ("Trying DP settings: Symbol Rate = "));
172 pragma Debug (Success, Debug.Put_Int32
173 (Int32 (DP_Symbol_Rate (Link.Bandwidth))));
174 pragma Debug (Success, Debug.Put ("; Lane Count = "));
175 pragma Debug (Success, Debug.Put_Int32
176 (Int32 (Lane_Count_As_Integer (Link.Lane_Count))));
177 pragma Debug (Success, Debug.New_Line);
178 pragma Debug (Success, Debug.New_Line);
179 end Next_Link_Setting;
180
181 ----------------------------------------------------------------------------
182
183 procedure Calculate_M_N
184 (Link : in DP_Link;
185 Mode : in Mode_Type;
186 Data_M : out M_Type;
187 Data_N : out N_Type;
188 Link_M : out M_Type;
189 Link_N : out N_Type)
190 is
191 DATA_N_MAX : constant := 16#800000#;
192 LINK_N_MAX : constant := 16#100000#;
193
194 subtype Calc_M_Type is Int64 range 0 .. 2 ** 36;
195 subtype Calc_N_Type is Int64 range 0 .. 2 ** 36;
196 subtype N_Rounded_Type is Int64 range
197 0 .. Int64'Max (DATA_N_MAX, LINK_N_MAX);
198
199 M : Calc_M_Type;
200 N : Calc_N_Type;
201
202 procedure Cancel_M_N
203 (M : in out Calc_M_Type;
204 N : in out Calc_N_Type;
205 N_Max : in N_Rounded_Type)
206 with
207 Depends => ((M, N) => (M, N, N_max)),
208 Pre => (N > 0 and M in 0 .. Calc_M_Type'Last / 2),
209 Post => (M <= M_N_Max and N <= M_N_Max)
210 is
211 Orig_N : constant Calc_N_Type := N;
212
213 function Round_N (N : Calc_N_Type) return N_Rounded_Type
214 with
215 Post => (Round_N'Result <= N * 2)
216 is
217 RN : Calc_N_Type;
218 RN2 : Calc_N_Type := N_Max;
219 begin
220 loop
221 RN := RN2;
222 RN2 := RN2 / 2;
223 exit when RN2 < N;
224 pragma Loop_Invariant (RN2 = RN / 2 and RN2 in N .. N_Max);
225 end loop;
226 return RN;
227 end Round_N;
228 begin
229 N := Round_N (N);
230
231 -- The automatic provers need a little nudge here.
232 pragma Assert
233 (if M <= Calc_M_Type'Last/2 and
234 N <= Orig_N * 2 and
235 Orig_N > 0 and
236 M > 0
237 then
238 M * N / Orig_N <= Calc_M_Type'Last);
239
240 pragma Annotate (GNATprove, False_Positive,
241 "assertion might fail",
242 "The property cannot be proven automatically. An Isabelle proof is included as an axiom");
243
244 M := M * N / Orig_N;
245
246 -- This loop is never hit for sane values (i.e. M <= N) but
247 -- we have to make sure returned values are always in range.
248 while M > M_N_Max loop
249 pragma Loop_Invariant (N <= M_N_Max);
250 M := M / 2;
251 N := N / 2;
252 end loop;
253 end Cancel_M_N;
254 begin
255 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
256
257 pragma Assert (3
258 * Mode.BPC
259 * Mode.Dotclock
260 in Pos64);
261 M := 3
262 * Mode.BPC
263 * Mode.Dotclock;
264
265 pragma Assert (8
266 * DP_Symbol_Rate (Link.Bandwidth)
267 * Lane_Count_As_Integer (Link.Lane_Count)
268 in Pos64);
269 N := 8
270 * DP_Symbol_Rate (Link.Bandwidth)
271 * Lane_Count_As_Integer (Link.Lane_Count);
272
273 Cancel_M_N (M, N, DATA_N_MAX);
274 Data_M := M;
275 Data_N := N;
276
277 -------------------------------------------------------------------
278
279 M := Pos64 (Mode.Dotclock);
280 N := Pos64 (DP_Symbol_Rate (Link.Bandwidth));
281
282 Cancel_M_N (M, N, LINK_N_MAX);
283 Link_M := M;
284 Link_N := N;
285 end Calculate_M_N;
286
287 ----------------------------------------------------------------------------
288
289 procedure Read_Link_Status
290 (Port : in T;
291 Status : out Link_Status;
292 Success : out Boolean)
293 is
294 subtype Status_Index is DP_Defs.Aux_Payload_Index range 0 .. 5;
295 subtype Status_Buffer is Buffer (Status_Index);
296 function Buffer_As_Status is new Ada.Unchecked_Conversion
297 (Source => Status_Buffer, Target => Link_Status);
298
299 Data : DP_Defs.Aux_Payload;
300 Length : DP_Defs.Aux_Payload_Length;
301 begin
302 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
303
304 Length := Status_Index'Last + 1;
305 Aux_Ch.Aux_Read
306 (Port => Port,
307 Address => 16#00202#,
308 Length => Length,
309 Data => Data,
310 Success => Success);
311 Success := Success and Length = Status_Index'Last + 1;
312 Status := Buffer_As_Status (Data (Status_Index));
313 end Read_Link_Status;
314
315 function All_CR_Done
316 (Status : Link_Status;
317 Link : DP_Link)
318 return Boolean
319 is
320 CR_Done : Boolean := True;
321 begin
322 for Lane in Lane_Index
323 range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
324 loop
325 CR_Done := CR_Done and Status.Lanes (Lane).CR_Done;
326 end loop;
327 return CR_Done;
328 end All_CR_Done;
329
330 function All_EQ_Done
331 (Status : Link_Status;
332 Link : DP_Link)
333 return Boolean
334 is
335 EQ_Done : Boolean := True;
336 begin
337 for Lane in Lane_Index
338 range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
339 loop
340 EQ_Done := EQ_Done and Status.Lanes (Lane).CR_Done
341 and Status.Lanes (Lane).Channel_EQ_Done
342 and Status.Lanes (Lane).Symbol_Locked;
343 end loop;
344 return EQ_Done and Status.Interlane_Align_Done;
345 end All_EQ_Done;
346
347 function Max_Requested_VS
348 (Status : Link_Status;
349 Link : DP_Link)
350 return DP_Voltage_Swing
351 is
352 VS : DP_Voltage_Swing := DP_Voltage_Swing'First;
353 begin
354 for Lane in Lane_Index
355 range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
356 loop
357 if Status.Adjust_Requests (Lane).Voltage_Swing > VS then
358 VS := Status.Adjust_Requests (Lane).Voltage_Swing;
359 end if;
360 end loop;
361 return VS;
362 end Max_Requested_VS;
363
364 function Max_Requested_Emph
365 (Status : Link_Status;
366 Link : DP_Link)
367 return DP_Pre_Emph
368 is
369 Emph : DP_Pre_Emph := DP_Pre_Emph'First;
370 begin
371 for Lane in Lane_Index
372 range 0 .. Lane_Index (Lane_Count_As_Integer (Link.Lane_Count) - 1)
373 loop
374 if Status.Adjust_Requests (Lane).Pre_Emph > Emph then
375 Emph := Status.Adjust_Requests (Lane).Pre_Emph;
376 end if;
377 end loop;
378 return Emph;
379 end Max_Requested_Emph;
380
381end HW.GFX.DP_Info;