blob: 4a22564b87ce07742896026eefd1a10be634651d [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 Huber17d64b62017-07-15 20:51:25 +020064 procedure Clear_Fences
65 is
66 Fence_Regs_Base : constant :=
67 (case Config.CPU is
68 when Ironlake => 16#00_3000#,
69 when Sandybridge .. Skylake => 16#10_0000#);
70 subtype Fence_Range is Registers_Range range 0 .. 63;
71 begin
72 for Idx in Fence_Range loop
73 Regs.Write (Fence_Regs_Base / Register_Width + Idx, 0);
74 end loop;
75 end Clear_Fences;
76
77 ----------------------------------------------------------------------------
78
Nico Huber83693c82016-10-08 22:17:55 +020079 procedure Write_GTT
80 (GTT_Page : GTT_Range;
81 Device_Address : GTT_Address_Type;
82 Valid : Boolean)
83 is
84 begin
85 if Config.Fold_39Bit_GTT_PTE then
86 GTT.Write
87 (Index => GTT_Page,
88 Value => GTT_PTE_Type (Device_Address and 16#ffff_f000#) or
89 GTT_PTE_Type (Shift_Right (Word64 (Device_Address), 32 - 4)
90 and 16#0000_07f0#) or
91 Boolean'Pos (Valid));
92 else
93 GTT.Write
94 (Index => GTT_Page,
95 Value => GTT_PTE_Type (Device_Address and 16#7f_ffff_f000#) or
96 Boolean'Pos (Valid));
97 end if;
98 end Write_GTT;
99
100 ----------------------------------------------------------------------------
101
102 package Rep is
103 function Index (Reg : Registers_Index) return Registers_Range;
104 end Rep;
105
106 package body Rep is
107 function Index (Reg : Registers_Index) return Registers_Range
108 with
109 SPARK_Mode => Off
110 is
111 begin
112 return Reg'Enum_Rep;
113 end Index;
114 end Rep;
115
116 -- Read a specific register
117 procedure Read
118 (Register : in Registers_Index;
119 Value : out Word32;
120 Verbose : in Boolean := True)
121 is
122 begin
123 Regs.Read (Value, Rep.Index (Register));
124
125 pragma Debug (Verbose, Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
126 pragma Debug (Verbose, Debug.Put_Word32 (Value));
127 pragma Debug (Verbose, Debug.Put (" <- "));
128 pragma Debug (Verbose, Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
129 pragma Debug (Verbose, Debug.Put (":"));
130 pragma Debug (Verbose, Debug.Put_Line (Registers_Index'Image (Register)));
131 end Read;
132
133 ----------------------------------------------------------------------------
134
135 -- Read a specific register to post a previous write
136 procedure Posting_Read (Register : Registers_Index)
137 is
138 Discard_Value : Word32;
139 begin
140 pragma Warnings
141 (Off, "unused assignment to ""Discard_Value""",
142 Reason => "Intentional dummy read to affect hardware.");
143
144 Read (Register, Discard_Value);
145
146 pragma Warnings
147 (On, "unused assignment to ""Discard_Value""");
148 end Posting_Read;
149
150 ----------------------------------------------------------------------------
151
152 -- Write a specific register
153 procedure Write (Register : Registers_Index; Value : Word32)
154 is
155 begin
156 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
157 pragma Debug (Debug.Put_Word32 (Value));
158 pragma Debug (Debug.Put (" -> "));
159 pragma Debug (Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
160 pragma Debug (Debug.Put (":"));
161 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
162
163 Regs.Write (Rep.Index (Register), Value);
164 pragma Debug (Debug.Register_Write_Wait);
165 end Write;
166
167 ----------------------------------------------------------------------------
168
169 -- Check whether all bits in @Register@ indicated by @Mask@ are set
170 procedure Is_Set_Mask
171 (Register : in Registers_Index;
172 Mask : in Word32;
173 Result : out Boolean)
174 is
175 Value : Word32;
176 begin
177 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
178 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
179
180 Read (Register, Value);
181 Result := (Value and Mask) = Mask;
182
183 end Is_Set_Mask;
184
185 ----------------------------------------------------------------------------
186
187 -- TODO: Should have Success parameter
Nico Huberbcb2c472017-02-02 16:39:26 +0100188 -- Wait for the bits in @Register@ indicated by @Mask@ to be of @Value@
189 procedure Wait
190 (Register : Registers_Index;
191 Mask : Word32;
192 Value : Word32;
193 TOut_MS : Natural := Default_Timeout_MS;
194 Verbose : Boolean := False)
195 is
196 Current : Word32;
197 Timeout : Time.T;
198 Timed_Out : Boolean;
199 begin
200 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
201 pragma Debug (Debug.Put_Word32 (Value));
202 pragma Debug (Debug.Put (" <- "));
203 pragma Debug (Debug.Put_Word32 (Mask));
204 pragma Debug (Debug.Put (" & "));
205 pragma Debug (Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
206 pragma Debug (Debug.Put (":"));
207 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
208
209 Timeout := Time.MS_From_Now (TOut_MS);
210 loop
211 Timed_Out := Time.Timed_Out (Timeout);
212 Read (Register, Current, Verbose);
213 if (Current and Mask) = Value then
214 exit;
215 end if;
216 pragma Debug (Timed_Out, Debug.Put (GNAT.Source_Info.Enclosing_Entity));
217 pragma Debug (Timed_Out, Debug.Put_Line (": Timed Out!"));
218 exit when Timed_Out;
219 end loop;
220 end Wait;
221
222 ----------------------------------------------------------------------------
223
224 -- TODO: Should have Success parameter
Nico Huber83693c82016-10-08 22:17:55 +0200225 -- Wait for all bits in @Register@ indicated by @Mask@ to be set
226 procedure Wait_Set_Mask
227 (Register : in Registers_Index;
228 Mask : in Word32;
229 TOut_MS : in Natural := Default_Timeout_MS;
230 Verbose : in Boolean := False)
231 is
Nico Huber83693c82016-10-08 22:17:55 +0200232 begin
Nico Huberbcb2c472017-02-02 16:39:26 +0100233 Wait (Register, Mask, Mask, TOut_MS, Verbose);
Nico Huber83693c82016-10-08 22:17:55 +0200234 end Wait_Set_Mask;
235
236 ----------------------------------------------------------------------------
237
238 -- TODO: Should have Success parameter
239 -- Wait for bits in @Register@ indicated by @Mask@ to be clear
240 procedure Wait_Unset_Mask
241 (Register : Registers_Index;
242 Mask : Word32;
243 TOut_MS : in Natural := Default_Timeout_MS;
244 Verbose : in Boolean := False)
245 is
Nico Huber83693c82016-10-08 22:17:55 +0200246 begin
Nico Huberbcb2c472017-02-02 16:39:26 +0100247 Wait (Register, Mask, 0, TOut_MS, Verbose);
Nico Huber83693c82016-10-08 22:17:55 +0200248 end Wait_Unset_Mask;
249
250 ----------------------------------------------------------------------------
251
252 -- Set bits from @Mask@ in @Register@
253 procedure Set_Mask
254 (Register : Registers_Index;
255 Mask : Word32)
256 is
257 Value : Word32;
258 begin
259 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
260 pragma Debug (Debug.Put_Word32 (Mask));
261 pragma Debug (Debug.Put (" .S "));
262 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
263
264 Read (Register, Value);
265 Value := Value or Mask;
266 Write (Register, Value);
267 end Set_Mask;
268
269 ----------------------------------------------------------------------------
270
271 -- Mask out @Mask@ in @Register@
272 procedure Unset_Mask
273 (Register : Registers_Index;
274 Mask : Word32)
275 is
276 Value : Word32;
277 begin
278 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
279 pragma Debug (Debug.Put_Word32 (Mask));
280 pragma Debug (Debug.Put (" !S "));
281 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
282
283 Read (Register, Value);
284 Value := Value and not Mask;
285 Write (Register, Value);
286 end Unset_Mask;
287
288 ----------------------------------------------------------------------------
289
290 -- Mask out @Unset_Mask@ and set @Set_Mask@ in @Register@
291 procedure Unset_And_Set_Mask
292 (Register : Registers_Index;
293 Mask_Unset : Word32;
294 Mask_Set : Word32)
295 is
296 Value : Word32;
297 begin
298 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
299 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
300
301 Read (Register, Value);
302 Value := (Value and not Mask_Unset) or Mask_Set;
303 Write (Register, Value);
304 end Unset_And_Set_Mask;
305
306 ----------------------------------------------------------------------------
307
Nico Huber2b6f6992017-07-09 18:11:34 +0200308 procedure Set_Register_Base (Base : Word64; GTT_Base : Word64 := 0)
Nico Huber83693c82016-10-08 22:17:55 +0200309 is
310 begin
311 Regs.Set_Base_Address (Base);
Nico Huber2b6f6992017-07-09 18:11:34 +0200312 if GTT_Base = 0 then
313 GTT.Set_Base_Address (Base + Config.GTT_Offset);
314 else
315 GTT.Set_Base_Address (GTT_Base);
316 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200317 end Set_Register_Base;
318
319end HW.GFX.GMA.Registers;