blob: 3f0d7ae6aaf20d35a59a7d7b2a58a30957ed8078 [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
Nico Huber83693c82016-10-08 22:17:55 +020015with HW.Time;
16with HW.MMIO_Range;
17pragma Elaborate_All (HW.MMIO_Range);
18
19with HW.Debug;
20with GNAT.Source_Info;
21
Nico Huber83693c82016-10-08 22:17:55 +020022use type HW.Word64;
23
24package body HW.GFX.GMA.Registers
25with
26 Refined_State =>
Nico Huber0b2329a2018-06-09 21:14:27 +020027 (Address_State =>
28 (Regs.Base_Address, GTT_32.Base_Address, GTT_64.Base_Address),
Nico Huber83693c82016-10-08 22:17:55 +020029 Register_State => Regs.State,
Nico Huber0b2329a2018-06-09 21:14:27 +020030 GTT_State => (GTT_32.State, GTT_64.State))
Nico Huber83693c82016-10-08 22:17:55 +020031is
32 pragma Disable_Atomic_Synchronization;
33
34 type Registers_Range is
35 new Natural range 0 .. 16#0020_0000# / Register_Width - 1;
36 type Registers_Type is array (Registers_Range) of Word32
37 with
38 Atomic_Components,
39 Size => 16#20_0000# * 8;
40 package Regs is new MMIO_Range
41 (Base_Addr => Config.Default_MMIO_Base,
42 Element_T => Word32,
43 Index_T => Registers_Range,
44 Array_T => Registers_Type);
45
46 ----------------------------------------------------------------------------
47
Nico Huber0b2329a2018-06-09 21:14:27 +020048 type GTT_PTE_32 is mod 2 ** 32;
49 type GTT_Registers_32 is array (GTT_Range) of GTT_PTE_32
Nico Huber83693c82016-10-08 22:17:55 +020050 with
51 Volatile_Components,
Nico Huber0b2329a2018-06-09 21:14:27 +020052 Size => MMIO_GTT_32_Size * 8;
53 package GTT_32 is new MMIO_Range
54 (Base_Addr => Config.Default_MMIO_Base + MMIO_GTT_32_Offset,
55 Element_T => GTT_PTE_32,
Nico Huber83693c82016-10-08 22:17:55 +020056 Index_T => GTT_Range,
Nico Huber0b2329a2018-06-09 21:14:27 +020057 Array_T => GTT_Registers_32);
58
59 type GTT_PTE_64 is mod 2 ** 64;
60 type GTT_Registers_64 is array (GTT_Range) of GTT_PTE_64
61 with
62 Volatile_Components,
63 Size => MMIO_GTT_64_Size * 8;
64 package GTT_64 is new MMIO_Range
65 (Base_Addr => Config.Default_MMIO_Base + MMIO_GTT_64_Offset,
66 Element_T => GTT_PTE_64,
67 Index_T => GTT_Range,
68 Array_T => GTT_Registers_64);
Nico Huber83693c82016-10-08 22:17:55 +020069
Nico Huberceda17d2018-06-09 22:00:29 +020070 GTT_PTE_Valid : constant := 1;
Nico Huber83693c82016-10-08 22:17:55 +020071
72 ----------------------------------------------------------------------------
73
Nico Huberd0d8b792018-06-09 19:45:00 +020074 subtype Fence_Range is Natural range 0 .. 31;
Nico Huberb03c8f12017-08-25 13:29:08 +020075
76 FENCE_PAGE_SHIFT : constant := 12;
77 FENCE_PAGE_MASK : constant := 16#ffff_f000#;
78 FENCE_TILE_WALK_YMAJOR : constant := 1 * 2 ** 1;
79 FENCE_VALID : constant := 1 * 2 ** 0;
80
81 function Fence_Lower_Idx (Fence : Fence_Range) return Registers_Range is
Nico Huberd0d8b792018-06-09 19:45:00 +020082 (Registers_Range (Config.Fence_Base / Register_Width + 2 * Fence));
Nico Huberb03c8f12017-08-25 13:29:08 +020083 function Fence_Upper_Idx (Fence : Fence_Range) return Registers_Range is
84 (Fence_Lower_Idx (Fence) + 1);
85
Nico Huber17d64b62017-07-15 20:51:25 +020086 procedure Clear_Fences
87 is
Nico Huber17d64b62017-07-15 20:51:25 +020088 begin
Nico Huberd0d8b792018-06-09 19:45:00 +020089 for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
Nico Huberb03c8f12017-08-25 13:29:08 +020090 Regs.Write (Fence_Lower_Idx (Fence), 0);
Nico Huber17d64b62017-07-15 20:51:25 +020091 end loop;
92 end Clear_Fences;
93
Nico Huberb03c8f12017-08-25 13:29:08 +020094 procedure Add_Fence
95 (First_Page : in GTT_Range;
96 Last_Page : in GTT_Range;
97 Tiling : in XY_Tiling;
98 Pitch : in Natural;
99 Success : out Boolean)
100 is
101 Y_Tiles : constant Boolean := Tiling = Y_Tiled;
102 Reg32 : Word32;
103 begin
104 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
105 pragma Debug (Debug.Put_Word32 (Shift_Left (Word32 (First_Page), 12)));
106 pragma Debug (Debug.Put (":"));
107 pragma Debug (Debug.Put_Word32 (Shift_Left (Word32 (Last_Page), 12)));
108 pragma Debug (not Y_Tiles, Debug.Put (" X tiled in "));
109 pragma Debug ( Y_Tiles, Debug.Put (" Y tiled in "));
110 pragma Debug (Debug.Put_Int32 (Int32 (Pitch)));
111 pragma Debug (Debug.Put_Line (" tiles per row."));
112
113 Success := False;
Nico Huberd0d8b792018-06-09 19:45:00 +0200114 for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
Nico Huberb03c8f12017-08-25 13:29:08 +0200115 Regs.Read (Reg32, Fence_Lower_Idx (Fence));
116 if (Reg32 and FENCE_VALID) = 0 then
117 Regs.Write
118 (Index => Fence_Lower_Idx (Fence),
119 Value => Shift_Left (Word32 (First_Page), FENCE_PAGE_SHIFT) or
120 (if Y_Tiles then FENCE_TILE_WALK_YMAJOR else 0) or
121 FENCE_VALID);
122 Regs.Write
123 (Index => Fence_Upper_Idx (Fence),
124 Value => Shift_Left (Word32 (Last_Page), FENCE_PAGE_SHIFT) or
125 Word32 (Pitch) * (if Y_Tiles then 1 else 4) - 1);
126 Success := True;
127 exit;
128 end if;
129 end loop;
130 end Add_Fence;
131
132 procedure Remove_Fence (First_Page, Last_Page : GTT_Range)
133 is
134 Page_Lower : constant Word32 :=
135 Shift_Left (Word32 (First_Page), FENCE_PAGE_SHIFT);
136 Page_Upper : constant Word32 :=
137 Shift_Left (Word32 (Last_Page), FENCE_PAGE_SHIFT);
138 Fence_Upper, Fence_Lower : Word32;
139 begin
Nico Huberd0d8b792018-06-09 19:45:00 +0200140 for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
Nico Huberb03c8f12017-08-25 13:29:08 +0200141 Regs.Read (Fence_Lower, Fence_Lower_Idx (Fence));
142 Regs.Read (Fence_Upper, Fence_Upper_Idx (Fence));
143 if (Fence_Lower and FENCE_PAGE_MASK) = Page_Lower and
144 (Fence_Upper and FENCE_PAGE_MASK) = Page_Upper
145 then
146 Regs.Write (Fence_Lower_Idx (Fence), 0);
147 exit;
148 end if;
149 end loop;
150 end Remove_Fence;
151
Nico Huber17d64b62017-07-15 20:51:25 +0200152 ----------------------------------------------------------------------------
153
Nico Huber83693c82016-10-08 22:17:55 +0200154 procedure Write_GTT
155 (GTT_Page : GTT_Range;
156 Device_Address : GTT_Address_Type;
157 Valid : Boolean)
158 is
159 begin
Nico Huber0b2329a2018-06-09 21:14:27 +0200160 if not Config.Has_64bit_GTT then
161 GTT_32.Write
Nico Huber83693c82016-10-08 22:17:55 +0200162 (Index => GTT_Page,
Nico Huber0b2329a2018-06-09 21:14:27 +0200163 Value => GTT_PTE_32 (Device_Address and 16#ffff_f000#) or
164 GTT_PTE_32 (Shift_Right (Word64 (Device_Address), 32 - 4)
Nico Huber83693c82016-10-08 22:17:55 +0200165 and 16#0000_07f0#) or
166 Boolean'Pos (Valid));
167 else
Nico Huber0b2329a2018-06-09 21:14:27 +0200168 GTT_64.Write
Nico Huber83693c82016-10-08 22:17:55 +0200169 (Index => GTT_Page,
Nico Huber0b2329a2018-06-09 21:14:27 +0200170 Value => GTT_PTE_64 (Device_Address and 16#7f_ffff_f000#) or
Nico Huber83693c82016-10-08 22:17:55 +0200171 Boolean'Pos (Valid));
172 end if;
173 end Write_GTT;
174
Nico Huberceda17d2018-06-09 22:00:29 +0200175 procedure Read_GTT
176 (Device_Address : out GTT_Address_Type;
177 Valid : out Boolean;
178 GTT_Page : in GTT_Range)
179 is
180 begin
181 if not Config.Has_64bit_GTT then
182 declare
183 PTE : GTT_PTE_32;
184 begin
185 GTT_32.Read (PTE, GTT_Page);
186 Valid := (PTE and GTT_PTE_Valid) /= 0;
187 Device_Address := GTT_Address_Type
188 (Shift_Left (Word64 (PTE and 16#07f0#), 32 - 4) or
189 Word64 (PTE and 16#ffff_f000#));
190 end;
191 else
192 declare
193 PTE : GTT_PTE_64;
194 begin
195 GTT_64.Read (PTE, GTT_Page);
196 Valid := (PTE and GTT_PTE_Valid) /= 0;
197 Device_Address := GTT_Address_Type (PTE and 16#7f_ffff_f000#);
198 end;
199 end if;
200 end Read_GTT;
201
Nico Huber83693c82016-10-08 22:17:55 +0200202 ----------------------------------------------------------------------------
203
204 package Rep is
205 function Index (Reg : Registers_Index) return Registers_Range;
206 end Rep;
207
208 package body Rep is
209 function Index (Reg : Registers_Index) return Registers_Range
210 with
211 SPARK_Mode => Off
212 is
213 begin
214 return Reg'Enum_Rep;
215 end Index;
216 end Rep;
217
218 -- Read a specific register
219 procedure Read
220 (Register : in Registers_Index;
221 Value : out Word32;
222 Verbose : in Boolean := True)
223 is
224 begin
225 Regs.Read (Value, Rep.Index (Register));
226
227 pragma Debug (Verbose, Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
228 pragma Debug (Verbose, Debug.Put_Word32 (Value));
229 pragma Debug (Verbose, Debug.Put (" <- "));
230 pragma Debug (Verbose, Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
231 pragma Debug (Verbose, Debug.Put (":"));
232 pragma Debug (Verbose, Debug.Put_Line (Registers_Index'Image (Register)));
233 end Read;
234
235 ----------------------------------------------------------------------------
236
237 -- Read a specific register to post a previous write
238 procedure Posting_Read (Register : Registers_Index)
239 is
240 Discard_Value : Word32;
241 begin
242 pragma Warnings
243 (Off, "unused assignment to ""Discard_Value""",
244 Reason => "Intentional dummy read to affect hardware.");
245
246 Read (Register, Discard_Value);
247
248 pragma Warnings
249 (On, "unused assignment to ""Discard_Value""");
250 end Posting_Read;
251
252 ----------------------------------------------------------------------------
253
254 -- Write a specific register
255 procedure Write (Register : Registers_Index; Value : Word32)
256 is
257 begin
258 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
259 pragma Debug (Debug.Put_Word32 (Value));
260 pragma Debug (Debug.Put (" -> "));
261 pragma Debug (Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
262 pragma Debug (Debug.Put (":"));
263 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
264
265 Regs.Write (Rep.Index (Register), Value);
266 pragma Debug (Debug.Register_Write_Wait);
267 end Write;
268
269 ----------------------------------------------------------------------------
270
271 -- Check whether all bits in @Register@ indicated by @Mask@ are set
272 procedure Is_Set_Mask
273 (Register : in Registers_Index;
274 Mask : in Word32;
275 Result : out Boolean)
276 is
277 Value : Word32;
278 begin
279 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
280 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
281
282 Read (Register, Value);
283 Result := (Value and Mask) = Mask;
284
285 end Is_Set_Mask;
286
287 ----------------------------------------------------------------------------
288
Nico Huber82ca09f2019-09-28 02:37:50 +0200289 pragma Warnings (GNATprove, Off, "unused assignment to ""Ignored_Success""");
290
Nico Huberbcb2c472017-02-02 16:39:26 +0100291 -- Wait for the bits in @Register@ indicated by @Mask@ to be of @Value@
292 procedure Wait
Nico Huber82ca09f2019-09-28 02:37:50 +0200293 (Register : in Registers_Index;
294 Mask : in Word32;
295 Value : in Word32;
296 TOut_MS : in Natural := Default_Timeout_MS;
297 Verbose : in Boolean := False;
298 Success : out Boolean)
Nico Huberbcb2c472017-02-02 16:39:26 +0100299 is
300 Current : Word32;
301 Timeout : Time.T;
Nico Huber82ca09f2019-09-28 02:37:50 +0200302 Timed_Out : Boolean := False;
Nico Huberbcb2c472017-02-02 16:39:26 +0100303 begin
304 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
305 pragma Debug (Debug.Put_Word32 (Value));
306 pragma Debug (Debug.Put (" <- "));
307 pragma Debug (Debug.Put_Word32 (Mask));
308 pragma Debug (Debug.Put (" & "));
309 pragma Debug (Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
310 pragma Debug (Debug.Put (":"));
311 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
312
313 Timeout := Time.MS_From_Now (TOut_MS);
314 loop
Nico Huberbcb2c472017-02-02 16:39:26 +0100315 Read (Register, Current, Verbose);
316 if (Current and Mask) = Value then
Nico Huber82ca09f2019-09-28 02:37:50 +0200317 -- Ignore timeout if we succeeded anyway.
318 Timed_Out := False;
Nico Huberbcb2c472017-02-02 16:39:26 +0100319 exit;
320 end if;
321 pragma Debug (Timed_Out, Debug.Put (GNAT.Source_Info.Enclosing_Entity));
322 pragma Debug (Timed_Out, Debug.Put_Line (": Timed Out!"));
323 exit when Timed_Out;
Nico Huber82ca09f2019-09-28 02:37:50 +0200324
325 Timed_Out := Time.Timed_Out (Timeout);
Nico Huberbcb2c472017-02-02 16:39:26 +0100326 end loop;
Nico Huber82ca09f2019-09-28 02:37:50 +0200327
328 Success := not Timed_Out;
329 end Wait;
330
331 procedure Wait
332 (Register : Registers_Index;
333 Mask : Word32;
334 Value : Word32;
335 TOut_MS : Natural := Default_Timeout_MS;
336 Verbose : Boolean := False)
337 is
338 Ignored_Success : Boolean;
339 begin
340 Wait (Register, Mask, Value, TOut_MS, Verbose, Ignored_Success);
Nico Huberbcb2c472017-02-02 16:39:26 +0100341 end Wait;
342
343 ----------------------------------------------------------------------------
344
Nico Huber83693c82016-10-08 22:17:55 +0200345 -- Wait for all bits in @Register@ indicated by @Mask@ to be set
346 procedure Wait_Set_Mask
347 (Register : in Registers_Index;
348 Mask : in Word32;
349 TOut_MS : in Natural := Default_Timeout_MS;
Nico Huber82ca09f2019-09-28 02:37:50 +0200350 Verbose : in Boolean := False;
351 Success : out Boolean) is
Nico Huber83693c82016-10-08 22:17:55 +0200352 begin
Nico Huber82ca09f2019-09-28 02:37:50 +0200353 Wait (Register, Mask, Mask, TOut_MS, Verbose, Success);
354 end Wait_Set_Mask;
355
356 procedure Wait_Set_Mask
357 (Register : Registers_Index;
358 Mask : Word32;
359 TOut_MS : Natural := Default_Timeout_MS;
360 Verbose : Boolean := False)
361 is
362 Ignored_Success : Boolean;
363 begin
364 Wait (Register, Mask, Mask, TOut_MS, Verbose, Ignored_Success);
Nico Huber83693c82016-10-08 22:17:55 +0200365 end Wait_Set_Mask;
366
367 ----------------------------------------------------------------------------
368
Nico Huber83693c82016-10-08 22:17:55 +0200369 -- Wait for bits in @Register@ indicated by @Mask@ to be clear
370 procedure Wait_Unset_Mask
Nico Huber82ca09f2019-09-28 02:37:50 +0200371 (Register : in Registers_Index;
372 Mask : in Word32;
373 TOut_MS : in Natural := Default_Timeout_MS;
374 Verbose : in Boolean := False;
375 Success : out Boolean) is
376 begin
377 Wait (Register, Mask, 0, TOut_MS, Verbose, Success);
378 end;
379
380 procedure Wait_Unset_Mask
Nico Huber83693c82016-10-08 22:17:55 +0200381 (Register : Registers_Index;
382 Mask : Word32;
Nico Huber82ca09f2019-09-28 02:37:50 +0200383 TOut_MS : Natural := Default_Timeout_MS;
384 Verbose : Boolean := False)
Nico Huber83693c82016-10-08 22:17:55 +0200385 is
Nico Huber82ca09f2019-09-28 02:37:50 +0200386 Ignored_Success : Boolean;
Nico Huber83693c82016-10-08 22:17:55 +0200387 begin
Nico Huber82ca09f2019-09-28 02:37:50 +0200388 Wait (Register, Mask, 0, TOut_MS, Verbose, Ignored_Success);
Nico Huber83693c82016-10-08 22:17:55 +0200389 end Wait_Unset_Mask;
390
391 ----------------------------------------------------------------------------
392
393 -- Set bits from @Mask@ in @Register@
394 procedure Set_Mask
395 (Register : Registers_Index;
396 Mask : Word32)
397 is
398 Value : Word32;
399 begin
400 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
401 pragma Debug (Debug.Put_Word32 (Mask));
402 pragma Debug (Debug.Put (" .S "));
403 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
404
405 Read (Register, Value);
406 Value := Value or Mask;
407 Write (Register, Value);
408 end Set_Mask;
409
410 ----------------------------------------------------------------------------
411
412 -- Mask out @Mask@ in @Register@
413 procedure Unset_Mask
414 (Register : Registers_Index;
415 Mask : Word32)
416 is
417 Value : Word32;
418 begin
419 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
420 pragma Debug (Debug.Put_Word32 (Mask));
421 pragma Debug (Debug.Put (" !S "));
422 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
423
424 Read (Register, Value);
425 Value := Value and not Mask;
426 Write (Register, Value);
427 end Unset_Mask;
428
429 ----------------------------------------------------------------------------
430
431 -- Mask out @Unset_Mask@ and set @Set_Mask@ in @Register@
432 procedure Unset_And_Set_Mask
433 (Register : Registers_Index;
434 Mask_Unset : Word32;
435 Mask_Set : Word32)
436 is
437 Value : Word32;
438 begin
439 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
440 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
441
442 Read (Register, Value);
443 Value := (Value and not Mask_Unset) or Mask_Set;
444 Write (Register, Value);
445 end Unset_And_Set_Mask;
446
447 ----------------------------------------------------------------------------
448
Nico Huber2b6f6992017-07-09 18:11:34 +0200449 procedure Set_Register_Base (Base : Word64; GTT_Base : Word64 := 0)
Nico Huber83693c82016-10-08 22:17:55 +0200450 is
451 begin
452 Regs.Set_Base_Address (Base);
Nico Huber2b6f6992017-07-09 18:11:34 +0200453 if GTT_Base = 0 then
Nico Huber0b2329a2018-06-09 21:14:27 +0200454 GTT_32.Set_Base_Address (Base + MMIO_GTT_32_Offset);
455 GTT_64.Set_Base_Address (Base + MMIO_GTT_64_Offset);
Nico Huber2b6f6992017-07-09 18:11:34 +0200456 else
Nico Huber0b2329a2018-06-09 21:14:27 +0200457 GTT_32.Set_Base_Address (GTT_Base);
458 GTT_64.Set_Base_Address (GTT_Base);
Nico Huber2b6f6992017-07-09 18:11:34 +0200459 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200460 end Set_Register_Base;
461
462end HW.GFX.GMA.Registers;