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