blob: 380bcedc68b85086beb9e0fd71bdb49ff4895644 [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
289 -- TODO: Should have Success parameter
Nico Huberbcb2c472017-02-02 16:39:26 +0100290 -- Wait for the bits in @Register@ indicated by @Mask@ to be of @Value@
291 procedure Wait
292 (Register : Registers_Index;
293 Mask : Word32;
294 Value : Word32;
295 TOut_MS : Natural := Default_Timeout_MS;
296 Verbose : Boolean := False)
297 is
298 Current : Word32;
299 Timeout : Time.T;
300 Timed_Out : Boolean;
301 begin
302 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
303 pragma Debug (Debug.Put_Word32 (Value));
304 pragma Debug (Debug.Put (" <- "));
305 pragma Debug (Debug.Put_Word32 (Mask));
306 pragma Debug (Debug.Put (" & "));
307 pragma Debug (Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
308 pragma Debug (Debug.Put (":"));
309 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
310
311 Timeout := Time.MS_From_Now (TOut_MS);
312 loop
313 Timed_Out := Time.Timed_Out (Timeout);
314 Read (Register, Current, Verbose);
315 if (Current and Mask) = Value then
316 exit;
317 end if;
318 pragma Debug (Timed_Out, Debug.Put (GNAT.Source_Info.Enclosing_Entity));
319 pragma Debug (Timed_Out, Debug.Put_Line (": Timed Out!"));
320 exit when Timed_Out;
321 end loop;
322 end Wait;
323
324 ----------------------------------------------------------------------------
325
326 -- TODO: Should have Success parameter
Nico Huber83693c82016-10-08 22:17:55 +0200327 -- Wait for all bits in @Register@ indicated by @Mask@ to be set
328 procedure Wait_Set_Mask
329 (Register : in Registers_Index;
330 Mask : in Word32;
331 TOut_MS : in Natural := Default_Timeout_MS;
332 Verbose : in Boolean := False)
333 is
Nico Huber83693c82016-10-08 22:17:55 +0200334 begin
Nico Huberbcb2c472017-02-02 16:39:26 +0100335 Wait (Register, Mask, Mask, TOut_MS, Verbose);
Nico Huber83693c82016-10-08 22:17:55 +0200336 end Wait_Set_Mask;
337
338 ----------------------------------------------------------------------------
339
340 -- TODO: Should have Success parameter
341 -- Wait for bits in @Register@ indicated by @Mask@ to be clear
342 procedure Wait_Unset_Mask
343 (Register : Registers_Index;
344 Mask : Word32;
345 TOut_MS : in Natural := Default_Timeout_MS;
346 Verbose : in Boolean := False)
347 is
Nico Huber83693c82016-10-08 22:17:55 +0200348 begin
Nico Huberbcb2c472017-02-02 16:39:26 +0100349 Wait (Register, Mask, 0, TOut_MS, Verbose);
Nico Huber83693c82016-10-08 22:17:55 +0200350 end Wait_Unset_Mask;
351
352 ----------------------------------------------------------------------------
353
354 -- Set bits from @Mask@ in @Register@
355 procedure Set_Mask
356 (Register : Registers_Index;
357 Mask : Word32)
358 is
359 Value : Word32;
360 begin
361 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
362 pragma Debug (Debug.Put_Word32 (Mask));
363 pragma Debug (Debug.Put (" .S "));
364 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
365
366 Read (Register, Value);
367 Value := Value or Mask;
368 Write (Register, Value);
369 end Set_Mask;
370
371 ----------------------------------------------------------------------------
372
373 -- Mask out @Mask@ in @Register@
374 procedure Unset_Mask
375 (Register : Registers_Index;
376 Mask : Word32)
377 is
378 Value : Word32;
379 begin
380 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
381 pragma Debug (Debug.Put_Word32 (Mask));
382 pragma Debug (Debug.Put (" !S "));
383 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
384
385 Read (Register, Value);
386 Value := Value and not Mask;
387 Write (Register, Value);
388 end Unset_Mask;
389
390 ----------------------------------------------------------------------------
391
392 -- Mask out @Unset_Mask@ and set @Set_Mask@ in @Register@
393 procedure Unset_And_Set_Mask
394 (Register : Registers_Index;
395 Mask_Unset : Word32;
396 Mask_Set : Word32)
397 is
398 Value : Word32;
399 begin
400 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
401 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
402
403 Read (Register, Value);
404 Value := (Value and not Mask_Unset) or Mask_Set;
405 Write (Register, Value);
406 end Unset_And_Set_Mask;
407
408 ----------------------------------------------------------------------------
409
Nico Huber2b6f6992017-07-09 18:11:34 +0200410 procedure Set_Register_Base (Base : Word64; GTT_Base : Word64 := 0)
Nico Huber83693c82016-10-08 22:17:55 +0200411 is
412 begin
413 Regs.Set_Base_Address (Base);
Nico Huber2b6f6992017-07-09 18:11:34 +0200414 if GTT_Base = 0 then
Nico Huber0b2329a2018-06-09 21:14:27 +0200415 GTT_32.Set_Base_Address (Base + MMIO_GTT_32_Offset);
416 GTT_64.Set_Base_Address (Base + MMIO_GTT_64_Offset);
Nico Huber2b6f6992017-07-09 18:11:34 +0200417 else
Nico Huber0b2329a2018-06-09 21:14:27 +0200418 GTT_32.Set_Base_Address (GTT_Base);
419 GTT_64.Set_Base_Address (GTT_Base);
Nico Huber2b6f6992017-07-09 18:11:34 +0200420 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200421 end Set_Register_Base;
422
423end HW.GFX.GMA.Registers;