blob: 4a1050ee952b92d054c855a935ae2eaff1719f6a [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
Nico Huber9a4c4c32019-09-16 22:05:11 +02002-- Copyright (C) 2014-2019 secunet Security Networks AG
Nico Huber2b6f6992017-07-09 18:11:34 +02003-- Copyright (C) 2017 Nico Huber <nico.h@gmx.de>
Nico Huber83693c82016-10-08 22:17:55 +02004--
5-- This program is free software; you can redistribute it and/or modify
6-- it under the terms of the GNU General Public License as published by
Nico Huber125a29e2016-10-18 00:23:54 +02007-- the Free Software Foundation; either version 2 of the License, or
8-- (at your option) any later version.
Nico Huber83693c82016-10-08 22:17:55 +02009--
10-- This program is distributed in the hope that it will be useful,
11-- but WITHOUT ANY WARRANTY; without even the implied warranty of
12-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13-- GNU General Public License for more details.
14--
15
Nico Huber2b6f6992017-07-09 18:11:34 +020016with HW.MMIO_Range;
17pragma Elaborate_All (HW.MMIO_Range);
18with HW.PCI.Dev;
19pragma Elaborate_All (HW.PCI.Dev);
20
Nico Huber83693c82016-10-08 22:17:55 +020021with HW.GFX.GMA.Config;
Nico Huber8c45bcf2016-11-20 17:30:57 +010022with HW.GFX.GMA.Config_Helpers;
Nico Huber83693c82016-10-08 22:17:55 +020023with HW.GFX.GMA.Registers;
Nico Huber312433c2019-09-28 03:15:48 +020024with HW.GFX.GMA.PCode;
Nico Huber83693c82016-10-08 22:17:55 +020025with HW.GFX.GMA.Power_And_Clocks;
26with HW.GFX.GMA.Panel;
27with HW.GFX.GMA.PLLs;
28with HW.GFX.GMA.Port_Detect;
29with HW.GFX.GMA.Connectors;
30with HW.GFX.GMA.Connector_Info;
31with HW.GFX.GMA.Pipe_Setup;
32
Nico Huber83693c82016-10-08 22:17:55 +020033with HW.Debug;
34with GNAT.Source_Info;
35
Nico Huber83693c82016-10-08 22:17:55 +020036use type HW.Int32;
37
38package body HW.GFX.GMA
39 with Refined_State =>
40 (State =>
Nico Hubere317e9c2019-09-29 03:03:18 +020041 (Config.Variable,
42 PCI_Usable,
Nico Huberc5c66ec2019-09-28 23:59:45 +020043 Dev.Address_State,
Nico Huber2b6f6992017-07-09 18:11:34 +020044 Registers.Address_State,
Nico Huber312433c2019-09-28 03:15:48 +020045 PCode.Mailbox_Ready,
Nico Huber83693c82016-10-08 22:17:55 +020046 PLLs.State, Panel.Panel_State,
Nico Huber1a712d32017-01-09 15:11:04 +010047 Cur_Configs, Allocated_PLLs,
Nico Huberc3f66f62017-07-16 21:39:54 +020048 HPD_Delay, Wait_For_HPD,
49 Linear_FB_Base),
Nico Huber83693c82016-10-08 22:17:55 +020050 Init_State => Initialized,
Nico Huber83693c82016-10-08 22:17:55 +020051 Device_State =>
Nico Huber2b6f6992017-07-09 18:11:34 +020052 (Dev.PCI_State, Registers.Register_State, Registers.GTT_State))
Nico Huber83693c82016-10-08 22:17:55 +020053is
Nico Huber2b6f6992017-07-09 18:11:34 +020054 pragma Disable_Atomic_Synchronization;
Nico Huber83693c82016-10-08 22:17:55 +020055
56 subtype Port_Name is String (1 .. 8);
57 type Port_Name_Array is array (Port_Type) of Port_Name;
58 Port_Names : constant Port_Name_Array :=
59 (Disabled => "Disabled",
Nico Huber8beafd72020-01-07 14:59:44 +010060 LVDS => "LVDS ",
61 eDP => "eDP ",
Nico Huber83693c82016-10-08 22:17:55 +020062 DP1 => "DP1 ",
63 DP2 => "DP2 ",
64 DP3 => "DP3 ",
Nico Huber0d454cd2016-11-21 13:33:43 +010065 HDMI1 => "HDMI1 ",
66 HDMI2 => "HDMI2 ",
67 HDMI3 => "HDMI3 ",
Nico Huber83693c82016-10-08 22:17:55 +020068 Analog => "Analog ");
69
Nico Huber2b6f6992017-07-09 18:11:34 +020070 package Dev is new HW.PCI.Dev (PCI.Address'(0, 2, 0));
71
Nico Huber83693c82016-10-08 22:17:55 +020072 package Display_Controller renames Pipe_Setup;
73
Nico Huber99f10f32016-11-20 00:34:05 +010074 type PLLs_Type is array (Pipe_Index) of PLLs.T;
Nico Huber83693c82016-10-08 22:17:55 +020075
Nico Huber83693c82016-10-08 22:17:55 +020076 type HPD_Type is array (Port_Type) of Boolean;
Nico Huber3be61d42017-01-09 13:58:18 +010077 type HPD_Delay_Type is array (Active_Port_Type) of Time.T;
Nico Huber83693c82016-10-08 22:17:55 +020078
Nico Huber83693c82016-10-08 22:17:55 +020079 Allocated_PLLs : PLLs_Type;
Nico Huber83693c82016-10-08 22:17:55 +020080 HPD_Delay : HPD_Delay_Type;
81 Wait_For_HPD : HPD_Type;
82 Initialized : Boolean := False;
83
Nico Huberc3f66f62017-07-16 21:39:54 +020084 Linear_FB_Base : Word64;
85
Nico Huber83693c82016-10-08 22:17:55 +020086 ----------------------------------------------------------------------------
87
Nico Huberdde06302020-12-20 02:18:30 +010088 PCH_RAWCLK_FREQ_MASK : constant :=
89 (if Config.Has_Fractional_RawClk then 16#3fff# * 2 ** 16 else 16#3ff# * 2 ** 0);
Nico Huberf54d0962016-10-20 14:17:18 +020090
91 function PCH_RAWCLK_FREQ (Freq : Frequency_Type) return Word32
92 is
93 begin
Nico Huberdde06302020-12-20 02:18:30 +010094 if Config.Has_Fractional_RawClk then
95 declare
96 Fraction_K : constant Int64 := Freq / 1_000 mod 1_000;
97 Freq32 : Word32 := Shift_Left (Word32 (Freq / 1_000_000), 16);
98 begin
99 if Fraction_K /= 0 then
100 Freq32 := Freq32 or Shift_Left
101 (Word32 (Div_Round_Closest (1_000, Fraction_K) - 1), 26);
102 end if;
103 return Freq32;
104 end;
105 else
106 return Word32 (Freq / 1_000_000);
107 end if;
Nico Huberf54d0962016-10-20 14:17:18 +0200108 end PCH_RAWCLK_FREQ;
109
110 ----------------------------------------------------------------------------
111
Nico Huber43370ba2017-01-09 15:26:19 +0100112 procedure Enable_Output
113 (Pipe : in Pipe_Index;
114 Pipe_Cfg : in Pipe_Config;
115 Success : out Boolean)
Nico Huber8a5a3b52018-06-04 14:42:13 +0200116 with
Nico Huber9a4c4c32019-09-16 22:05:11 +0200117 Pre =>
118 Pipe_Cfg.Port in Active_Port_Type and
119 Config_Helpers.Valid_FB (Pipe_Cfg.Framebuffer, Pipe_Cfg.Mode)
Nico Huber43370ba2017-01-09 15:26:19 +0100120 is
121 Port_Cfg : Port_Config;
122 begin
Nico Huber3be61d42017-01-09 13:58:18 +0100123 pragma Debug (Debug.New_Line);
124 pragma Debug (Debug.Put_Line
125 ("Trying to enable port " & Port_Names (Pipe_Cfg.Port)));
126
Nico Huber43370ba2017-01-09 15:26:19 +0100127 Config_Helpers.Fill_Port_Config
128 (Port_Cfg, Pipe, Pipe_Cfg.Port, Pipe_Cfg.Mode, Success);
129
130 if Success then
Nico Huber43370ba2017-01-09 15:26:19 +0100131 Connector_Info.Preferred_Link_Setting (Port_Cfg, Success);
132 end if;
133
134 -- loop over all possible DP-lane configurations
135 -- (non-DP ports use a single fake configuration)
136 while Success loop
137 pragma Loop_Invariant
138 (Pipe_Cfg.Port in Active_Port_Type and
139 Port_Cfg.Mode = Port_Cfg.Mode'Loop_Entry);
140
141 PLLs.Alloc
142 (Port_Cfg => Port_Cfg,
143 PLL => Allocated_PLLs (Pipe),
144 Success => Success);
145
146 if Success then
147 -- try each DP-lane configuration twice
148 for Try in 1 .. 2 loop
149 pragma Loop_Invariant
150 (Pipe_Cfg.Port in Active_Port_Type);
151
Nico Huber4798c662017-01-11 12:44:48 +0100152 -- Clear pending hot-plug events before every try
153 Port_Detect.Clear_Hotplug_Detect (Pipe_Cfg.Port);
154
Nico Huber43370ba2017-01-09 15:26:19 +0100155 Connectors.Pre_On
156 (Pipe => Pipe,
157 Port_Cfg => Port_Cfg,
158 PLL_Hint => PLLs.Register_Value (Allocated_PLLs (Pipe)),
159 Success => Success);
160
161 if Success then
162 Display_Controller.On
163 (Pipe => Pipe,
164 Port_Cfg => Port_Cfg,
Nico Huber4dc4c612018-01-10 15:55:09 +0100165 Framebuffer => Pipe_Cfg.Framebuffer,
166 Cursor => Pipe_Cfg.Cursor);
Nico Huber43370ba2017-01-09 15:26:19 +0100167
168 Connectors.Post_On
Arthur Heymans60d0e5f2018-03-28 17:08:27 +0200169 (Pipe => Pipe,
170 Port_Cfg => Port_Cfg,
Nico Huber43370ba2017-01-09 15:26:19 +0100171 PLL_Hint => PLLs.Register_Value (Allocated_PLLs (Pipe)),
172 Success => Success);
173
174 if not Success then
175 Display_Controller.Off (Pipe);
176 Connectors.Post_Off (Port_Cfg);
177 end if;
178 end if;
179
180 exit when Success;
181 end loop;
182 exit when Success; -- connection established => stop loop
183
184 -- connection failed
185 PLLs.Free (Allocated_PLLs (Pipe));
186 end if;
187
188 Connector_Info.Next_Link_Setting (Port_Cfg, Success);
189 end loop;
190
191 if Success then
192 pragma Debug (Debug.Put_Line
193 ("Enabled port " & Port_Names (Pipe_Cfg.Port)));
194 else
195 Wait_For_HPD (Pipe_Cfg.Port) := True;
Nico Huber2bbd6e72020-01-07 18:22:59 +0100196 Panel.Off (Config_Helpers.To_Panel (Pipe_Cfg.Port));
Nico Huber43370ba2017-01-09 15:26:19 +0100197 end if;
198 end Enable_Output;
199
Nico Huber3be61d42017-01-09 13:58:18 +0100200 procedure Disable_Output (Pipe : Pipe_Index; Pipe_Cfg : Pipe_Config)
201 is
202 Port_Cfg : Port_Config;
203 Success : Boolean;
204 begin
205 Config_Helpers.Fill_Port_Config
206 (Port_Cfg, Pipe, Pipe_Cfg.Port, Pipe_Cfg.Mode, Success);
207 if Success then
208 pragma Debug (Debug.New_Line);
209 pragma Debug (Debug.Put_Line
210 ("Disabling port " & Port_Names (Pipe_Cfg.Port)));
211 pragma Debug (Debug.New_Line);
212
Jeremy Compostellafe80fbb2023-01-11 14:05:42 -0700213 if Pipe_Cfg.Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
214 Display_Controller.Legacy_VGA_Off;
215 end if;
216
Nico Huber3be61d42017-01-09 13:58:18 +0100217 Connectors.Pre_Off (Port_Cfg);
218 Display_Controller.Off (Pipe);
219 Connectors.Post_Off (Port_Cfg);
220
221 PLLs.Free (Allocated_PLLs (Pipe));
222 end if;
223 end Disable_Output;
224
Nico Huber99f10f32016-11-20 00:34:05 +0100225 procedure Update_Outputs (Configs : Pipe_Configs)
Nico Huber83693c82016-10-08 22:17:55 +0200226 is
Nico Huber3be61d42017-01-09 13:58:18 +0100227 procedure Check_HPD (Port : in Active_Port_Type; Detected : out Boolean)
228 is
229 HPD_Delay_Over : constant Boolean := Time.Timed_Out (HPD_Delay (Port));
230 begin
231 if HPD_Delay_Over then
232 Port_Detect.Hotplug_Detect (Port, Detected);
233 HPD_Delay (Port) := Time.MS_From_Now (333);
234 else
235 Detected := False;
236 end if;
237 end Check_HPD;
Nico Huberb56b9c52017-01-11 15:12:23 +0100238
Nico Huber9a4c4c32019-09-16 22:05:11 +0200239 Scaler_Reservation : Display_Controller.Scaler_Reservation :=
240 Display_Controller.Null_Scaler_Reservation;
Nico Huber564103f2017-01-11 15:33:07 +0100241
Nico Huber9a4c4c32019-09-16 22:05:11 +0200242 Update_Power : Boolean := False;
Nico Huberb0bbdbc2019-09-27 22:32:21 +0200243 Update_CDClk : Boolean;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200244 Old_Configs,
245 New_Configs : Pipe_Configs;
Nico Huber3d06de82018-05-29 01:35:04 +0200246
247 function Full_Update (Cur_Config, New_Config : Pipe_Config) return Boolean
248 is
249 begin
250 return
Nico Huber958c5642018-06-02 16:59:31 +0200251 Cur_Config.Port /= New_Config.Port
252 or else
253 Cur_Config.Mode /= New_Config.Mode
254 or else
Nico Huber3d06de82018-05-29 01:35:04 +0200255 (Config.Use_PDW_For_EDP_Scaling and then
Nico Huber8beafd72020-01-07 14:59:44 +0100256 (Cur_Config.Port = eDP and
Nico Huber958c5642018-06-02 16:59:31 +0200257 Requires_Scaling (Cur_Config) /= Requires_Scaling (New_Config)))
258 or else
259 (Config.Has_GMCH_PFIT_CONTROL and then
260 (Requires_Scaling (Cur_Config) /= Requires_Scaling (New_Config) or
261 Scaling_Type (Cur_Config) /= Scaling_Type (New_Config)));
Nico Huber3d06de82018-05-29 01:35:04 +0200262 end Full_Update;
Nico Huber83693c82016-10-08 22:17:55 +0200263 begin
264 Old_Configs := Cur_Configs;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200265 New_Configs := Configs;
266
267 -- validate new configs, filter invalid configs and those waiting for HPD
268 for Pipe in Pipe_Index loop
269 declare
270 Success : Boolean := True;
271 Cur_Config : Pipe_Config renames Cur_Configs (Pipe);
272 New_Config : Pipe_Config renames New_Configs (Pipe);
273 begin
274 if New_Config.Port /= Disabled then
275 if Wait_For_HPD (New_Config.Port) then
276 Check_HPD (New_Config.Port, Success);
277 Wait_For_HPD (New_Config.Port) := not Success;
278 end if;
279
280 Success := Success and then
281 Config_Helpers.Validate_Config
282 (New_Config.Framebuffer, New_Config.Mode, Pipe);
283
284 if Success and then Requires_Scaling (New_Config) then
285 Display_Controller.Reserve_Scaler
286 (Success, Scaler_Reservation, Pipe);
287 end if;
288
289 if not Success then
290 New_Config.Port := Disabled;
291 end if;
292 end if;
293 end;
294 pragma Loop_Invariant
295 (for all P in Pipe_Index'First .. Pipe =>
296 New_Configs (P).Port = Disabled or
297 Config_Helpers.Valid_FB
298 (New_Configs (P).Framebuffer, New_Configs (P).Mode));
299 end loop;
Nico Huber83693c82016-10-08 22:17:55 +0200300
Nico Huberb0bbdbc2019-09-27 22:32:21 +0200301 -- limit dotclocks to maximum CDClk, if we are about
302 -- to switch CDClk, all pipes have to be disabled
303 Power_And_Clocks.Limit_Dotclocks (New_Configs, Update_CDClk);
304
Nico Huberb56b9c52017-01-11 15:12:23 +0100305 -- disable all pipes that changed or had a hot-plug event
306 for Pipe in Pipe_Index loop
307 declare
308 Unplug_Detected : Boolean;
309 Cur_Config : Pipe_Config renames Cur_Configs (Pipe);
Nico Huber9a4c4c32019-09-16 22:05:11 +0200310 New_Config : Pipe_Config renames New_Configs (Pipe);
Nico Huberb56b9c52017-01-11 15:12:23 +0100311 begin
312 if Cur_Config.Port /= Disabled then
313 Check_HPD (Cur_Config.Port, Unplug_Detected);
Nico Huber83693c82016-10-08 22:17:55 +0200314
Nico Huberb0bbdbc2019-09-27 22:32:21 +0200315 if Update_CDClk or
316 Unplug_Detected or
317 Full_Update (Cur_Config, New_Config)
318 then
Nico Huberb56b9c52017-01-11 15:12:23 +0100319 Disable_Output (Pipe, Cur_Config);
320 Cur_Config.Port := Disabled;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200321 Update_Power := True;
Nico Huberb56b9c52017-01-11 15:12:23 +0100322 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200323 end if;
Nico Huberb56b9c52017-01-11 15:12:23 +0100324 end;
325 end loop;
Nico Huber83693c82016-10-08 22:17:55 +0200326
Nico Huberb0bbdbc2019-09-27 22:32:21 +0200327 -- switch CDClk if necessary and possible, limit dotclocks accordingly
328 if Update_CDClk then
329 Power_And_Clocks.Update_CDClk (New_Configs);
330 end if;
331
Nico Huberb56b9c52017-01-11 15:12:23 +0100332 -- enable all pipes that changed and should be active
333 for Pipe in Pipe_Index loop
334 declare
335 Success : Boolean;
336 Cur_Config : Pipe_Config renames Cur_Configs (Pipe);
Nico Huber9a4c4c32019-09-16 22:05:11 +0200337 New_Config : Pipe_Config renames New_Configs (Pipe);
Nico Huberb56b9c52017-01-11 15:12:23 +0100338 begin
Nico Huber9a4c4c32019-09-16 22:05:11 +0200339 -- full update
Nico Huber3d06de82018-05-29 01:35:04 +0200340 if New_Config.Port /= Disabled and
341 Full_Update (Cur_Config, New_Config)
Nico Huberb56b9c52017-01-11 15:12:23 +0100342 then
Nico Huber9a4c4c32019-09-16 22:05:11 +0200343 Power_And_Clocks.Power_Up (Old_Configs, New_Configs);
344 Update_Power := True;
Nico Huberc7a4fee2016-11-03 18:18:03 +0100345
Nico Huber9a4c4c32019-09-16 22:05:11 +0200346 Enable_Output (Pipe, New_Config, Success);
Nico Huber83693c82016-10-08 22:17:55 +0200347 if Success then
Nico Huberb56b9c52017-01-11 15:12:23 +0100348 Cur_Config := New_Config;
Nico Huber83693c82016-10-08 22:17:55 +0200349 end if;
Nico Huber3be61d42017-01-09 13:58:18 +0100350
Nico Huberb56b9c52017-01-11 15:12:23 +0100351 -- update framebuffer offset only
352 elsif New_Config.Port /= Disabled and
Nico Huberf361ec82018-06-02 18:01:45 +0200353 Cur_Config.Framebuffer /= New_Config.Framebuffer
Nico Huberb56b9c52017-01-11 15:12:23 +0100354 then
Nico Huber9a4c4c32019-09-16 22:05:11 +0200355 Display_Controller.Setup_FB
356 (Pipe, New_Config.Mode, New_Config.Framebuffer);
357 Display_Controller.Update_Cursor
358 (Pipe, New_Config.Framebuffer, New_Config.Cursor);
359 Cur_Config := New_Config;
Nico Huberb56b9c52017-01-11 15:12:23 +0100360 end if;
361 end;
Nico Huber83693c82016-10-08 22:17:55 +0200362 end loop;
363
Nico Huber9a4c4c32019-09-16 22:05:11 +0200364 if Update_Power then
365 Power_And_Clocks.Power_Down (Old_Configs, New_Configs, Cur_Configs);
Nico Huber83693c82016-10-08 22:17:55 +0200366 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200367 end Update_Outputs;
368
369 ----------------------------------------------------------------------------
370
Nico Huber15ffc4f2018-01-11 14:44:43 +0100371 procedure Update_Cursor (Pipe : Pipe_Index; Cursor : Cursor_Type)
372 is
373 begin
374 Cur_Configs (Pipe).Cursor := Cursor;
375 Display_Controller.Update_Cursor
376 (Pipe, Cur_Configs (Pipe).Framebuffer, Cur_Configs (Pipe).Cursor);
377 end Update_Cursor;
378
379 procedure Place_Cursor
380 (Pipe : Pipe_Index;
381 X : Cursor_Pos;
382 Y : Cursor_Pos)
383 is
384 begin
385 Cur_Configs (Pipe).Cursor.Center_X := X;
386 Cur_Configs (Pipe).Cursor.Center_Y := Y;
387 Display_Controller.Place_Cursor
388 (Pipe, Cur_Configs (Pipe).Framebuffer, Cur_Configs (Pipe).Cursor);
389 end Place_Cursor;
390
391 procedure Move_Cursor
392 (Pipe : Pipe_Index;
393 X : Cursor_Pos;
394 Y : Cursor_Pos)
395 is
396 function Cap_Add (A, B : Cursor_Pos) return Cursor_Pos is
397 (if A + B < 0
398 then Int32'Max (Cursor_Pos'First, A + B)
399 else Int32'Min (Cursor_Pos'Last, A + B));
400 begin
401 Place_Cursor
402 (Pipe => Pipe,
403 X => Cap_Add (Cur_Configs (Pipe).Cursor.Center_X, X),
404 Y => Cap_Add (Cur_Configs (Pipe).Cursor.Center_Y, Y));
405 end Move_Cursor;
406
407 ----------------------------------------------------------------------------
408
Nico Huberbc0588e2020-07-21 12:17:19 +0200409 procedure Backlight_On (Port : Active_Port_Type)
410 with
411 Refined_Global => (In_Out => Registers.Register_State)
412 is
413 begin
414 Panel.Backlight_On (Config_Helpers.To_Panel (Port));
415 end Backlight_On;
416
417 procedure Backlight_Off (Port : Active_Port_Type)
418 with
419 Refined_Global => (In_Out => Registers.Register_State)
420 is
421 begin
422 Panel.Backlight_Off (Config_Helpers.To_Panel (Port));
423 end Backlight_Off;
424
425 procedure Set_Brightness (Port : Active_Port_Type; Level : Word32)
426 with
427 Refined_Global => (In_Out => Registers.Register_State)
428 is
429 begin
430 Panel.Set_Backlight (Config_Helpers.To_Panel (Port), Level);
431 end Set_Brightness;
432
433 procedure Get_Max_Brightness (Port : Active_Port_Type; Level : out Word32)
434 with
435 Refined_Global => (In_Out => Registers.Register_State)
436 is
437 begin
438 Panel.Get_Max_Backlight (Config_Helpers.To_Panel (Port), Level);
439 end Get_Max_Brightness;
440
441 ----------------------------------------------------------------------------
442
Nico Huber793f4f82022-09-04 14:24:00 +0000443 pragma Warnings
444 (GNATprove, Off, """Registers.GTT_State"" * is not modified*",
445 Reason => "The whole, abstract Device_State is modified in certain configurations.");
446 pragma Warnings
447 (GNATprove, Off, "no check message justified*", Reason => "see below");
Nico Huber83693c82016-10-08 22:17:55 +0200448 procedure Initialize
Nico Huber2b6f6992017-07-09 18:11:34 +0200449 (Write_Delay : in Word64 := 0;
Nico Huber793a8d42016-11-21 18:57:03 +0100450 Clean_State : in Boolean := False;
Nico Huber83693c82016-10-08 22:17:55 +0200451 Success : out Boolean)
452 with
453 Refined_Global =>
Nico Huber27088aa2018-06-10 13:28:05 +0200454 (Input => (Time.State),
Nico Huber793f4f82022-09-04 14:24:00 +0000455 In_Out =>
456 (Dev.PCI_State, Port_IO.State,
457 Registers.Register_State, Registers.GTT_State),
Nico Huber83693c82016-10-08 22:17:55 +0200458 Output =>
Nico Huberc5c66ec2019-09-28 23:59:45 +0200459 (PCI_Usable,
460 Config.Variable,
Nico Huber27088aa2018-06-10 13:28:05 +0200461 Dev.Address_State,
Nico Huber2b6f6992017-07-09 18:11:34 +0200462 Registers.Address_State,
Nico Huber312433c2019-09-28 03:15:48 +0200463 PCode.Mailbox_Ready,
Nico Huber83693c82016-10-08 22:17:55 +0200464 PLLs.State, Panel.Panel_State,
Nico Huber1a712d32017-01-09 15:11:04 +0100465 Cur_Configs, Allocated_PLLs,
Nico Huberc3f66f62017-07-16 21:39:54 +0200466 HPD_Delay, Wait_For_HPD,
467 Linear_FB_Base, Initialized))
Nico Huber83693c82016-10-08 22:17:55 +0200468 is
469 use type HW.Word64;
470
Nico Huber0b2329a2018-06-09 21:14:27 +0200471 function MMIO_GTT_Offset return Natural is
472 (if Config.Has_64bit_GTT
473 then Registers.MMIO_GTT_64_Offset
474 else Registers.MMIO_GTT_32_Offset);
Nico Huber2b6f6992017-07-09 18:11:34 +0200475 PCI_MMIO_Base, PCI_GTT_Base : Word64;
476
Nico Huber83693c82016-10-08 22:17:55 +0200477 Now : constant Time.T := Time.Now;
478
479 procedure Check_Platform (Success : out Boolean)
480 is
481 Audio_VID_DID : Word32;
482 begin
Nico Huber6621a142018-06-07 23:56:54 +0200483 case Config.Gen is
Arthur Heymans73ea0322018-03-28 17:17:07 +0200484 when G45 =>
485 Registers.Read (Registers.G4X_AUD_VID_DID, Audio_VID_DID);
Nico Huber6621a142018-06-07 23:56:54 +0200486 when Ironlake =>
487 Registers.Read (Registers.PCH_AUD_VID_DID, Audio_VID_DID);
Nico Huber83693c82016-10-08 22:17:55 +0200488 when Haswell .. Skylake =>
489 Registers.Read (Registers.AUD_VID_DID, Audio_VID_DID);
Nico Huber83693c82016-10-08 22:17:55 +0200490 end case;
491 Success :=
Nico Huber998ee2b2018-06-12 23:02:17 +0200492 ((Config.Gen_Broxton and Audio_VID_DID = 16#8086_280a#) or
Nico Huber88badbe2018-09-27 16:36:47 +0200493 (Config.CPU_Kabylake and Audio_VID_DID = 16#8086_280b#) or
494 (Config.CPU_Skylake and Audio_VID_DID = 16#8086_2809#) or
Nico Huber998ee2b2018-06-12 23:02:17 +0200495 (Config.CPU_Broadwell and Audio_VID_DID = 16#8086_2808#) or
496 (Config.CPU_Haswell and Audio_VID_DID = 16#8086_2807#) or
497 ((Config.CPU_Ivybridge or
498 Config.CPU_Sandybridge) and (Audio_VID_DID = 16#8086_2806# or
499 Audio_VID_DID = 16#8086_2805#)) or
500 (Config.CPU_Ironlake and Audio_VID_DID = 16#0000_0000#) or
501 (Config.Gen_G45 and (Audio_VID_DID = 16#8086_2801# or
502 Audio_VID_DID = 16#8086_2802# or
503 Audio_VID_DID = 16#8086_2803#)));
Nico Huber83693c82016-10-08 22:17:55 +0200504 end Check_Platform;
Nico Hubere7ac6eb2017-09-04 23:54:13 +0200505
506 procedure Check_Platform_PCI (Success : out Boolean)
507 is
508 use type HW.Word16;
509 Vendor, Device : Word16;
510 begin
511 Dev.Read16 (Vendor, PCI.Vendor_Id);
512 Dev.Read16 (Device, PCI.Device_Id);
513
Nico Huber6a996dc2018-06-17 16:30:33 +0200514 Config.Detect_CPU (Device);
Nico Hubere7ac6eb2017-09-04 23:54:13 +0200515 Success := Vendor = 16#8086# and Config.Compatible_GPU (Device);
516 end Check_Platform_PCI;
Nico Huber83693c82016-10-08 22:17:55 +0200517 begin
Nico Huber83693c82016-10-08 22:17:55 +0200518 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
519
520 pragma Debug (Debug.Set_Register_Write_Delay (Write_Delay));
521
Nico Huberc5c66ec2019-09-28 23:59:45 +0200522 PCI_Usable := False;
Nico Huberc3f66f62017-07-16 21:39:54 +0200523 Linear_FB_Base := 0;
Nico Huber312433c2019-09-28 03:15:48 +0200524 PCode.Mailbox_Ready := False;
Nico Huber83693c82016-10-08 22:17:55 +0200525 Wait_For_HPD := HPD_Type'(others => False);
526 HPD_Delay := HPD_Delay_Type'(others => Now);
Nico Huber83693c82016-10-08 22:17:55 +0200527 Allocated_PLLs := (others => PLLs.Invalid);
Nico Huber99f10f32016-11-20 00:34:05 +0100528 Cur_Configs := Pipe_Configs'
529 (others => Pipe_Config'
Nico Huber83693c82016-10-08 22:17:55 +0200530 (Port => Disabled,
531 Framebuffer => HW.GFX.Default_FB,
Nico Hubera02b2c62018-01-09 15:58:34 +0100532 Cursor => Default_Cursor,
Nico Huber83693c82016-10-08 22:17:55 +0200533 Mode => HW.GFX.Invalid_Mode));
Nico Huber27088aa2018-06-10 13:28:05 +0200534 Config.Variable := Config.Initial_Settings;
Nico Huber6a996dc2018-06-17 16:30:33 +0200535 Registers.Set_Register_Base (Config.Default_MMIO_Base);
Nico Huber83693c82016-10-08 22:17:55 +0200536 PLLs.Initialize;
537
Nico Huber2b6f6992017-07-09 18:11:34 +0200538 Dev.Initialize (Success);
539
540 if Success then
Nico Huber6a996dc2018-06-17 16:30:33 +0200541 Check_Platform_PCI (Success);
Nico Hubere7ac6eb2017-09-04 23:54:13 +0200542 if Success then
Nico Huber6a996dc2018-06-17 16:30:33 +0200543 Dev.Map (PCI_MMIO_Base, PCI.Res0, Length => MMIO_GTT_Offset);
544 Dev.Map (PCI_GTT_Base, PCI.Res0, Offset => MMIO_GTT_Offset);
545 if PCI_MMIO_Base /= 0 and PCI_GTT_Base /= 0 then
546 Registers.Set_Register_Base (PCI_MMIO_Base, PCI_GTT_Base);
Nico Huberc5c66ec2019-09-28 23:59:45 +0200547 PCI_Usable := True;
Nico Huber6a996dc2018-06-17 16:30:33 +0200548 else
549 pragma Debug (Debug.Put_Line
550 ("ERROR: Couldn't map resoure0."));
551 Success := Config.Default_MMIO_Base_Set;
552 end if;
Nico Hubere7ac6eb2017-09-04 23:54:13 +0200553 end if;
Nico Huber2b6f6992017-07-09 18:11:34 +0200554 else
555 pragma Debug (Debug.Put_Line
556 ("WARNING: Couldn't initialize PCI dev."));
Nico Huber2b6f6992017-07-09 18:11:34 +0200557 Success := Config.Default_MMIO_Base_Set;
Nico Huber2b6f6992017-07-09 18:11:34 +0200558
Nico Hubere7ac6eb2017-09-04 23:54:13 +0200559 if Success then
560 Check_Platform (Success);
561 end if;
Nico Huber2b6f6992017-07-09 18:11:34 +0200562 end if;
563
Nico Huber5dbaf4b2020-01-08 17:24:58 +0100564 Panel.Static_Init; -- early for flow analysis
565
Nico Huber83693c82016-10-08 22:17:55 +0200566 if not Success then
567 pragma Debug (Debug.Put_Line ("ERROR: Incompatible CPU or PCH."));
568
Nico Huber83693c82016-10-08 22:17:55 +0200569 Initialized := False;
570 return;
571 end if;
572
573 Panel.Setup_PP_Sequencer;
574 Port_Detect.Initialize;
Nico Huber0923b792017-06-09 15:28:41 +0200575 Connectors.Initialize;
Nico Huber83693c82016-10-08 22:17:55 +0200576
Nico Huber793a8d42016-11-21 18:57:03 +0100577 if Clean_State then
578 Power_And_Clocks.Pre_All_Off;
579 Connectors.Pre_All_Off;
580 Display_Controller.All_Off;
581 Connectors.Post_All_Off;
582 PLLs.All_Off;
583 Power_And_Clocks.Post_All_Off;
Nico Huber17d64b62017-07-15 20:51:25 +0200584 Registers.Clear_Fences;
Nico Huber33912aa2016-12-06 20:36:23 +0100585 else
586 -- According to PRMs, VGA plane is the only thing
Nico Huber3a0e2a02017-07-19 14:41:46 +0200587 -- that's enabled by default after reset...
Nico Huber33912aa2016-12-06 20:36:23 +0100588 Display_Controller.Legacy_VGA_Off;
Nico Huber3a0e2a02017-07-19 14:41:46 +0200589 -- ... along with some DDI port bits since Skylake.
590 Connectors.Post_Reset_Off;
Nico Huber793a8d42016-11-21 18:57:03 +0100591 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200592
593 -------------------- Now restart from a clean state ---------------------
594 Power_And_Clocks.Initialize;
595
Nico Huber1c3b9282017-02-09 13:57:04 +0100596 if Config.Has_PCH then
597 Registers.Unset_And_Set_Mask
598 (Register => Registers.PCH_RAWCLK_FREQ,
599 Mask_Unset => PCH_RAWCLK_FREQ_MASK,
Nico Huberc9ad9de2020-12-20 02:34:37 +0100600 Mask_Set => PCH_RAWCLK_FREQ (Config.Raw_Clock));
Nico Huber1c3b9282017-02-09 13:57:04 +0100601 end if;
Nico Huberf54d0962016-10-20 14:17:18 +0200602
Nico Huber83693c82016-10-08 22:17:55 +0200603 Initialized := True;
604
605 end Initialize;
Nico Huber793f4f82022-09-04 14:24:00 +0000606 pragma Annotate
607 (GNATprove, Intentional, "unused global",
608 "The whole, abstract Device_State is modified in certain configurations.");
609 pragma Warnings (GNATprove, On, "no check message justified*");
610 pragma Warnings
611 (GNATprove, On, """Registers.GTT_State"" * is not modified*");
Nico Huber83693c82016-10-08 22:17:55 +0200612
613 function Is_Initialized return Boolean
614 with
615 Refined_Post => Is_Initialized'Result = Initialized
616 is
617 begin
618 return Initialized;
619 end Is_Initialized;
620
621 ----------------------------------------------------------------------------
622
Nico Hubercf88f3d2018-06-05 13:27:34 +0200623 pragma Warnings
624 (GNATprove, Off, """Registers.Register_State"" * is not modified*",
Nico Huberadfe11f2018-06-10 14:59:04 +0200625 Reason => "Power_Up_VGA is only effective in certain configurations.");
Nico Huber17b513e2022-09-04 13:36:02 +0200626 pragma Warnings
627 (GNATprove, Off, "no check message justified*", Reason => "see below");
Nico Huber42fb2d02017-09-01 17:01:51 +0200628 procedure Power_Up_VGA
Nico Hubercf88f3d2018-06-05 13:27:34 +0200629 with
630 Refined_Global =>
Nico Huberadfe11f2018-06-10 14:59:04 +0200631 (Input => (Cur_Configs, Config.Variable, Time.State),
Nico Hubercf88f3d2018-06-05 13:27:34 +0200632 In_Out => (Registers.Register_State),
633 Proof_In => (Initialized))
Nico Huber42fb2d02017-09-01 17:01:51 +0200634 is
635 Fake_Config : constant Pipe_Configs :=
636 (Primary =>
637 (Port => Analog,
638 Framebuffer => HW.GFX.Default_FB,
Nico Hubera02b2c62018-01-09 15:58:34 +0100639 Cursor => Default_Cursor,
Nico Huber42fb2d02017-09-01 17:01:51 +0200640 Mode => HW.GFX.Invalid_Mode),
641 others =>
642 (Port => Disabled,
643 Framebuffer => HW.GFX.Default_FB,
Nico Hubera02b2c62018-01-09 15:58:34 +0100644 Cursor => Default_Cursor,
Nico Huber42fb2d02017-09-01 17:01:51 +0200645 Mode => HW.GFX.Invalid_Mode));
646 begin
647 Power_And_Clocks.Power_Up (Cur_Configs, Fake_Config);
648 end Power_Up_VGA;
Nico Hubercf88f3d2018-06-05 13:27:34 +0200649 pragma Annotate
650 (GNATprove, Intentional, "unused global",
Nico Huberadfe11f2018-06-10 14:59:04 +0200651 "Power_Up_VGA is only effective in certain configurations.");
Nico Hubercf88f3d2018-06-05 13:27:34 +0200652 pragma Warnings (GNATprove, On, "no check message justified*");
653 pragma Warnings
654 (GNATprove, On, """Registers.Register_State"" * is not modified*");
Nico Huber42fb2d02017-09-01 17:01:51 +0200655
656 ----------------------------------------------------------------------------
657
Nico Huber5374c3a2017-07-15 21:48:06 +0200658 function FB_First_Page (FB : Framebuffer_Type) return Natural is
Nico Huber34be6542017-12-13 09:26:24 +0100659 (Natural (Phys_Offset (FB) / GTT_Page_Size));
Nico Huber5374c3a2017-07-15 21:48:06 +0200660 function FB_Pages (FB : Framebuffer_Type) return Natural is
661 (Natural (Div_Round_Up (FB_Size (FB), GTT_Page_Size)));
662 function FB_Last_Page (FB : Framebuffer_Type) return Natural is
663 (FB_First_Page (FB) + FB_Pages (FB) - 1);
664
Nico Huber34be6542017-12-13 09:26:24 +0100665 -- Check basics and that it fits in GTT. For 90 degree rotations,
666 -- the Offset should be above GTT_Rotation_Offset. The latter will
667 -- be subtracted for the aperture mapping.
Nico Huber5374c3a2017-07-15 21:48:06 +0200668 function Valid_FB (FB : Framebuffer_Type) return Boolean is
Nico Huber34be6542017-12-13 09:26:24 +0100669 (Valid_Stride (FB) and
670 FB_First_Page (FB) in GTT_Range and
Nico Huber2e87c0d2020-04-18 00:46:39 +0200671 FB_Last_Page (FB) + 128 in GTT_Range and
Nico Huber34be6542017-12-13 09:26:24 +0100672 (not Rotation_90 (FB) or
Nico Huber2e87c0d2020-04-18 00:46:39 +0200673 (FB_First_Page (FB) mod 64 = 0 and
674 FB_Last_Page (FB) + 128 + GTT_Rotation_Offset in GTT_Range and
Nico Huber34be6542017-12-13 09:26:24 +0100675 FB.Offset >= Word32 (GTT_Rotation_Offset) * GTT_Page_Size)));
Nico Huber5374c3a2017-07-15 21:48:06 +0200676
677 -- Also check that we don't overflow the GTT's 39-bit space
678 -- (always true with a 32-bit base)
679 function Valid_Phys_FB (FB : Framebuffer_Type; Phys_Base : Word32)
680 return Boolean is
681 (Valid_FB (FB) and
Nico Huber34be6542017-12-13 09:26:24 +0100682 Int64 (Phys_Base) + Int64 (Phys_Offset (FB)) + Int64 (FB_Size (FB)) <=
Nico Huber5374c3a2017-07-15 21:48:06 +0200683 Int64 (GTT_Address_Type'Last))
684 with
685 Ghost;
686
Nico Huber83693c82016-10-08 22:17:55 +0200687 procedure Write_GTT
688 (GTT_Page : GTT_Range;
689 Device_Address : GTT_Address_Type;
Nico Huber5374c3a2017-07-15 21:48:06 +0200690 Valid : Boolean)
691 is
Nico Huber83693c82016-10-08 22:17:55 +0200692 begin
693 Registers.Write_GTT (GTT_Page, Device_Address, Valid);
694 end Write_GTT;
695
Nico Huberceda17d2018-06-09 22:00:29 +0200696 procedure Read_GTT
697 (Device_Address : out GTT_Address_Type;
698 Valid : out Boolean;
699 GTT_Page : in GTT_Range)
700 is
701 begin
702 Registers.Read_GTT (Device_Address, Valid, GTT_Page);
703 end Read_GTT;
704
Nico Huber194e57e2017-07-15 21:15:46 +0200705 procedure Setup_Default_GTT (FB : Framebuffer_Type; Phys_Base : Word32)
Nico Huber5374c3a2017-07-15 21:48:06 +0200706 with
707 Pre => Is_Initialized and Valid_Phys_FB (FB, Phys_Base)
Nico Huber83693c82016-10-08 22:17:55 +0200708 is
Nico Huber194e57e2017-07-15 21:15:46 +0200709 Phys_Addr : GTT_Address_Type :=
Nico Huber34be6542017-12-13 09:26:24 +0100710 GTT_Address_Type (Phys_Base) + GTT_Address_Type (Phys_Offset (FB));
Nico Huber83693c82016-10-08 22:17:55 +0200711 begin
Nico Huber194e57e2017-07-15 21:15:46 +0200712 for Idx in FB_First_Page (FB) .. FB_Last_Page (FB) loop
Nico Huber83693c82016-10-08 22:17:55 +0200713 Registers.Write_GTT
714 (GTT_Page => Idx,
715 Device_Address => Phys_Addr,
716 Valid => True);
Nico Huber194e57e2017-07-15 21:15:46 +0200717 Phys_Addr := Phys_Addr + GTT_Page_Size;
Nico Huber83693c82016-10-08 22:17:55 +0200718 end loop;
Nico Huber2e87c0d2020-04-18 00:46:39 +0200719 -- Add another 128 dummy pages to work around buggy VT-d
720 for Idx in FB_Last_Page (FB) + 1 .. FB_Last_Page (FB) + 128 loop
721 Registers.Write_GTT (Idx, Phys_Addr, True);
722 end loop;
Nico Huber9b479412017-08-27 11:55:56 +0200723
724 if Rotation_90 (FB) and FB.Tiling = Y_Tiled and FB.V_Stride >= 32 then
725 declare
726 V_Pages : constant Natural := Natural (FB.V_Stride) / 32;
727 Bytes_Per_Row : constant GTT_Address_Type :=
728 GTT_Address_Type (Pixel_To_Bytes (32 * FB.Stride, FB));
729 begin
730 Phys_Addr := GTT_Address_Type (Phys_Base) +
Nico Huber34be6542017-12-13 09:26:24 +0100731 GTT_Address_Type (Phys_Offset (FB)) +
Nico Huber9b479412017-08-27 11:55:56 +0200732 GTT_Address_Type (FB_Size (FB));
733 for Page in FB_First_Page (FB) .. FB_Last_Page (FB) loop
734 Phys_Addr := Phys_Addr - Bytes_Per_Row;
735 Registers.Write_GTT
736 (GTT_Page => GTT_Rotation_Offset + Page,
737 Device_Address => Phys_Addr,
738 Valid => True);
739
740 if (Page - FB_First_Page (FB) + 1) mod V_Pages = 0 then
741 Phys_Addr := Phys_Addr + GTT_Page_Size +
742 GTT_Address_Type (V_Pages) * Bytes_Per_Row;
743 end if;
744 end loop;
745 end;
Nico Huber2e87c0d2020-04-18 00:46:39 +0200746 -- Add another 128 dummy pages to work around buggy VT-d
747 for Idx in FB_Last_Page (FB) + 1 .. FB_Last_Page (FB) + 128 loop
748 Registers.Write_GTT (GTT_Rotation_Offset + Idx, Phys_Addr, True);
749 end loop;
Nico Huber9b479412017-08-27 11:55:56 +0200750 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200751 end Setup_Default_GTT;
752
753 ----------------------------------------------------------------------------
754
Nico Hubereedde882017-07-16 02:54:39 +0200755 use type HW.Word16;
756 subtype Stolen_Size_Range is Int64 range 0 .. 2 ** 33;
757
758 function GGMS_Gen4 (GGC : Word16) return Natural is
759 (Natural (Shift_Right (GGC, 8) and 16#07#));
760 function GTT_Size_Gen4 (GGC : Word16) return Natural is
761 (if GGMS_Gen4 (GGC) in 1 .. 3 then
762 (GGMS_Gen4 (GGC) + 1) * 2 ** 19 else 0);
763
764 function GMS_Gen4 (GGC : Word16) return Natural is
765 (Natural (Shift_Right (GGC, 4) and 16#0f#));
766 Valid_Stolen_Size_Gen4 : constant
767 array (Natural range 1 .. 13) of Stolen_Size_Range :=
768 (1, 4, 8, 16, 32, 48, 64, 128, 256, 96, 160, 224, 352);
769 function Stolen_Size_Gen4 (GGC : Word16) return Stolen_Size_Range is
770 (if GMS_Gen4 (GGC) in Valid_Stolen_Size_Gen4'Range then
Arthur Heymans5fd9a312017-09-12 12:45:18 +0200771 Valid_Stolen_Size_Gen4 (GMS_Gen4 (GGC)) * 2 ** 20 else 0);
Nico Hubereedde882017-07-16 02:54:39 +0200772
773 function GTT_Size_Gen6 (GGC : Word16) return Natural is
774 (Natural (Shift_Right (GGC, 8) and 16#03#) * 2 ** 20);
775
776 function Stolen_Size_Gen6 (GGC : Word16) return Stolen_Size_Range is
777 (Stolen_Size_Range (Shift_Right (GGC, 3) and 16#1f#) * 32 * 2 ** 20);
778
Nico Huberfe7985f2019-10-12 22:19:24 +0200779 function GGMS_Gen8 (GGC : Word16) return Natural is
780 (Natural (Shift_Right (GGC, 6) and 16#03#));
Nico Hubereedde882017-07-16 02:54:39 +0200781 function GTT_Size_Gen8 (GGC : Word16) return Natural is
Nico Huberfe7985f2019-10-12 22:19:24 +0200782 (if GGMS_Gen8 (GGC) /= 0 then
783 Natural (Shift_Left (Word32'(1), 20 + GGMS_Gen8 (GGC))) else 0);
Nico Hubereedde882017-07-16 02:54:39 +0200784
785 function GMS_Gen8 (GGC : Word16) return Stolen_Size_Range is
786 (Stolen_Size_Range (Shift_Right (GGC, 8) and 16#ff#));
787 function Stolen_Size_Gen8 (GGC : Word16) return Stolen_Size_Range is
788 (GMS_Gen8 (GGC) * 32 * 2 ** 20);
789
790 function Stolen_Size_Gen9 (GGC : Word16) return Stolen_Size_Range is
791 (if GMS_Gen8 (GGC) < 16#f0# then
792 Stolen_Size_Gen8 (GGC)
793 else
794 (GMS_Gen8 (GGC) - 16#f0# + 1) * 4 * 2 ** 20);
795
796 procedure Decode_Stolen
797 (GTT_Size : out Natural;
798 Stolen_Size : out Stolen_Size_Range)
799 with
800 Pre => Is_Initialized
801 is
Nico Huber63ec8362018-06-09 17:42:19 +0200802 GGC_Reg : constant PCI.Index :=
Nico Huber998ee2b2018-06-12 23:02:17 +0200803 (if Config.Gen_G45 or Config.CPU_Ironlake then 16#52# else 16#50#);
Nico Hubereedde882017-07-16 02:54:39 +0200804 GGC : Word16;
805 begin
806 Dev.Read16 (GGC, GGC_Reg);
Nico Huber998ee2b2018-06-12 23:02:17 +0200807 if Config.Gen_G45 or Config.CPU_Ironlake then
808 GTT_Size := GTT_Size_Gen4 (GGC);
809 Stolen_Size := Stolen_Size_Gen4 (GGC);
810 elsif Config.CPU_Sandybridge or Config.CPU_Ivybridge or Config.CPU_Haswell
811 then
812 GTT_Size := GTT_Size_Gen6 (GGC);
813 Stolen_Size := Stolen_Size_Gen6 (GGC);
814 elsif Config.CPU_Broadwell then
815 GTT_Size := GTT_Size_Gen8 (GGC);
816 Stolen_Size := Stolen_Size_Gen8 (GGC);
817 else
818 GTT_Size := GTT_Size_Gen8 (GGC);
819 Stolen_Size := Stolen_Size_Gen9 (GGC);
820 end if;
Nico Hubereedde882017-07-16 02:54:39 +0200821 end Decode_Stolen;
822
823 -- Additional runtime validation that FB fits stolen memory and aperture.
824 procedure Validate_FB (FB : Framebuffer_Type; Valid : out Boolean)
825 with
826 Pre => Is_Initialized,
827 Post => (if Valid then Valid_FB (FB))
828 is
Nico Huber2e87c0d2020-04-18 00:46:39 +0200829 GTT_Off : constant Natural :=
830 (if Rotation_90 (FB) then GTT_Rotation_Offset else 0);
831
Nico Hubereedde882017-07-16 02:54:39 +0200832 GTT_Size, Aperture_Size : Natural;
833 Stolen_Size : Stolen_Size_Range;
834 begin
835 Valid := Valid_FB (FB);
836
837 if Valid then
838 Decode_Stolen (GTT_Size, Stolen_Size);
839 Dev.Resource_Size (Aperture_Size, PCI.Res2);
840 Valid :=
Nico Huber2e87c0d2020-04-18 00:46:39 +0200841 FB_Last_Page (FB) + 128 + GTT_Off < GTT_Size / Config.GTT_PTE_Size
842 and
843 FB_Last_Page (FB) < Natural (Stolen_Size / GTT_Page_Size)
844 and
Nico Hubereedde882017-07-16 02:54:39 +0200845 FB_Last_Page (FB) < Aperture_Size / GTT_Page_Size;
Nico Huber34be6542017-12-13 09:26:24 +0100846 pragma Debug (not Valid, Debug.Put_Line
Nico Hubereedde882017-07-16 02:54:39 +0200847 ("Stolen memory too small to hold framebuffer."));
848 end if;
849 end Validate_FB;
850
Nico Huber5374c3a2017-07-15 21:48:06 +0200851 procedure Setup_Default_FB
852 (FB : in Framebuffer_Type;
853 Clear : in Boolean := True;
854 Success : out Boolean)
855 is
856 GMA_Phys_Base : constant PCI.Index := 16#5c#;
857 GMA_Phys_Base_Mask : constant := 16#fff0_0000#;
858
859 Phys_Base : Word32;
860 begin
Nico Hubereedde882017-07-16 02:54:39 +0200861 Validate_FB (FB, Success);
Nico Huber5374c3a2017-07-15 21:48:06 +0200862
863 if Success then
864 Dev.Read32 (Phys_Base, GMA_Phys_Base);
865 Phys_Base := Phys_Base and GMA_Phys_Base_Mask;
866 Success := Phys_Base /= GMA_Phys_Base_Mask and Phys_Base /= 0;
867 pragma Debug (not Success, Debug.Put_Line
868 ("Failed to read stolen memory base."));
Nico Huber0164b022017-08-24 15:12:51 +0200869
870 if Success then
871 if FB.Tiling in XY_Tiling then
872 Registers.Add_Fence
873 (First_Page => FB_First_Page (FB),
874 Last_Page => FB_Last_Page (FB),
875 Tiling => FB.Tiling,
876 Pitch => FB_Pitch (FB.Stride, FB),
877 Success => Success);
878 end if;
879 pragma Debug (not Success, Debug.Put_Line
880 ("Tiled framebuffer but no fence regs available."));
881 end if;
882
Nico Huber5374c3a2017-07-15 21:48:06 +0200883 if Success then
884 Setup_Default_GTT (FB, Phys_Base);
885 end if;
886 end if;
887
888 if Success and then Clear then
889 declare
890 use type HW.Word64;
891 Linear_FB : Word64;
892 begin
Nico Huberc3f66f62017-07-16 21:39:54 +0200893 Map_Linear_FB (Linear_FB, FB);
Nico Huber5374c3a2017-07-15 21:48:06 +0200894 if Linear_FB /= 0 then
Nico Huberc3f66f62017-07-16 21:39:54 +0200895 Framebuffer_Filler.Fill (Linear_FB, FB);
Nico Huber5374c3a2017-07-15 21:48:06 +0200896 end if;
Nico Huber5374c3a2017-07-15 21:48:06 +0200897 end;
898 end if;
899 end Setup_Default_FB;
900
Nico Huberc3f66f62017-07-16 21:39:54 +0200901 procedure Map_Linear_FB (Linear_FB : out Word64; FB : in Framebuffer_Type)
902 is
903 use type HW.Word64;
904
905 Valid : Boolean;
906 begin
907 Linear_FB := 0;
908
909 if Linear_FB_Base = 0 then
910 Dev.Map (Linear_FB_Base, PCI.Res2);
911 pragma Debug
912 (Linear_FB_Base = 0, Debug.Put_Line ("Failed to map resource2."));
913 end if;
914
915 if Linear_FB_Base /= 0 then
916 Validate_FB (FB, Valid);
917 if Valid then
Nico Huber34be6542017-12-13 09:26:24 +0100918 Linear_FB := Linear_FB_Base + Word64 (Phys_Offset (FB));
Nico Huberc3f66f62017-07-16 21:39:54 +0200919 end if;
920 end if;
921 end Map_Linear_FB;
922
Nico Huber5374c3a2017-07-15 21:48:06 +0200923 ----------------------------------------------------------------------------
924
Nico Huber99f10f32016-11-20 00:34:05 +0100925 procedure Dump_Configs (Configs : Pipe_Configs)
Nico Huber83693c82016-10-08 22:17:55 +0200926 is
927 subtype Pipe_Name is String (1 .. 9);
Nico Huber99f10f32016-11-20 00:34:05 +0100928 type Pipe_Name_Array is array (Pipe_Index) of Pipe_Name;
Nico Huber83693c82016-10-08 22:17:55 +0200929 Pipe_Names : constant Pipe_Name_Array :=
930 (Primary => "Primary ",
931 Secondary => "Secondary",
932 Tertiary => "Tertiary ");
Nico Huber5ef4d602017-12-13 13:56:47 +0100933
934 subtype Tiling_Name is String (1 .. 7);
935 type Tiling_Name_Array is array (Tiling_Type) of Tiling_Name;
936 Tilings : constant Tiling_Name_Array :=
937 (Linear => "Linear ",
938 X_Tiled => "X_Tiled",
939 Y_Tiled => "Y_Tiled");
940
941 subtype Rotation_Name is String (1 .. 11);
942 type Rotation_Name_Array is array (Rotation_Type) of Rotation_Name;
943 Rotations : constant Rotation_Name_Array :=
944 (No_Rotation => "No_Rotation",
945 Rotated_90 => "Rotated_90 ",
946 Rotated_180 => "Rotated_180",
947 Rotated_270 => "Rotated_270");
Nico Huber83693c82016-10-08 22:17:55 +0200948 begin
949 Debug.New_Line;
Paul Menzelb83107c2017-05-04 09:02:33 +0200950 Debug.Put_Line ("CONFIG =>");
Nico Huber99f10f32016-11-20 00:34:05 +0100951 for Pipe in Pipe_Index loop
952 if Pipe = Pipe_Index'First then
Nico Huber83693c82016-10-08 22:17:55 +0200953 Debug.Put (" (");
954 else
955 Debug.Put (" ");
956 end if;
957 Debug.Put_Line (Pipe_Names (Pipe) & " =>");
958 Debug.Put_Line
959 (" (Port => " & Port_Names (Configs (Pipe).Port) & ",");
960 Debug.Put_Line (" Framebuffer =>");
Nico Huber5ef4d602017-12-13 13:56:47 +0100961 Debug.Put (" (Width => ");
Nico Huber83693c82016-10-08 22:17:55 +0200962 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Width);
963 Debug.Put_Line (",");
Nico Huber5ef4d602017-12-13 13:56:47 +0100964 Debug.Put (" Height => ");
Nico Huber83693c82016-10-08 22:17:55 +0200965 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Height);
966 Debug.Put_Line (",");
Nico Huber5ef4d602017-12-13 13:56:47 +0100967 Debug.Put (" Start_X => ");
968 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Start_X);
969 Debug.Put_Line (",");
970 Debug.Put (" Start_Y => ");
971 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Start_Y);
972 Debug.Put_Line (",");
973 Debug.Put (" Stride => ");
Nico Huber83693c82016-10-08 22:17:55 +0200974 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Stride);
975 Debug.Put_Line (",");
Nico Huber5ef4d602017-12-13 13:56:47 +0100976 Debug.Put (" V_Stride => ");
977 Debug.Put_Int32 (Configs (Pipe).Framebuffer.V_Stride);
978 Debug.Put_Line (",");
979 Debug.Put (" Tiling => ");
980 Debug.Put_Line (Tilings (Configs (Pipe).Framebuffer.Tiling) & ",");
981 Debug.Put (" Rotation => ");
982 Debug.Put_Line (Rotations (Configs (Pipe).Framebuffer.Rotation) & ",");
Nico Huber83693c82016-10-08 22:17:55 +0200983 Debug.Put (" Offset => ");
984 Debug.Put_Word32 (Configs (Pipe).Framebuffer.Offset);
985 Debug.Put_Line (",");
986 Debug.Put (" BPC => ");
987 Debug.Put_Int64 (Configs (Pipe).Framebuffer.BPC);
988 Debug.Put_Line ("),");
989 Debug.Put_Line (" Mode =>");
990 Debug.Put (" (Dotclock => ");
991 Debug.Put_Int64 (Configs (Pipe).Mode.Dotclock);
992 Debug.Put_Line (",");
993 Debug.Put (" H_Visible => ");
Nico Huberc5c767a2018-06-03 01:09:04 +0200994 Debug.Put_Int32 (Configs (Pipe).Mode.H_Visible);
Nico Huber83693c82016-10-08 22:17:55 +0200995 Debug.Put_Line (",");
996 Debug.Put (" H_Sync_Begin => ");
Nico Huberc5c767a2018-06-03 01:09:04 +0200997 Debug.Put_Int32 (Configs (Pipe).Mode.H_Sync_Begin);
Nico Huber83693c82016-10-08 22:17:55 +0200998 Debug.Put_Line (",");
999 Debug.Put (" H_Sync_End => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001000 Debug.Put_Int32 (Configs (Pipe).Mode.H_Sync_End);
Nico Huber83693c82016-10-08 22:17:55 +02001001 Debug.Put_Line (",");
1002 Debug.Put (" H_Total => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001003 Debug.Put_Int32 (Configs (Pipe).Mode.H_Total);
Nico Huber83693c82016-10-08 22:17:55 +02001004 Debug.Put_Line (",");
1005 Debug.Put (" V_Visible => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001006 Debug.Put_Int32 (Configs (Pipe).Mode.V_Visible);
Nico Huber83693c82016-10-08 22:17:55 +02001007 Debug.Put_Line (",");
1008 Debug.Put (" V_Sync_Begin => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001009 Debug.Put_Int32 (Configs (Pipe).Mode.V_Sync_Begin);
Nico Huber83693c82016-10-08 22:17:55 +02001010 Debug.Put_Line (",");
1011 Debug.Put (" V_Sync_End => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001012 Debug.Put_Int32 (Configs (Pipe).Mode.V_Sync_End);
Nico Huber83693c82016-10-08 22:17:55 +02001013 Debug.Put_Line (",");
1014 Debug.Put (" V_Total => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001015 Debug.Put_Int32 (Configs (Pipe).Mode.V_Total);
Nico Huber83693c82016-10-08 22:17:55 +02001016 Debug.Put_Line (",");
1017 Debug.Put_Line (" H_Sync_Active_High => " &
1018 (if Configs (Pipe).Mode.H_Sync_Active_High
1019 then "True,"
1020 else "False,"));
1021 Debug.Put_Line (" V_Sync_Active_High => " &
1022 (if Configs (Pipe).Mode.V_Sync_Active_High
1023 then "True,"
1024 else "False,"));
1025 Debug.Put (" BPC => ");
1026 Debug.Put_Int64 (Configs (Pipe).Mode.BPC);
Nico Huber99f10f32016-11-20 00:34:05 +01001027 if Pipe /= Pipe_Index'Last then
Nico Huber83693c82016-10-08 22:17:55 +02001028 Debug.Put_Line (")),");
1029 else
1030 Debug.Put_Line (")));");
1031 end if;
1032 end loop;
1033 end Dump_Configs;
1034
Nico Huberc5c66ec2019-09-28 23:59:45 +02001035 ----------------------------------------------------------------------------
1036
1037 procedure PCI_Read16 (Value : out Word16; Offset : HW.PCI.Index) is
1038 begin
1039 Dev.Read16 (Value, Offset);
1040 end PCI_Read16;
1041
Nico Huber83693c82016-10-08 22:17:55 +02001042end HW.GFX.GMA;