blob: df666d1e545016394a8c4cd93f2526bf07d9bb38 [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
15with System.Storage_Elements;
16
17with HW.Time;
18with HW.MMIO_Range;
19pragma Elaborate_All (HW.MMIO_Range);
20
21with HW.Debug;
22with GNAT.Source_Info;
23
24use type System.Address;
25use type HW.Word64;
26
27package body HW.GFX.GMA.Registers
28with
29 Refined_State =>
30 (Address_State => (Regs.Base_Address, GTT.Base_Address),
31 Register_State => Regs.State,
32 GTT_State => GTT.State)
33is
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
50 GTT_Offset : constant := (case Config.CPU is
51 when Ironlake .. Haswell => 16#0020_0000#,
52 when Broadwell .. Skylake => 16#0080_0000#);
53
54 GTT_Size : constant := (case Config.CPU is
55 when Ironlake .. Haswell => 16#0020_0000#,
56 -- Limit Broadwell to 4MiB to have a stable
57 -- interface (i.e. same number of entries):
58 when Broadwell .. Skylake => 16#0040_0000#);
59
60 GTT_PTE_Size : constant := (case Config.CPU is
61 when Ironlake .. Haswell => 4,
62 when Broadwell .. Skylake => 8);
63
64
65 type GTT_PTE_Type is mod 2 ** (GTT_PTE_Size * 8);
66 type GTT_Registers_Type is array (GTT_Range) of GTT_PTE_Type
67 with
68 Volatile_Components,
69 Size => GTT_Size * 8;
70 package GTT is new MMIO_Range
71 (Base_Addr => Config.Default_MMIO_Base + GTT_Offset,
72 Element_T => GTT_PTE_Type,
73 Index_T => GTT_Range,
74 Array_T => GTT_Registers_Type);
75
76 GTT_PTE_Valid : constant Word32 := 1;
77
78 ----------------------------------------------------------------------------
79
80 procedure Write_GTT
81 (GTT_Page : GTT_Range;
82 Device_Address : GTT_Address_Type;
83 Valid : Boolean)
84 is
85 begin
86 if Config.Fold_39Bit_GTT_PTE then
87 GTT.Write
88 (Index => GTT_Page,
89 Value => GTT_PTE_Type (Device_Address and 16#ffff_f000#) or
90 GTT_PTE_Type (Shift_Right (Word64 (Device_Address), 32 - 4)
91 and 16#0000_07f0#) or
92 Boolean'Pos (Valid));
93 else
94 GTT.Write
95 (Index => GTT_Page,
96 Value => GTT_PTE_Type (Device_Address and 16#7f_ffff_f000#) or
97 Boolean'Pos (Valid));
98 end if;
99 end Write_GTT;
100
101 ----------------------------------------------------------------------------
102
103 package Rep is
104 function Index (Reg : Registers_Index) return Registers_Range;
105 end Rep;
106
107 package body Rep is
108 function Index (Reg : Registers_Index) return Registers_Range
109 with
110 SPARK_Mode => Off
111 is
112 begin
113 return Reg'Enum_Rep;
114 end Index;
115 end Rep;
116
117 -- Read a specific register
118 procedure Read
119 (Register : in Registers_Index;
120 Value : out Word32;
121 Verbose : in Boolean := True)
122 is
123 begin
124 Regs.Read (Value, Rep.Index (Register));
125
126 pragma Debug (Verbose, Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
127 pragma Debug (Verbose, Debug.Put_Word32 (Value));
128 pragma Debug (Verbose, Debug.Put (" <- "));
129 pragma Debug (Verbose, Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
130 pragma Debug (Verbose, Debug.Put (":"));
131 pragma Debug (Verbose, Debug.Put_Line (Registers_Index'Image (Register)));
132 end Read;
133
134 ----------------------------------------------------------------------------
135
136 -- Read a specific register to post a previous write
137 procedure Posting_Read (Register : Registers_Index)
138 is
139 Discard_Value : Word32;
140 begin
141 pragma Warnings
142 (Off, "unused assignment to ""Discard_Value""",
143 Reason => "Intentional dummy read to affect hardware.");
144
145 Read (Register, Discard_Value);
146
147 pragma Warnings
148 (On, "unused assignment to ""Discard_Value""");
149 end Posting_Read;
150
151 ----------------------------------------------------------------------------
152
153 -- Write a specific register
154 procedure Write (Register : Registers_Index; Value : Word32)
155 is
156 begin
157 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
158 pragma Debug (Debug.Put_Word32 (Value));
159 pragma Debug (Debug.Put (" -> "));
160 pragma Debug (Debug.Put_Word32 (Register'Enum_Rep * Register_Width));
161 pragma Debug (Debug.Put (":"));
162 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
163
164 Regs.Write (Rep.Index (Register), Value);
165 pragma Debug (Debug.Register_Write_Wait);
166 end Write;
167
168 ----------------------------------------------------------------------------
169
170 -- Check whether all bits in @Register@ indicated by @Mask@ are set
171 procedure Is_Set_Mask
172 (Register : in Registers_Index;
173 Mask : in Word32;
174 Result : out Boolean)
175 is
176 Value : Word32;
177 begin
178 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
179 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
180
181 Read (Register, Value);
182 Result := (Value and Mask) = Mask;
183
184 end Is_Set_Mask;
185
186 ----------------------------------------------------------------------------
187
188 -- TODO: Should have Success parameter
189 -- Wait for all bits in @Register@ indicated by @Mask@ to be set
190 procedure Wait_Set_Mask
191 (Register : in Registers_Index;
192 Mask : in Word32;
193 TOut_MS : in Natural := Default_Timeout_MS;
194 Verbose : in Boolean := False)
195 is
196 Value : 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_Line (Registers_Index'Image (Register)));
202
203 Timeout := Time.MS_From_Now (TOut_MS);
204 loop
205 Timed_Out := Time.Timed_Out (Timeout);
206 Read (Register, Value, Verbose);
207 if (Value and Mask) = Mask then
208 exit;
209 end if;
210 pragma Debug (Timed_Out, Debug.Put (GNAT.Source_Info.Enclosing_Entity));
211 pragma Debug (Timed_Out, Debug.Put_Line (": Timed Out!"));
212 exit when Timed_Out;
213 end loop;
214
215 end Wait_Set_Mask;
216
217 ----------------------------------------------------------------------------
218
219 -- TODO: Should have Success parameter
220 -- Wait for bits in @Register@ indicated by @Mask@ to be clear
221 procedure Wait_Unset_Mask
222 (Register : Registers_Index;
223 Mask : Word32;
224 TOut_MS : in Natural := Default_Timeout_MS;
225 Verbose : in Boolean := False)
226 is
227 Value : Word32;
228 Timeout : Time.T;
229 Timed_Out : Boolean;
230 begin
231 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
232 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
233
234 Timeout := Time.MS_From_Now (TOut_MS);
235 loop
236 Timed_Out := Time.Timed_Out (Timeout);
237 Read (Register, Value, Verbose);
238 if (Value and Mask) = 0 then
239 exit;
240 end if;
241 pragma Debug (Timed_Out, Debug.Put (GNAT.Source_Info.Enclosing_Entity));
242 pragma Debug (Timed_Out, Debug.Put_Line (": Timed Out!"));
243 exit when Timed_Out;
244 end loop;
245
246 end Wait_Unset_Mask;
247
248 ----------------------------------------------------------------------------
249
250 -- Set bits from @Mask@ in @Register@
251 procedure Set_Mask
252 (Register : Registers_Index;
253 Mask : Word32)
254 is
255 Value : Word32;
256 begin
257 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
258 pragma Debug (Debug.Put_Word32 (Mask));
259 pragma Debug (Debug.Put (" .S "));
260 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
261
262 Read (Register, Value);
263 Value := Value or Mask;
264 Write (Register, Value);
265 end Set_Mask;
266
267 ----------------------------------------------------------------------------
268
269 -- Mask out @Mask@ in @Register@
270 procedure Unset_Mask
271 (Register : Registers_Index;
272 Mask : Word32)
273 is
274 Value : Word32;
275 begin
276 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
277 pragma Debug (Debug.Put_Word32 (Mask));
278 pragma Debug (Debug.Put (" !S "));
279 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
280
281 Read (Register, Value);
282 Value := Value and not Mask;
283 Write (Register, Value);
284 end Unset_Mask;
285
286 ----------------------------------------------------------------------------
287
288 -- Mask out @Unset_Mask@ and set @Set_Mask@ in @Register@
289 procedure Unset_And_Set_Mask
290 (Register : Registers_Index;
291 Mask_Unset : Word32;
292 Mask_Set : Word32)
293 is
294 Value : Word32;
295 begin
296 pragma Debug (Debug.Put (GNAT.Source_Info.Enclosing_Entity & ": "));
297 pragma Debug (Debug.Put_Line (Registers_Index'Image (Register)));
298
299 Read (Register, Value);
300 Value := (Value and not Mask_Unset) or Mask_Set;
301 Write (Register, Value);
302 end Unset_And_Set_Mask;
303
304 ----------------------------------------------------------------------------
305
306 procedure Set_Register_Base (Base : Word64)
307 is
308 begin
309 Regs.Set_Base_Address (Base);
310 GTT.Set_Base_Address (Base + GTT_Offset);
311 end Set_Register_Base;
312
313end HW.GFX.GMA.Registers;