blob: 9b14a3b41d244b849f256f9c943e26f623b567c0 [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
72 GTT_PTE_Valid : constant Word32 := 1;
73
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
177 ----------------------------------------------------------------------------
178
179 package Rep is
180 function Index (Reg : Registers_Index) return Registers_Range;
181 end Rep;
182
183 package body Rep is
184 function Index (Reg : Registers_Index) return Registers_Range
185 with
186 SPARK_Mode => Off
187 is
188 begin
189 return Reg'Enum_Rep;
190 end Index;
191 end Rep;
192
193 -- Read a specific register
194 procedure Read
195 (Register : in Registers_Index;
196 Value : out Word32;
197 Verbose : in Boolean := True)
198 is
199 begin
200 Regs.Read (Value, Rep.Index (Register));
201
202 pragma Debug (Verbose, Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
203 pragma Debug (Verbose, Debug.Put_Word32 (Value));
204 pragma Debug (Verbose, Debug.Put (" <- "));
205 pragma Debug (Verbose, Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
206 pragma Debug (Verbose, Debug.Put (":"));
207 pragma Debug (Verbose, Debug.Put_Line (Registers_Index'Image (Register)));
208 end Read;
209
210 ----------------------------------------------------------------------------
211
212 -- Read a specific register to post a previous write
213 procedure Posting_Read (Register : Registers_Index)
214 is
215 Discard_Value : Word32;
216 begin
217 pragma Warnings
218 (Off, "unused assignment to ""Discard_Value""",
219 Reason => "Intentional dummy read to affect hardware.");
220
221 Read (Register, Discard_Value);
222
223 pragma Warnings
224 (On, "unused assignment to ""Discard_Value""");
225 end Posting_Read;
226
227 ----------------------------------------------------------------------------
228
229 -- Write a specific register
230 procedure Write (Register : Registers_Index; Value : Word32)
231 is
232 begin
233 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
234 pragma Debug (Debug.Put_Word32 (Value));
235 pragma Debug (Debug.Put (" -> "));
236 pragma Debug (Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
237 pragma Debug (Debug.Put (":"));
238 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
239
240 Regs.Write (Rep.Index (Register), Value);
241 pragma Debug (Debug.Register_Write_Wait);
242 end Write;
243
244 ----------------------------------------------------------------------------
245
246 -- Check whether all bits in @Register@ indicated by @Mask@ are set
247 procedure Is_Set_Mask
248 (Register : in Registers_Index;
249 Mask : in Word32;
250 Result : out Boolean)
251 is
252 Value : Word32;
253 begin
254 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
255 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
256
257 Read (Register, Value);
258 Result := (Value and Mask) = Mask;
259
260 end Is_Set_Mask;
261
262 ----------------------------------------------------------------------------
263
264 -- TODO: Should have Success parameter
Nico Huberbcb2c472017-02-02 16:39:26 +0100265 -- Wait for the bits in @Register@ indicated by @Mask@ to be of @Value@
266 procedure Wait
267 (Register : Registers_Index;
268 Mask : Word32;
269 Value : Word32;
270 TOut_MS : Natural := Default_Timeout_MS;
271 Verbose : Boolean := False)
272 is
273 Current : Word32;
274 Timeout : Time.T;
275 Timed_Out : Boolean;
276 begin
277 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
278 pragma Debug (Debug.Put_Word32 (Value));
279 pragma Debug (Debug.Put (" <- "));
280 pragma Debug (Debug.Put_Word32 (Mask));
281 pragma Debug (Debug.Put (" & "));
282 pragma Debug (Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
283 pragma Debug (Debug.Put (":"));
284 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
285
286 Timeout := Time.MS_From_Now (TOut_MS);
287 loop
288 Timed_Out := Time.Timed_Out (Timeout);
289 Read (Register, Current, Verbose);
290 if (Current and Mask) = Value then
291 exit;
292 end if;
293 pragma Debug (Timed_Out, Debug.Put (GNAT.Source_Info.Enclosing_Entity));
294 pragma Debug (Timed_Out, Debug.Put_Line (": Timed Out!"));
295 exit when Timed_Out;
296 end loop;
297 end Wait;
298
299 ----------------------------------------------------------------------------
300
301 -- TODO: Should have Success parameter
Nico Huber83693c82016-10-08 22:17:55 +0200302 -- Wait for all bits in @Register@ indicated by @Mask@ to be set
303 procedure Wait_Set_Mask
304 (Register : in Registers_Index;
305 Mask : in Word32;
306 TOut_MS : in Natural := Default_Timeout_MS;
307 Verbose : in Boolean := False)
308 is
Nico Huber83693c82016-10-08 22:17:55 +0200309 begin
Nico Huberbcb2c472017-02-02 16:39:26 +0100310 Wait (Register, Mask, Mask, TOut_MS, Verbose);
Nico Huber83693c82016-10-08 22:17:55 +0200311 end Wait_Set_Mask;
312
313 ----------------------------------------------------------------------------
314
315 -- TODO: Should have Success parameter
316 -- Wait for bits in @Register@ indicated by @Mask@ to be clear
317 procedure Wait_Unset_Mask
318 (Register : Registers_Index;
319 Mask : Word32;
320 TOut_MS : in Natural := Default_Timeout_MS;
321 Verbose : in Boolean := False)
322 is
Nico Huber83693c82016-10-08 22:17:55 +0200323 begin
Nico Huberbcb2c472017-02-02 16:39:26 +0100324 Wait (Register, Mask, 0, TOut_MS, Verbose);
Nico Huber83693c82016-10-08 22:17:55 +0200325 end Wait_Unset_Mask;
326
327 ----------------------------------------------------------------------------
328
329 -- Set bits from @Mask@ in @Register@
330 procedure Set_Mask
331 (Register : Registers_Index;
332 Mask : Word32)
333 is
334 Value : Word32;
335 begin
336 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
337 pragma Debug (Debug.Put_Word32 (Mask));
338 pragma Debug (Debug.Put (" .S "));
339 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
340
341 Read (Register, Value);
342 Value := Value or Mask;
343 Write (Register, Value);
344 end Set_Mask;
345
346 ----------------------------------------------------------------------------
347
348 -- Mask out @Mask@ in @Register@
349 procedure Unset_Mask
350 (Register : Registers_Index;
351 Mask : Word32)
352 is
353 Value : Word32;
354 begin
355 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
356 pragma Debug (Debug.Put_Word32 (Mask));
357 pragma Debug (Debug.Put (" !S "));
358 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
359
360 Read (Register, Value);
361 Value := Value and not Mask;
362 Write (Register, Value);
363 end Unset_Mask;
364
365 ----------------------------------------------------------------------------
366
367 -- Mask out @Unset_Mask@ and set @Set_Mask@ in @Register@
368 procedure Unset_And_Set_Mask
369 (Register : Registers_Index;
370 Mask_Unset : Word32;
371 Mask_Set : Word32)
372 is
373 Value : Word32;
374 begin
375 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
376 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
377
378 Read (Register, Value);
379 Value := (Value and not Mask_Unset) or Mask_Set;
380 Write (Register, Value);
381 end Unset_And_Set_Mask;
382
383 ----------------------------------------------------------------------------
384
Nico Huber2b6f6992017-07-09 18:11:34 +0200385 procedure Set_Register_Base (Base : Word64; GTT_Base : Word64 := 0)
Nico Huber83693c82016-10-08 22:17:55 +0200386 is
387 begin
388 Regs.Set_Base_Address (Base);
Nico Huber2b6f6992017-07-09 18:11:34 +0200389 if GTT_Base = 0 then
Nico Huber0b2329a2018-06-09 21:14:27 +0200390 GTT_32.Set_Base_Address (Base + MMIO_GTT_32_Offset);
391 GTT_64.Set_Base_Address (Base + MMIO_GTT_64_Offset);
Nico Huber2b6f6992017-07-09 18:11:34 +0200392 else
Nico Huber0b2329a2018-06-09 21:14:27 +0200393 GTT_32.Set_Base_Address (GTT_Base);
394 GTT_64.Set_Base_Address (GTT_Base);
Nico Huber2b6f6992017-07-09 18:11:34 +0200395 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200396 end Set_Register_Base;
397
398end HW.GFX.GMA.Registers;