blob: 838afed9b9b0c45eeae0ff5da173cba8032753b6 [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
Nico Huberb8ae6182017-07-15 20:03:56 +020019with HW.GFX.GMA.Config;
20
Nico Huber83693c82016-10-08 22:17:55 +020021with HW.Debug;
22with GNAT.Source_Info;
23
Nico Huber83693c82016-10-08 22:17:55 +020024use type HW.Word64;
25
26package body HW.GFX.GMA.Registers
27with
28 Refined_State =>
Nico Huber0b2329a2018-06-09 21:14:27 +020029 (Address_State =>
30 (Regs.Base_Address, GTT_32.Base_Address, GTT_64.Base_Address),
Nico Huber83693c82016-10-08 22:17:55 +020031 Register_State => Regs.State,
Nico Huber0b2329a2018-06-09 21:14:27 +020032 GTT_State => (GTT_32.State, GTT_64.State))
Nico Huber83693c82016-10-08 22:17:55 +020033is
34 pragma Disable_Atomic_Synchronization;
35
36 type Registers_Range is
37 new Natural range 0 .. 16#0020_0000# / Register_Width - 1;
38 type Registers_Type is array (Registers_Range) of Word32
39 with
40 Atomic_Components,
41 Size => 16#20_0000# * 8;
42 package Regs is new MMIO_Range
43 (Base_Addr => Config.Default_MMIO_Base,
44 Element_T => Word32,
45 Index_T => Registers_Range,
46 Array_T => Registers_Type);
47
48 ----------------------------------------------------------------------------
49
Nico Huber0b2329a2018-06-09 21:14:27 +020050 type GTT_PTE_32 is mod 2 ** 32;
51 type GTT_Registers_32 is array (GTT_Range) of GTT_PTE_32
Nico Huber83693c82016-10-08 22:17:55 +020052 with
53 Volatile_Components,
Nico Huber0b2329a2018-06-09 21:14:27 +020054 Size => MMIO_GTT_32_Size * 8;
55 package GTT_32 is new MMIO_Range
56 (Base_Addr => Config.Default_MMIO_Base + MMIO_GTT_32_Offset,
57 Element_T => GTT_PTE_32,
Nico Huber83693c82016-10-08 22:17:55 +020058 Index_T => GTT_Range,
Nico Huber0b2329a2018-06-09 21:14:27 +020059 Array_T => GTT_Registers_32);
60
61 type GTT_PTE_64 is mod 2 ** 64;
62 type GTT_Registers_64 is array (GTT_Range) of GTT_PTE_64
63 with
64 Volatile_Components,
65 Size => MMIO_GTT_64_Size * 8;
66 package GTT_64 is new MMIO_Range
67 (Base_Addr => Config.Default_MMIO_Base + MMIO_GTT_64_Offset,
68 Element_T => GTT_PTE_64,
69 Index_T => GTT_Range,
70 Array_T => GTT_Registers_64);
Nico Huber83693c82016-10-08 22:17:55 +020071
Nico Huberceda17d2018-06-09 22:00:29 +020072 GTT_PTE_Valid : constant := 1;
Nico Huber83693c82016-10-08 22:17:55 +020073
74 ----------------------------------------------------------------------------
75
Nico Huberd0d8b792018-06-09 19:45:00 +020076 subtype Fence_Range is Natural range 0 .. 31;
Nico Huberb03c8f12017-08-25 13:29:08 +020077
78 FENCE_PAGE_SHIFT : constant := 12;
79 FENCE_PAGE_MASK : constant := 16#ffff_f000#;
80 FENCE_TILE_WALK_YMAJOR : constant := 1 * 2 ** 1;
81 FENCE_VALID : constant := 1 * 2 ** 0;
82
83 function Fence_Lower_Idx (Fence : Fence_Range) return Registers_Range is
Nico Huberd0d8b792018-06-09 19:45:00 +020084 (Registers_Range (Config.Fence_Base / Register_Width + 2 * Fence));
Nico Huberb03c8f12017-08-25 13:29:08 +020085 function Fence_Upper_Idx (Fence : Fence_Range) return Registers_Range is
86 (Fence_Lower_Idx (Fence) + 1);
87
Nico Huber17d64b62017-07-15 20:51:25 +020088 procedure Clear_Fences
89 is
Nico Huber17d64b62017-07-15 20:51:25 +020090 begin
Nico Huberd0d8b792018-06-09 19:45:00 +020091 for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
Nico Huberb03c8f12017-08-25 13:29:08 +020092 Regs.Write (Fence_Lower_Idx (Fence), 0);
Nico Huber17d64b62017-07-15 20:51:25 +020093 end loop;
94 end Clear_Fences;
95
Nico Huberb03c8f12017-08-25 13:29:08 +020096 procedure Add_Fence
97 (First_Page : in GTT_Range;
98 Last_Page : in GTT_Range;
99 Tiling : in XY_Tiling;
100 Pitch : in Natural;
101 Success : out Boolean)
102 is
103 Y_Tiles : constant Boolean := Tiling = Y_Tiled;
104 Reg32 : Word32;
105 begin
106 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
107 pragma Debug (Debug.Put_Word32 (Shift_Left (Word32 (First_Page), 12)));
108 pragma Debug (Debug.Put (":"));
109 pragma Debug (Debug.Put_Word32 (Shift_Left (Word32 (Last_Page), 12)));
110 pragma Debug (not Y_Tiles, Debug.Put (" X tiled in "));
111 pragma Debug ( Y_Tiles, Debug.Put (" Y tiled in "));
112 pragma Debug (Debug.Put_Int32 (Int32 (Pitch)));
113 pragma Debug (Debug.Put_Line (" tiles per row."));
114
115 Success := False;
Nico Huberd0d8b792018-06-09 19:45:00 +0200116 for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
Nico Huberb03c8f12017-08-25 13:29:08 +0200117 Regs.Read (Reg32, Fence_Lower_Idx (Fence));
118 if (Reg32 and FENCE_VALID) = 0 then
119 Regs.Write
120 (Index => Fence_Lower_Idx (Fence),
121 Value => Shift_Left (Word32 (First_Page), FENCE_PAGE_SHIFT) or
122 (if Y_Tiles then FENCE_TILE_WALK_YMAJOR else 0) or
123 FENCE_VALID);
124 Regs.Write
125 (Index => Fence_Upper_Idx (Fence),
126 Value => Shift_Left (Word32 (Last_Page), FENCE_PAGE_SHIFT) or
127 Word32 (Pitch) * (if Y_Tiles then 1 else 4) - 1);
128 Success := True;
129 exit;
130 end if;
131 end loop;
132 end Add_Fence;
133
134 procedure Remove_Fence (First_Page, Last_Page : GTT_Range)
135 is
136 Page_Lower : constant Word32 :=
137 Shift_Left (Word32 (First_Page), FENCE_PAGE_SHIFT);
138 Page_Upper : constant Word32 :=
139 Shift_Left (Word32 (Last_Page), FENCE_PAGE_SHIFT);
140 Fence_Upper, Fence_Lower : Word32;
141 begin
Nico Huberd0d8b792018-06-09 19:45:00 +0200142 for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
Nico Huberb03c8f12017-08-25 13:29:08 +0200143 Regs.Read (Fence_Lower, Fence_Lower_Idx (Fence));
144 Regs.Read (Fence_Upper, Fence_Upper_Idx (Fence));
145 if (Fence_Lower and FENCE_PAGE_MASK) = Page_Lower and
146 (Fence_Upper and FENCE_PAGE_MASK) = Page_Upper
147 then
148 Regs.Write (Fence_Lower_Idx (Fence), 0);
149 exit;
150 end if;
151 end loop;
152 end Remove_Fence;
153
Nico Huber17d64b62017-07-15 20:51:25 +0200154 ----------------------------------------------------------------------------
155
Nico Huber83693c82016-10-08 22:17:55 +0200156 procedure Write_GTT
157 (GTT_Page : GTT_Range;
158 Device_Address : GTT_Address_Type;
159 Valid : Boolean)
160 is
161 begin
Nico Huber0b2329a2018-06-09 21:14:27 +0200162 if not Config.Has_64bit_GTT then
163 GTT_32.Write
Nico Huber83693c82016-10-08 22:17:55 +0200164 (Index => GTT_Page,
Nico Huber0b2329a2018-06-09 21:14:27 +0200165 Value => GTT_PTE_32 (Device_Address and 16#ffff_f000#) or
166 GTT_PTE_32 (Shift_Right (Word64 (Device_Address), 32 - 4)
Nico Huber83693c82016-10-08 22:17:55 +0200167 and 16#0000_07f0#) or
168 Boolean'Pos (Valid));
169 else
Nico Huber0b2329a2018-06-09 21:14:27 +0200170 GTT_64.Write
Nico Huber83693c82016-10-08 22:17:55 +0200171 (Index => GTT_Page,
Nico Huber0b2329a2018-06-09 21:14:27 +0200172 Value => GTT_PTE_64 (Device_Address and 16#7f_ffff_f000#) or
Nico Huber83693c82016-10-08 22:17:55 +0200173 Boolean'Pos (Valid));
174 end if;
175 end Write_GTT;
176
Nico Huberceda17d2018-06-09 22:00:29 +0200177 procedure Read_GTT
178 (Device_Address : out GTT_Address_Type;
179 Valid : out Boolean;
180 GTT_Page : in GTT_Range)
181 is
182 begin
183 if not Config.Has_64bit_GTT then
184 declare
185 PTE : GTT_PTE_32;
186 begin
187 GTT_32.Read (PTE, GTT_Page);
188 Valid := (PTE and GTT_PTE_Valid) /= 0;
189 Device_Address := GTT_Address_Type
190 (Shift_Left (Word64 (PTE and 16#07f0#), 32 - 4) or
191 Word64 (PTE and 16#ffff_f000#));
192 end;
193 else
194 declare
195 PTE : GTT_PTE_64;
196 begin
197 GTT_64.Read (PTE, GTT_Page);
198 Valid := (PTE and GTT_PTE_Valid) /= 0;
199 Device_Address := GTT_Address_Type (PTE and 16#7f_ffff_f000#);
200 end;
201 end if;
202 end Read_GTT;
203
Nico Huber83693c82016-10-08 22:17:55 +0200204 ----------------------------------------------------------------------------
205
206 package Rep is
207 function Index (Reg : Registers_Index) return Registers_Range;
208 end Rep;
209
210 package body Rep is
211 function Index (Reg : Registers_Index) return Registers_Range
212 with
213 SPARK_Mode => Off
214 is
215 begin
216 return Reg'Enum_Rep;
217 end Index;
218 end Rep;
219
220 -- Read a specific register
221 procedure Read
222 (Register : in Registers_Index;
223 Value : out Word32;
224 Verbose : in Boolean := True)
225 is
226 begin
227 Regs.Read (Value, Rep.Index (Register));
228
229 pragma Debug (Verbose, Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
230 pragma Debug (Verbose, Debug.Put_Word32 (Value));
231 pragma Debug (Verbose, Debug.Put (" <- "));
232 pragma Debug (Verbose, Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
233 pragma Debug (Verbose, Debug.Put (":"));
234 pragma Debug (Verbose, Debug.Put_Line (Registers_Index'Image (Register)));
235 end Read;
236
237 ----------------------------------------------------------------------------
238
239 -- Read a specific register to post a previous write
240 procedure Posting_Read (Register : Registers_Index)
241 is
242 Discard_Value : Word32;
243 begin
244 pragma Warnings
245 (Off, "unused assignment to ""Discard_Value""",
246 Reason => "Intentional dummy read to affect hardware.");
247
248 Read (Register, Discard_Value);
249
250 pragma Warnings
251 (On, "unused assignment to ""Discard_Value""");
252 end Posting_Read;
253
254 ----------------------------------------------------------------------------
255
256 -- Write a specific register
257 procedure Write (Register : Registers_Index; Value : Word32)
258 is
259 begin
260 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
261 pragma Debug (Debug.Put_Word32 (Value));
262 pragma Debug (Debug.Put (" -> "));
263 pragma Debug (Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
264 pragma Debug (Debug.Put (":"));
265 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
266
267 Regs.Write (Rep.Index (Register), Value);
268 pragma Debug (Debug.Register_Write_Wait);
269 end Write;
270
271 ----------------------------------------------------------------------------
272
273 -- Check whether all bits in @Register@ indicated by @Mask@ are set
274 procedure Is_Set_Mask
275 (Register : in Registers_Index;
276 Mask : in Word32;
277 Result : out Boolean)
278 is
279 Value : Word32;
280 begin
281 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
282 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
283
284 Read (Register, Value);
285 Result := (Value and Mask) = Mask;
286
287 end Is_Set_Mask;
288
289 ----------------------------------------------------------------------------
290
291 -- TODO: Should have Success parameter
Nico Huberbcb2c472017-02-02 16:39:26 +0100292 -- Wait for the bits in @Register@ indicated by @Mask@ to be of @Value@
293 procedure Wait
294 (Register : Registers_Index;
295 Mask : Word32;
296 Value : Word32;
297 TOut_MS : Natural := Default_Timeout_MS;
298 Verbose : Boolean := False)
299 is
300 Current : Word32;
301 Timeout : Time.T;
302 Timed_Out : Boolean;
303 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
315 Timed_Out := Time.Timed_Out (Timeout);
316 Read (Register, Current, Verbose);
317 if (Current and Mask) = Value then
318 exit;
319 end if;
320 pragma Debug (Timed_Out, Debug.Put (GNAT.Source_Info.Enclosing_Entity));
321 pragma Debug (Timed_Out, Debug.Put_Line (": Timed Out!"));
322 exit when Timed_Out;
323 end loop;
324 end Wait;
325
326 ----------------------------------------------------------------------------
327
328 -- TODO: Should have Success parameter
Nico Huber83693c82016-10-08 22:17:55 +0200329 -- Wait for all bits in @Register@ indicated by @Mask@ to be set
330 procedure Wait_Set_Mask
331 (Register : in Registers_Index;
332 Mask : in Word32;
333 TOut_MS : in Natural := Default_Timeout_MS;
334 Verbose : in Boolean := False)
335 is
Nico Huber83693c82016-10-08 22:17:55 +0200336 begin
Nico Huberbcb2c472017-02-02 16:39:26 +0100337 Wait (Register, Mask, Mask, TOut_MS, Verbose);
Nico Huber83693c82016-10-08 22:17:55 +0200338 end Wait_Set_Mask;
339
340 ----------------------------------------------------------------------------
341
342 -- TODO: Should have Success parameter
343 -- Wait for bits in @Register@ indicated by @Mask@ to be clear
344 procedure Wait_Unset_Mask
345 (Register : Registers_Index;
346 Mask : Word32;
347 TOut_MS : in Natural := Default_Timeout_MS;
348 Verbose : in Boolean := False)
349 is
Nico Huber83693c82016-10-08 22:17:55 +0200350 begin
Nico Huberbcb2c472017-02-02 16:39:26 +0100351 Wait (Register, Mask, 0, TOut_MS, Verbose);
Nico Huber83693c82016-10-08 22:17:55 +0200352 end Wait_Unset_Mask;
353
354 ----------------------------------------------------------------------------
355
356 -- Set bits from @Mask@ in @Register@
357 procedure Set_Mask
358 (Register : Registers_Index;
359 Mask : Word32)
360 is
361 Value : Word32;
362 begin
363 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
364 pragma Debug (Debug.Put_Word32 (Mask));
365 pragma Debug (Debug.Put (" .S "));
366 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
367
368 Read (Register, Value);
369 Value := Value or Mask;
370 Write (Register, Value);
371 end Set_Mask;
372
373 ----------------------------------------------------------------------------
374
375 -- Mask out @Mask@ in @Register@
376 procedure Unset_Mask
377 (Register : Registers_Index;
378 Mask : Word32)
379 is
380 Value : Word32;
381 begin
382 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
383 pragma Debug (Debug.Put_Word32 (Mask));
384 pragma Debug (Debug.Put (" !S "));
385 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
386
387 Read (Register, Value);
388 Value := Value and not Mask;
389 Write (Register, Value);
390 end Unset_Mask;
391
392 ----------------------------------------------------------------------------
393
394 -- Mask out @Unset_Mask@ and set @Set_Mask@ in @Register@
395 procedure Unset_And_Set_Mask
396 (Register : Registers_Index;
397 Mask_Unset : Word32;
398 Mask_Set : Word32)
399 is
400 Value : Word32;
401 begin
402 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
403 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
404
405 Read (Register, Value);
406 Value := (Value and not Mask_Unset) or Mask_Set;
407 Write (Register, Value);
408 end Unset_And_Set_Mask;
409
410 ----------------------------------------------------------------------------
411
Nico Huber2b6f6992017-07-09 18:11:34 +0200412 procedure Set_Register_Base (Base : Word64; GTT_Base : Word64 := 0)
Nico Huber83693c82016-10-08 22:17:55 +0200413 is
414 begin
415 Regs.Set_Base_Address (Base);
Nico Huber2b6f6992017-07-09 18:11:34 +0200416 if GTT_Base = 0 then
Nico Huber0b2329a2018-06-09 21:14:27 +0200417 GTT_32.Set_Base_Address (Base + MMIO_GTT_32_Offset);
418 GTT_64.Set_Base_Address (Base + MMIO_GTT_64_Offset);
Nico Huber2b6f6992017-07-09 18:11:34 +0200419 else
Nico Huber0b2329a2018-06-09 21:14:27 +0200420 GTT_32.Set_Base_Address (GTT_Base);
421 GTT_64.Set_Base_Address (GTT_Base);
Nico Huber2b6f6992017-07-09 18:11:34 +0200422 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200423 end Set_Register_Base;
424
425end HW.GFX.GMA.Registers;