blob: 94965d57afef9731d185a8878d37c961b8399697 [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 =>
29 (Address_State => (Regs.Base_Address, GTT.Base_Address),
30 Register_State => Regs.State,
31 GTT_State => GTT.State)
32is
33 pragma Disable_Atomic_Synchronization;
34
35 type Registers_Range is
36 new Natural range 0 .. 16#0020_0000# / Register_Width - 1;
37 type Registers_Type is array (Registers_Range) of Word32
38 with
39 Atomic_Components,
40 Size => 16#20_0000# * 8;
41 package Regs is new MMIO_Range
42 (Base_Addr => Config.Default_MMIO_Base,
43 Element_T => Word32,
44 Index_T => Registers_Range,
45 Array_T => Registers_Type);
46
47 ----------------------------------------------------------------------------
48
Nico Huberb8ae6182017-07-15 20:03:56 +020049 type GTT_PTE_Type is mod 2 ** (Config.GTT_PTE_Size * 8);
Nico Huber83693c82016-10-08 22:17:55 +020050 type GTT_Registers_Type is array (GTT_Range) of GTT_PTE_Type
51 with
52 Volatile_Components,
Nico Huberb8ae6182017-07-15 20:03:56 +020053 Size => Config.GTT_Size * 8;
Nico Huber83693c82016-10-08 22:17:55 +020054 package GTT is new MMIO_Range
Nico Huberb8ae6182017-07-15 20:03:56 +020055 (Base_Addr => Config.Default_MMIO_Base + Config.GTT_Offset,
Nico Huber83693c82016-10-08 22:17:55 +020056 Element_T => GTT_PTE_Type,
57 Index_T => GTT_Range,
58 Array_T => GTT_Registers_Type);
59
60 GTT_PTE_Valid : constant Word32 := 1;
61
62 ----------------------------------------------------------------------------
63
Nico Huberb03c8f12017-08-25 13:29:08 +020064 subtype Fence_Range is Registers_Range range 0 .. Config.Fence_Count - 1;
65
66 FENCE_PAGE_SHIFT : constant := 12;
67 FENCE_PAGE_MASK : constant := 16#ffff_f000#;
68 FENCE_TILE_WALK_YMAJOR : constant := 1 * 2 ** 1;
69 FENCE_VALID : constant := 1 * 2 ** 0;
70
71 function Fence_Lower_Idx (Fence : Fence_Range) return Registers_Range is
72 (Config.Fence_Base / Register_Width + 2 * Fence);
73 function Fence_Upper_Idx (Fence : Fence_Range) return Registers_Range is
74 (Fence_Lower_Idx (Fence) + 1);
75
Nico Huber17d64b62017-07-15 20:51:25 +020076 procedure Clear_Fences
77 is
Nico Huber17d64b62017-07-15 20:51:25 +020078 begin
Nico Huberb03c8f12017-08-25 13:29:08 +020079 for Fence in Fence_Range loop
80 Regs.Write (Fence_Lower_Idx (Fence), 0);
Nico Huber17d64b62017-07-15 20:51:25 +020081 end loop;
82 end Clear_Fences;
83
Nico Huberb03c8f12017-08-25 13:29:08 +020084 procedure Add_Fence
85 (First_Page : in GTT_Range;
86 Last_Page : in GTT_Range;
87 Tiling : in XY_Tiling;
88 Pitch : in Natural;
89 Success : out Boolean)
90 is
91 Y_Tiles : constant Boolean := Tiling = Y_Tiled;
92 Reg32 : Word32;
93 begin
94 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
95 pragma Debug (Debug.Put_Word32 (Shift_Left (Word32 (First_Page), 12)));
96 pragma Debug (Debug.Put (":"));
97 pragma Debug (Debug.Put_Word32 (Shift_Left (Word32 (Last_Page), 12)));
98 pragma Debug (not Y_Tiles, Debug.Put (" X tiled in "));
99 pragma Debug ( Y_Tiles, Debug.Put (" Y tiled in "));
100 pragma Debug (Debug.Put_Int32 (Int32 (Pitch)));
101 pragma Debug (Debug.Put_Line (" tiles per row."));
102
103 Success := False;
104 for Fence in Fence_Range loop
105 Regs.Read (Reg32, Fence_Lower_Idx (Fence));
106 if (Reg32 and FENCE_VALID) = 0 then
107 Regs.Write
108 (Index => Fence_Lower_Idx (Fence),
109 Value => Shift_Left (Word32 (First_Page), FENCE_PAGE_SHIFT) or
110 (if Y_Tiles then FENCE_TILE_WALK_YMAJOR else 0) or
111 FENCE_VALID);
112 Regs.Write
113 (Index => Fence_Upper_Idx (Fence),
114 Value => Shift_Left (Word32 (Last_Page), FENCE_PAGE_SHIFT) or
115 Word32 (Pitch) * (if Y_Tiles then 1 else 4) - 1);
116 Success := True;
117 exit;
118 end if;
119 end loop;
120 end Add_Fence;
121
122 procedure Remove_Fence (First_Page, Last_Page : GTT_Range)
123 is
124 Page_Lower : constant Word32 :=
125 Shift_Left (Word32 (First_Page), FENCE_PAGE_SHIFT);
126 Page_Upper : constant Word32 :=
127 Shift_Left (Word32 (Last_Page), FENCE_PAGE_SHIFT);
128 Fence_Upper, Fence_Lower : Word32;
129 begin
130 for Fence in Fence_Range loop
131 Regs.Read (Fence_Lower, Fence_Lower_Idx (Fence));
132 Regs.Read (Fence_Upper, Fence_Upper_Idx (Fence));
133 if (Fence_Lower and FENCE_PAGE_MASK) = Page_Lower and
134 (Fence_Upper and FENCE_PAGE_MASK) = Page_Upper
135 then
136 Regs.Write (Fence_Lower_Idx (Fence), 0);
137 exit;
138 end if;
139 end loop;
140 end Remove_Fence;
141
Nico Huber17d64b62017-07-15 20:51:25 +0200142 ----------------------------------------------------------------------------
143
Nico Huber83693c82016-10-08 22:17:55 +0200144 procedure Write_GTT
145 (GTT_Page : GTT_Range;
146 Device_Address : GTT_Address_Type;
147 Valid : Boolean)
148 is
149 begin
150 if Config.Fold_39Bit_GTT_PTE then
151 GTT.Write
152 (Index => GTT_Page,
153 Value => GTT_PTE_Type (Device_Address and 16#ffff_f000#) or
154 GTT_PTE_Type (Shift_Right (Word64 (Device_Address), 32 - 4)
155 and 16#0000_07f0#) or
156 Boolean'Pos (Valid));
157 else
158 GTT.Write
159 (Index => GTT_Page,
160 Value => GTT_PTE_Type (Device_Address and 16#7f_ffff_f000#) or
161 Boolean'Pos (Valid));
162 end if;
163 end Write_GTT;
164
165 ----------------------------------------------------------------------------
166
167 package Rep is
168 function Index (Reg : Registers_Index) return Registers_Range;
169 end Rep;
170
171 package body Rep is
172 function Index (Reg : Registers_Index) return Registers_Range
173 with
174 SPARK_Mode => Off
175 is
176 begin
177 return Reg'Enum_Rep;
178 end Index;
179 end Rep;
180
181 -- Read a specific register
182 procedure Read
183 (Register : in Registers_Index;
184 Value : out Word32;
185 Verbose : in Boolean := True)
186 is
187 begin
188 Regs.Read (Value, Rep.Index (Register));
189
190 pragma Debug (Verbose, Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
191 pragma Debug (Verbose, Debug.Put_Word32 (Value));
192 pragma Debug (Verbose, Debug.Put (" <- "));
193 pragma Debug (Verbose, Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
194 pragma Debug (Verbose, Debug.Put (":"));
195 pragma Debug (Verbose, Debug.Put_Line (Registers_Index'Image (Register)));
196 end Read;
197
198 ----------------------------------------------------------------------------
199
200 -- Read a specific register to post a previous write
201 procedure Posting_Read (Register : Registers_Index)
202 is
203 Discard_Value : Word32;
204 begin
205 pragma Warnings
206 (Off, "unused assignment to ""Discard_Value""",
207 Reason => "Intentional dummy read to affect hardware.");
208
209 Read (Register, Discard_Value);
210
211 pragma Warnings
212 (On, "unused assignment to ""Discard_Value""");
213 end Posting_Read;
214
215 ----------------------------------------------------------------------------
216
217 -- Write a specific register
218 procedure Write (Register : Registers_Index; Value : Word32)
219 is
220 begin
221 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
222 pragma Debug (Debug.Put_Word32 (Value));
223 pragma Debug (Debug.Put (" -> "));
224 pragma Debug (Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
225 pragma Debug (Debug.Put (":"));
226 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
227
228 Regs.Write (Rep.Index (Register), Value);
229 pragma Debug (Debug.Register_Write_Wait);
230 end Write;
231
232 ----------------------------------------------------------------------------
233
234 -- Check whether all bits in @Register@ indicated by @Mask@ are set
235 procedure Is_Set_Mask
236 (Register : in Registers_Index;
237 Mask : in Word32;
238 Result : out Boolean)
239 is
240 Value : Word32;
241 begin
242 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
243 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
244
245 Read (Register, Value);
246 Result := (Value and Mask) = Mask;
247
248 end Is_Set_Mask;
249
250 ----------------------------------------------------------------------------
251
252 -- TODO: Should have Success parameter
Nico Huberbcb2c472017-02-02 16:39:26 +0100253 -- Wait for the bits in @Register@ indicated by @Mask@ to be of @Value@
254 procedure Wait
255 (Register : Registers_Index;
256 Mask : Word32;
257 Value : Word32;
258 TOut_MS : Natural := Default_Timeout_MS;
259 Verbose : Boolean := False)
260 is
261 Current : Word32;
262 Timeout : Time.T;
263 Timed_Out : Boolean;
264 begin
265 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
266 pragma Debug (Debug.Put_Word32 (Value));
267 pragma Debug (Debug.Put (" <- "));
268 pragma Debug (Debug.Put_Word32 (Mask));
269 pragma Debug (Debug.Put (" & "));
270 pragma Debug (Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
271 pragma Debug (Debug.Put (":"));
272 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
273
274 Timeout := Time.MS_From_Now (TOut_MS);
275 loop
276 Timed_Out := Time.Timed_Out (Timeout);
277 Read (Register, Current, Verbose);
278 if (Current and Mask) = Value then
279 exit;
280 end if;
281 pragma Debug (Timed_Out, Debug.Put (GNAT.Source_Info.Enclosing_Entity));
282 pragma Debug (Timed_Out, Debug.Put_Line (": Timed Out!"));
283 exit when Timed_Out;
284 end loop;
285 end Wait;
286
287 ----------------------------------------------------------------------------
288
289 -- TODO: Should have Success parameter
Nico Huber83693c82016-10-08 22:17:55 +0200290 -- Wait for all bits in @Register@ indicated by @Mask@ to be set
291 procedure Wait_Set_Mask
292 (Register : in Registers_Index;
293 Mask : in Word32;
294 TOut_MS : in Natural := Default_Timeout_MS;
295 Verbose : in Boolean := False)
296 is
Nico Huber83693c82016-10-08 22:17:55 +0200297 begin
Nico Huberbcb2c472017-02-02 16:39:26 +0100298 Wait (Register, Mask, Mask, TOut_MS, Verbose);
Nico Huber83693c82016-10-08 22:17:55 +0200299 end Wait_Set_Mask;
300
301 ----------------------------------------------------------------------------
302
303 -- TODO: Should have Success parameter
304 -- Wait for bits in @Register@ indicated by @Mask@ to be clear
305 procedure Wait_Unset_Mask
306 (Register : Registers_Index;
307 Mask : Word32;
308 TOut_MS : in Natural := Default_Timeout_MS;
309 Verbose : in Boolean := False)
310 is
Nico Huber83693c82016-10-08 22:17:55 +0200311 begin
Nico Huberbcb2c472017-02-02 16:39:26 +0100312 Wait (Register, Mask, 0, TOut_MS, Verbose);
Nico Huber83693c82016-10-08 22:17:55 +0200313 end Wait_Unset_Mask;
314
315 ----------------------------------------------------------------------------
316
317 -- Set bits from @Mask@ in @Register@
318 procedure Set_Mask
319 (Register : Registers_Index;
320 Mask : Word32)
321 is
322 Value : Word32;
323 begin
324 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
325 pragma Debug (Debug.Put_Word32 (Mask));
326 pragma Debug (Debug.Put (" .S "));
327 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
328
329 Read (Register, Value);
330 Value := Value or Mask;
331 Write (Register, Value);
332 end Set_Mask;
333
334 ----------------------------------------------------------------------------
335
336 -- Mask out @Mask@ in @Register@
337 procedure Unset_Mask
338 (Register : Registers_Index;
339 Mask : Word32)
340 is
341 Value : Word32;
342 begin
343 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
344 pragma Debug (Debug.Put_Word32 (Mask));
345 pragma Debug (Debug.Put (" !S "));
346 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
347
348 Read (Register, Value);
349 Value := Value and not Mask;
350 Write (Register, Value);
351 end Unset_Mask;
352
353 ----------------------------------------------------------------------------
354
355 -- Mask out @Unset_Mask@ and set @Set_Mask@ in @Register@
356 procedure Unset_And_Set_Mask
357 (Register : Registers_Index;
358 Mask_Unset : Word32;
359 Mask_Set : Word32)
360 is
361 Value : Word32;
362 begin
363 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
364 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
365
366 Read (Register, Value);
367 Value := (Value and not Mask_Unset) or Mask_Set;
368 Write (Register, Value);
369 end Unset_And_Set_Mask;
370
371 ----------------------------------------------------------------------------
372
Nico Huber2b6f6992017-07-09 18:11:34 +0200373 procedure Set_Register_Base (Base : Word64; GTT_Base : Word64 := 0)
Nico Huber83693c82016-10-08 22:17:55 +0200374 is
375 begin
376 Regs.Set_Base_Address (Base);
Nico Huber2b6f6992017-07-09 18:11:34 +0200377 if GTT_Base = 0 then
378 GTT.Set_Base_Address (Base + Config.GTT_Offset);
379 else
380 GTT.Set_Base_Address (GTT_Base);
381 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200382 end Set_Register_Base;
383
384end HW.GFX.GMA.Registers;