blob: cacafd35de062b3fabdf477e702120ac4f6bd0d2 [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
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060056 subtype Port_Name is String (1 .. 10);
Nico Huber83693c82016-10-08 22:17:55 +020057 type Port_Name_Array is array (Port_Type) of Port_Name;
58 Port_Names : constant Port_Name_Array :=
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060059 (Disabled => "Disabled ",
60 LVDS => "LVDS ",
61 eDP => "eDP ",
62 DP1 => "DP1 ",
63 DP2 => "DP2 ",
64 DP3 => "DP3 ",
65 HDMI1 => "HDMI1 ",
66 HDMI2 => "HDMI2 ",
67 HDMI3 => "HDMI3 ",
68 Analog => "Analog ",
69 USBC1_DP => "USBC1-DP ",
70 USBC2_DP => "USBC2-DP ",
71 USBC3_DP => "USBC3-DP ",
72 USBC4_DP => "USBC4-DP ",
73 USBC5_DP => "USBC5-DP ",
74 USBC6_DP => "USBC6-DP ",
75 USBC1_HDMI => "USBC1-HDMI",
76 USBC2_HDMI => "USBC2-HDMI",
77 USBC3_HDMI => "USBC3-HDMI",
78 USBC4_HDMI => "USBC4-HDMI",
79 USBC5_HDMI => "USBC5-HDMI",
80 USBC6_HDMI => "USBC6-HDMI");
Nico Huber83693c82016-10-08 22:17:55 +020081
Nico Huber2b6f6992017-07-09 18:11:34 +020082 package Dev is new HW.PCI.Dev (PCI.Address'(0, 2, 0));
83
Nico Huber83693c82016-10-08 22:17:55 +020084 package Display_Controller renames Pipe_Setup;
85
Nico Huber99f10f32016-11-20 00:34:05 +010086 type PLLs_Type is array (Pipe_Index) of PLLs.T;
Nico Huber83693c82016-10-08 22:17:55 +020087
Nico Huber83693c82016-10-08 22:17:55 +020088 type HPD_Type is array (Port_Type) of Boolean;
Nico Huber3be61d42017-01-09 13:58:18 +010089 type HPD_Delay_Type is array (Active_Port_Type) of Time.T;
Nico Huber83693c82016-10-08 22:17:55 +020090
Nico Huber83693c82016-10-08 22:17:55 +020091 Allocated_PLLs : PLLs_Type;
Nico Huber83693c82016-10-08 22:17:55 +020092 HPD_Delay : HPD_Delay_Type;
93 Wait_For_HPD : HPD_Type;
94 Initialized : Boolean := False;
95
Nico Huberc3f66f62017-07-16 21:39:54 +020096 Linear_FB_Base : Word64;
97
Nico Huber83693c82016-10-08 22:17:55 +020098 ----------------------------------------------------------------------------
99
Tim Wawrzynczakfc49b602022-09-09 10:29:24 -0600100 ICP_RAWCLK_NUM : constant := 1 * 2 ** 11;
101
102 function PCH_RAWCLK_FREQ_MASK return Word32 is
103 Mask : Word32;
104 begin
105 if Config.Need_Rawclk_Numerator then
106 Mask := 16#ffff_ffff#;
107 elsif Config.Has_Fractional_RawClk then
108 Mask := 16#3fff# * 2 ** 16;
109 else
110 Mask := 16#3ff# * 2 ** 0;
111 end if;
112 return Mask;
113 end PCH_RAWCLK_FREQ_MASK;
Nico Huberf54d0962016-10-20 14:17:18 +0200114
115 function PCH_RAWCLK_FREQ (Freq : Frequency_Type) return Word32
116 is
117 begin
Nico Huberdde06302020-12-20 02:18:30 +0100118 if Config.Has_Fractional_RawClk then
119 declare
120 Fraction_K : constant Int64 := Freq / 1_000 mod 1_000;
121 Freq32 : Word32 := Shift_Left (Word32 (Freq / 1_000_000), 16);
122 begin
123 if Fraction_K /= 0 then
124 Freq32 := Freq32 or Shift_Left
125 (Word32 (Div_Round_Closest (1_000, Fraction_K) - 1), 26);
126 end if;
Tim Wawrzynczakfc49b602022-09-09 10:29:24 -0600127
128 if Config.Need_Rawclk_Numerator then
129 Freq32 := Freq32 or ICP_RAWCLK_NUM;
130 end if;
Nico Huberdde06302020-12-20 02:18:30 +0100131 return Freq32;
132 end;
133 else
134 return Word32 (Freq / 1_000_000);
135 end if;
Nico Huberf54d0962016-10-20 14:17:18 +0200136 end PCH_RAWCLK_FREQ;
137
138 ----------------------------------------------------------------------------
139
Nico Huber43370ba2017-01-09 15:26:19 +0100140 procedure Enable_Output
141 (Pipe : in Pipe_Index;
142 Pipe_Cfg : in Pipe_Config;
143 Success : out Boolean)
Nico Huber8a5a3b52018-06-04 14:42:13 +0200144 with
Nico Huber9a4c4c32019-09-16 22:05:11 +0200145 Pre =>
146 Pipe_Cfg.Port in Active_Port_Type and
147 Config_Helpers.Valid_FB (Pipe_Cfg.Framebuffer, Pipe_Cfg.Mode)
Nico Huber43370ba2017-01-09 15:26:19 +0100148 is
149 Port_Cfg : Port_Config;
150 begin
Nico Huber3be61d42017-01-09 13:58:18 +0100151 pragma Debug (Debug.New_Line);
152 pragma Debug (Debug.Put_Line
153 ("Trying to enable port " & Port_Names (Pipe_Cfg.Port)));
154
Nico Huber43370ba2017-01-09 15:26:19 +0100155 Config_Helpers.Fill_Port_Config
156 (Port_Cfg, Pipe, Pipe_Cfg.Port, Pipe_Cfg.Mode, Success);
157
158 if Success then
Nico Huber43370ba2017-01-09 15:26:19 +0100159 Connector_Info.Preferred_Link_Setting (Port_Cfg, Success);
160 end if;
161
162 -- loop over all possible DP-lane configurations
163 -- (non-DP ports use a single fake configuration)
164 while Success loop
165 pragma Loop_Invariant
166 (Pipe_Cfg.Port in Active_Port_Type and
167 Port_Cfg.Mode = Port_Cfg.Mode'Loop_Entry);
168
169 PLLs.Alloc
170 (Port_Cfg => Port_Cfg,
171 PLL => Allocated_PLLs (Pipe),
172 Success => Success);
173
174 if Success then
175 -- try each DP-lane configuration twice
176 for Try in 1 .. 2 loop
177 pragma Loop_Invariant
178 (Pipe_Cfg.Port in Active_Port_Type);
179
Nico Huber4798c662017-01-11 12:44:48 +0100180 -- Clear pending hot-plug events before every try
181 Port_Detect.Clear_Hotplug_Detect (Pipe_Cfg.Port);
182
Nico Huber43370ba2017-01-09 15:26:19 +0100183 Connectors.Pre_On
184 (Pipe => Pipe,
185 Port_Cfg => Port_Cfg,
186 PLL_Hint => PLLs.Register_Value (Allocated_PLLs (Pipe)),
187 Success => Success);
188
189 if Success then
190 Display_Controller.On
191 (Pipe => Pipe,
192 Port_Cfg => Port_Cfg,
Nico Huber4dc4c612018-01-10 15:55:09 +0100193 Framebuffer => Pipe_Cfg.Framebuffer,
194 Cursor => Pipe_Cfg.Cursor);
Nico Huber43370ba2017-01-09 15:26:19 +0100195
196 Connectors.Post_On
Arthur Heymans60d0e5f2018-03-28 17:08:27 +0200197 (Pipe => Pipe,
198 Port_Cfg => Port_Cfg,
Nico Huber43370ba2017-01-09 15:26:19 +0100199 PLL_Hint => PLLs.Register_Value (Allocated_PLLs (Pipe)),
200 Success => Success);
201
202 if not Success then
203 Display_Controller.Off (Pipe);
204 Connectors.Post_Off (Port_Cfg);
205 end if;
206 end if;
207
208 exit when Success;
209 end loop;
210 exit when Success; -- connection established => stop loop
211
212 -- connection failed
213 PLLs.Free (Allocated_PLLs (Pipe));
214 end if;
215
216 Connector_Info.Next_Link_Setting (Port_Cfg, Success);
217 end loop;
218
219 if Success then
220 pragma Debug (Debug.Put_Line
221 ("Enabled port " & Port_Names (Pipe_Cfg.Port)));
222 else
223 Wait_For_HPD (Pipe_Cfg.Port) := True;
Nico Huber2bbd6e72020-01-07 18:22:59 +0100224 Panel.Off (Config_Helpers.To_Panel (Pipe_Cfg.Port));
Nico Huber43370ba2017-01-09 15:26:19 +0100225 end if;
226 end Enable_Output;
227
Nico Huber3be61d42017-01-09 13:58:18 +0100228 procedure Disable_Output (Pipe : Pipe_Index; Pipe_Cfg : Pipe_Config)
229 is
230 Port_Cfg : Port_Config;
231 Success : Boolean;
232 begin
233 Config_Helpers.Fill_Port_Config
234 (Port_Cfg, Pipe, Pipe_Cfg.Port, Pipe_Cfg.Mode, Success);
235 if Success then
236 pragma Debug (Debug.New_Line);
237 pragma Debug (Debug.Put_Line
238 ("Disabling port " & Port_Names (Pipe_Cfg.Port)));
239 pragma Debug (Debug.New_Line);
240
Jeremy Compostellafe80fbb2023-01-11 14:05:42 -0700241 if Pipe_Cfg.Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
242 Display_Controller.Legacy_VGA_Off;
243 end if;
244
Nico Huber3be61d42017-01-09 13:58:18 +0100245 Connectors.Pre_Off (Port_Cfg);
246 Display_Controller.Off (Pipe);
247 Connectors.Post_Off (Port_Cfg);
248
249 PLLs.Free (Allocated_PLLs (Pipe));
250 end if;
251 end Disable_Output;
252
Nico Huber99f10f32016-11-20 00:34:05 +0100253 procedure Update_Outputs (Configs : Pipe_Configs)
Nico Huber83693c82016-10-08 22:17:55 +0200254 is
Nico Huber3be61d42017-01-09 13:58:18 +0100255 procedure Check_HPD (Port : in Active_Port_Type; Detected : out Boolean)
256 is
257 HPD_Delay_Over : constant Boolean := Time.Timed_Out (HPD_Delay (Port));
258 begin
259 if HPD_Delay_Over then
260 Port_Detect.Hotplug_Detect (Port, Detected);
261 HPD_Delay (Port) := Time.MS_From_Now (333);
262 else
263 Detected := False;
264 end if;
265 end Check_HPD;
Nico Huberb56b9c52017-01-11 15:12:23 +0100266
Nico Huber9a4c4c32019-09-16 22:05:11 +0200267 Scaler_Reservation : Display_Controller.Scaler_Reservation :=
268 Display_Controller.Null_Scaler_Reservation;
Nico Huber564103f2017-01-11 15:33:07 +0100269
Nico Huber9a4c4c32019-09-16 22:05:11 +0200270 Update_Power : Boolean := False;
Nico Huberb0bbdbc2019-09-27 22:32:21 +0200271 Update_CDClk : Boolean;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200272 Old_Configs,
273 New_Configs : Pipe_Configs;
Nico Huber3d06de82018-05-29 01:35:04 +0200274
275 function Full_Update (Cur_Config, New_Config : Pipe_Config) return Boolean
276 is
277 begin
278 return
Nico Huber958c5642018-06-02 16:59:31 +0200279 Cur_Config.Port /= New_Config.Port
280 or else
281 Cur_Config.Mode /= New_Config.Mode
282 or else
Nico Huber3d06de82018-05-29 01:35:04 +0200283 (Config.Use_PDW_For_EDP_Scaling and then
Nico Huber8beafd72020-01-07 14:59:44 +0100284 (Cur_Config.Port = eDP and
Nico Huber958c5642018-06-02 16:59:31 +0200285 Requires_Scaling (Cur_Config) /= Requires_Scaling (New_Config)))
286 or else
287 (Config.Has_GMCH_PFIT_CONTROL and then
288 (Requires_Scaling (Cur_Config) /= Requires_Scaling (New_Config) or
289 Scaling_Type (Cur_Config) /= Scaling_Type (New_Config)));
Nico Huber3d06de82018-05-29 01:35:04 +0200290 end Full_Update;
Nico Huber83693c82016-10-08 22:17:55 +0200291 begin
292 Old_Configs := Cur_Configs;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200293 New_Configs := Configs;
294
295 -- validate new configs, filter invalid configs and those waiting for HPD
296 for Pipe in Pipe_Index loop
297 declare
298 Success : Boolean := True;
299 Cur_Config : Pipe_Config renames Cur_Configs (Pipe);
300 New_Config : Pipe_Config renames New_Configs (Pipe);
301 begin
302 if New_Config.Port /= Disabled then
303 if Wait_For_HPD (New_Config.Port) then
304 Check_HPD (New_Config.Port, Success);
305 Wait_For_HPD (New_Config.Port) := not Success;
306 end if;
307
308 Success := Success and then
309 Config_Helpers.Validate_Config
310 (New_Config.Framebuffer, New_Config.Mode, Pipe);
311
312 if Success and then Requires_Scaling (New_Config) then
313 Display_Controller.Reserve_Scaler
314 (Success, Scaler_Reservation, Pipe);
315 end if;
316
317 if not Success then
318 New_Config.Port := Disabled;
319 end if;
320 end if;
321 end;
322 pragma Loop_Invariant
323 (for all P in Pipe_Index'First .. Pipe =>
324 New_Configs (P).Port = Disabled or
325 Config_Helpers.Valid_FB
326 (New_Configs (P).Framebuffer, New_Configs (P).Mode));
327 end loop;
Nico Huber83693c82016-10-08 22:17:55 +0200328
Nico Huberb0bbdbc2019-09-27 22:32:21 +0200329 -- limit dotclocks to maximum CDClk, if we are about
330 -- to switch CDClk, all pipes have to be disabled
331 Power_And_Clocks.Limit_Dotclocks (New_Configs, Update_CDClk);
332
Nico Huberb56b9c52017-01-11 15:12:23 +0100333 -- disable all pipes that changed or had a hot-plug event
334 for Pipe in Pipe_Index loop
335 declare
336 Unplug_Detected : Boolean;
337 Cur_Config : Pipe_Config renames Cur_Configs (Pipe);
Nico Huber9a4c4c32019-09-16 22:05:11 +0200338 New_Config : Pipe_Config renames New_Configs (Pipe);
Nico Huberb56b9c52017-01-11 15:12:23 +0100339 begin
340 if Cur_Config.Port /= Disabled then
341 Check_HPD (Cur_Config.Port, Unplug_Detected);
Nico Huber83693c82016-10-08 22:17:55 +0200342
Nico Huberb0bbdbc2019-09-27 22:32:21 +0200343 if Update_CDClk or
344 Unplug_Detected or
345 Full_Update (Cur_Config, New_Config)
346 then
Nico Huberb56b9c52017-01-11 15:12:23 +0100347 Disable_Output (Pipe, Cur_Config);
348 Cur_Config.Port := Disabled;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200349 Update_Power := True;
Nico Huberb56b9c52017-01-11 15:12:23 +0100350 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200351 end if;
Nico Huberb56b9c52017-01-11 15:12:23 +0100352 end;
353 end loop;
Nico Huber83693c82016-10-08 22:17:55 +0200354
Nico Huberb0bbdbc2019-09-27 22:32:21 +0200355 -- switch CDClk if necessary and possible, limit dotclocks accordingly
356 if Update_CDClk then
357 Power_And_Clocks.Update_CDClk (New_Configs);
358 end if;
359
Nico Huberb56b9c52017-01-11 15:12:23 +0100360 -- enable all pipes that changed and should be active
361 for Pipe in Pipe_Index loop
362 declare
363 Success : Boolean;
364 Cur_Config : Pipe_Config renames Cur_Configs (Pipe);
Nico Huber9a4c4c32019-09-16 22:05:11 +0200365 New_Config : Pipe_Config renames New_Configs (Pipe);
Nico Huberb56b9c52017-01-11 15:12:23 +0100366 begin
Nico Huber9a4c4c32019-09-16 22:05:11 +0200367 -- full update
Nico Huber3d06de82018-05-29 01:35:04 +0200368 if New_Config.Port /= Disabled and
369 Full_Update (Cur_Config, New_Config)
Nico Huberb56b9c52017-01-11 15:12:23 +0100370 then
Nico Huber9a4c4c32019-09-16 22:05:11 +0200371 Power_And_Clocks.Power_Up (Old_Configs, New_Configs);
372 Update_Power := True;
Nico Huberc7a4fee2016-11-03 18:18:03 +0100373
Nico Huber9a4c4c32019-09-16 22:05:11 +0200374 Enable_Output (Pipe, New_Config, Success);
Nico Huber83693c82016-10-08 22:17:55 +0200375 if Success then
Nico Huberb56b9c52017-01-11 15:12:23 +0100376 Cur_Config := New_Config;
Nico Huber83693c82016-10-08 22:17:55 +0200377 end if;
Nico Huber3be61d42017-01-09 13:58:18 +0100378
Nico Huberb56b9c52017-01-11 15:12:23 +0100379 -- update framebuffer offset only
380 elsif New_Config.Port /= Disabled and
Nico Huberf361ec82018-06-02 18:01:45 +0200381 Cur_Config.Framebuffer /= New_Config.Framebuffer
Nico Huberb56b9c52017-01-11 15:12:23 +0100382 then
Nico Huber9a4c4c32019-09-16 22:05:11 +0200383 Display_Controller.Setup_FB
384 (Pipe, New_Config.Mode, New_Config.Framebuffer);
385 Display_Controller.Update_Cursor
386 (Pipe, New_Config.Framebuffer, New_Config.Cursor);
387 Cur_Config := New_Config;
Nico Huberb56b9c52017-01-11 15:12:23 +0100388 end if;
389 end;
Nico Huber83693c82016-10-08 22:17:55 +0200390 end loop;
391
Nico Huber9a4c4c32019-09-16 22:05:11 +0200392 if Update_Power then
393 Power_And_Clocks.Power_Down (Old_Configs, New_Configs, Cur_Configs);
Nico Huber83693c82016-10-08 22:17:55 +0200394 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200395 end Update_Outputs;
396
397 ----------------------------------------------------------------------------
398
Nico Huber15ffc4f2018-01-11 14:44:43 +0100399 procedure Update_Cursor (Pipe : Pipe_Index; Cursor : Cursor_Type)
400 is
401 begin
402 Cur_Configs (Pipe).Cursor := Cursor;
403 Display_Controller.Update_Cursor
404 (Pipe, Cur_Configs (Pipe).Framebuffer, Cur_Configs (Pipe).Cursor);
405 end Update_Cursor;
406
407 procedure Place_Cursor
408 (Pipe : Pipe_Index;
409 X : Cursor_Pos;
410 Y : Cursor_Pos)
411 is
412 begin
413 Cur_Configs (Pipe).Cursor.Center_X := X;
414 Cur_Configs (Pipe).Cursor.Center_Y := Y;
415 Display_Controller.Place_Cursor
416 (Pipe, Cur_Configs (Pipe).Framebuffer, Cur_Configs (Pipe).Cursor);
417 end Place_Cursor;
418
419 procedure Move_Cursor
420 (Pipe : Pipe_Index;
421 X : Cursor_Pos;
422 Y : Cursor_Pos)
423 is
424 function Cap_Add (A, B : Cursor_Pos) return Cursor_Pos is
425 (if A + B < 0
426 then Int32'Max (Cursor_Pos'First, A + B)
427 else Int32'Min (Cursor_Pos'Last, A + B));
428 begin
429 Place_Cursor
430 (Pipe => Pipe,
431 X => Cap_Add (Cur_Configs (Pipe).Cursor.Center_X, X),
432 Y => Cap_Add (Cur_Configs (Pipe).Cursor.Center_Y, Y));
433 end Move_Cursor;
434
435 ----------------------------------------------------------------------------
436
Nico Huberbc0588e2020-07-21 12:17:19 +0200437 procedure Backlight_On (Port : Active_Port_Type)
438 with
439 Refined_Global => (In_Out => Registers.Register_State)
440 is
441 begin
442 Panel.Backlight_On (Config_Helpers.To_Panel (Port));
443 end Backlight_On;
444
445 procedure Backlight_Off (Port : Active_Port_Type)
446 with
447 Refined_Global => (In_Out => Registers.Register_State)
448 is
449 begin
450 Panel.Backlight_Off (Config_Helpers.To_Panel (Port));
451 end Backlight_Off;
452
453 procedure Set_Brightness (Port : Active_Port_Type; Level : Word32)
454 with
455 Refined_Global => (In_Out => Registers.Register_State)
456 is
457 begin
458 Panel.Set_Backlight (Config_Helpers.To_Panel (Port), Level);
459 end Set_Brightness;
460
461 procedure Get_Max_Brightness (Port : Active_Port_Type; Level : out Word32)
462 with
463 Refined_Global => (In_Out => Registers.Register_State)
464 is
465 begin
466 Panel.Get_Max_Backlight (Config_Helpers.To_Panel (Port), Level);
467 end Get_Max_Brightness;
468
469 ----------------------------------------------------------------------------
470
Nico Huber793f4f82022-09-04 14:24:00 +0000471 pragma Warnings
472 (GNATprove, Off, """Registers.GTT_State"" * is not modified*",
473 Reason => "The whole, abstract Device_State is modified in certain configurations.");
474 pragma Warnings
475 (GNATprove, Off, "no check message justified*", Reason => "see below");
Nico Huber83693c82016-10-08 22:17:55 +0200476 procedure Initialize
Nico Huber2b6f6992017-07-09 18:11:34 +0200477 (Write_Delay : in Word64 := 0;
Nico Huber793a8d42016-11-21 18:57:03 +0100478 Clean_State : in Boolean := False;
Nico Huber83693c82016-10-08 22:17:55 +0200479 Success : out Boolean)
480 with
481 Refined_Global =>
Nico Huber27088aa2018-06-10 13:28:05 +0200482 (Input => (Time.State),
Nico Huber793f4f82022-09-04 14:24:00 +0000483 In_Out =>
484 (Dev.PCI_State, Port_IO.State,
485 Registers.Register_State, Registers.GTT_State),
Nico Huber83693c82016-10-08 22:17:55 +0200486 Output =>
Nico Huberc5c66ec2019-09-28 23:59:45 +0200487 (PCI_Usable,
488 Config.Variable,
Nico Huber27088aa2018-06-10 13:28:05 +0200489 Dev.Address_State,
Nico Huber2b6f6992017-07-09 18:11:34 +0200490 Registers.Address_State,
Nico Huber312433c2019-09-28 03:15:48 +0200491 PCode.Mailbox_Ready,
Nico Huber83693c82016-10-08 22:17:55 +0200492 PLLs.State, Panel.Panel_State,
Nico Huber1a712d32017-01-09 15:11:04 +0100493 Cur_Configs, Allocated_PLLs,
Nico Huberc3f66f62017-07-16 21:39:54 +0200494 HPD_Delay, Wait_For_HPD,
495 Linear_FB_Base, Initialized))
Nico Huber83693c82016-10-08 22:17:55 +0200496 is
497 use type HW.Word64;
498
Nico Huber0b2329a2018-06-09 21:14:27 +0200499 function MMIO_GTT_Offset return Natural is
500 (if Config.Has_64bit_GTT
501 then Registers.MMIO_GTT_64_Offset
502 else Registers.MMIO_GTT_32_Offset);
Nico Huber2b6f6992017-07-09 18:11:34 +0200503 PCI_MMIO_Base, PCI_GTT_Base : Word64;
504
Nico Huber83693c82016-10-08 22:17:55 +0200505 Now : constant Time.T := Time.Now;
506
507 procedure Check_Platform (Success : out Boolean)
508 is
509 Audio_VID_DID : Word32;
510 begin
Nico Huber6621a142018-06-07 23:56:54 +0200511 case Config.Gen is
Arthur Heymans73ea0322018-03-28 17:17:07 +0200512 when G45 =>
513 Registers.Read (Registers.G4X_AUD_VID_DID, Audio_VID_DID);
Nico Huber6621a142018-06-07 23:56:54 +0200514 when Ironlake =>
515 Registers.Read (Registers.PCH_AUD_VID_DID, Audio_VID_DID);
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600516 when Haswell .. Tigerlake =>
Nico Huber83693c82016-10-08 22:17:55 +0200517 Registers.Read (Registers.AUD_VID_DID, Audio_VID_DID);
Nico Huber83693c82016-10-08 22:17:55 +0200518 end case;
519 Success :=
Nico Huber998ee2b2018-06-12 23:02:17 +0200520 ((Config.Gen_Broxton and Audio_VID_DID = 16#8086_280a#) or
Nico Huber88badbe2018-09-27 16:36:47 +0200521 (Config.CPU_Kabylake and Audio_VID_DID = 16#8086_280b#) or
522 (Config.CPU_Skylake and Audio_VID_DID = 16#8086_2809#) or
Nico Huber998ee2b2018-06-12 23:02:17 +0200523 (Config.CPU_Broadwell and Audio_VID_DID = 16#8086_2808#) or
524 (Config.CPU_Haswell and Audio_VID_DID = 16#8086_2807#) or
525 ((Config.CPU_Ivybridge or
526 Config.CPU_Sandybridge) and (Audio_VID_DID = 16#8086_2806# or
527 Audio_VID_DID = 16#8086_2805#)) or
528 (Config.CPU_Ironlake and Audio_VID_DID = 16#0000_0000#) or
529 (Config.Gen_G45 and (Audio_VID_DID = 16#8086_2801# or
530 Audio_VID_DID = 16#8086_2802# or
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600531 Audio_VID_DID = 16#8086_2803#)) or
532 (Config.CPU_Tigerlake and (Audio_VID_DID = 16#8086_2812#)));
Nico Huber83693c82016-10-08 22:17:55 +0200533 end Check_Platform;
Nico Hubere7ac6eb2017-09-04 23:54:13 +0200534
535 procedure Check_Platform_PCI (Success : out Boolean)
536 is
537 use type HW.Word16;
538 Vendor, Device : Word16;
539 begin
540 Dev.Read16 (Vendor, PCI.Vendor_Id);
541 Dev.Read16 (Device, PCI.Device_Id);
542
Nico Huber6a996dc2018-06-17 16:30:33 +0200543 Config.Detect_CPU (Device);
Nico Hubere7ac6eb2017-09-04 23:54:13 +0200544 Success := Vendor = 16#8086# and Config.Compatible_GPU (Device);
545 end Check_Platform_PCI;
Nico Huber83693c82016-10-08 22:17:55 +0200546 begin
Nico Huber83693c82016-10-08 22:17:55 +0200547 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
548
549 pragma Debug (Debug.Set_Register_Write_Delay (Write_Delay));
550
Nico Huberc5c66ec2019-09-28 23:59:45 +0200551 PCI_Usable := False;
Nico Huberc3f66f62017-07-16 21:39:54 +0200552 Linear_FB_Base := 0;
Nico Huber312433c2019-09-28 03:15:48 +0200553 PCode.Mailbox_Ready := False;
Nico Huber83693c82016-10-08 22:17:55 +0200554 Wait_For_HPD := HPD_Type'(others => False);
555 HPD_Delay := HPD_Delay_Type'(others => Now);
Nico Huber83693c82016-10-08 22:17:55 +0200556 Allocated_PLLs := (others => PLLs.Invalid);
Nico Huber99f10f32016-11-20 00:34:05 +0100557 Cur_Configs := Pipe_Configs'
558 (others => Pipe_Config'
Nico Huber83693c82016-10-08 22:17:55 +0200559 (Port => Disabled,
560 Framebuffer => HW.GFX.Default_FB,
Nico Hubera02b2c62018-01-09 15:58:34 +0100561 Cursor => Default_Cursor,
Nico Huber83693c82016-10-08 22:17:55 +0200562 Mode => HW.GFX.Invalid_Mode));
Nico Huber27088aa2018-06-10 13:28:05 +0200563 Config.Variable := Config.Initial_Settings;
Nico Huber6a996dc2018-06-17 16:30:33 +0200564 Registers.Set_Register_Base (Config.Default_MMIO_Base);
Nico Huber83693c82016-10-08 22:17:55 +0200565 PLLs.Initialize;
566
Nico Huber2b6f6992017-07-09 18:11:34 +0200567 Dev.Initialize (Success);
568
569 if Success then
Nico Huber6a996dc2018-06-17 16:30:33 +0200570 Check_Platform_PCI (Success);
Nico Hubere7ac6eb2017-09-04 23:54:13 +0200571 if Success then
Nico Huber6a996dc2018-06-17 16:30:33 +0200572 Dev.Map (PCI_MMIO_Base, PCI.Res0, Length => MMIO_GTT_Offset);
573 Dev.Map (PCI_GTT_Base, PCI.Res0, Offset => MMIO_GTT_Offset);
574 if PCI_MMIO_Base /= 0 and PCI_GTT_Base /= 0 then
575 Registers.Set_Register_Base (PCI_MMIO_Base, PCI_GTT_Base);
Nico Huberc5c66ec2019-09-28 23:59:45 +0200576 PCI_Usable := True;
Nico Huber6a996dc2018-06-17 16:30:33 +0200577 else
578 pragma Debug (Debug.Put_Line
579 ("ERROR: Couldn't map resoure0."));
580 Success := Config.Default_MMIO_Base_Set;
581 end if;
Nico Hubere7ac6eb2017-09-04 23:54:13 +0200582 end if;
Nico Huber2b6f6992017-07-09 18:11:34 +0200583 else
584 pragma Debug (Debug.Put_Line
585 ("WARNING: Couldn't initialize PCI dev."));
Nico Huber2b6f6992017-07-09 18:11:34 +0200586 Success := Config.Default_MMIO_Base_Set;
Nico Huber2b6f6992017-07-09 18:11:34 +0200587
Nico Hubere7ac6eb2017-09-04 23:54:13 +0200588 if Success then
589 Check_Platform (Success);
590 end if;
Nico Huber2b6f6992017-07-09 18:11:34 +0200591 end if;
592
Nico Huber5dbaf4b2020-01-08 17:24:58 +0100593 Panel.Static_Init; -- early for flow analysis
594
Nico Huber83693c82016-10-08 22:17:55 +0200595 if not Success then
596 pragma Debug (Debug.Put_Line ("ERROR: Incompatible CPU or PCH."));
597
Nico Huber83693c82016-10-08 22:17:55 +0200598 Initialized := False;
599 return;
600 end if;
601
602 Panel.Setup_PP_Sequencer;
603 Port_Detect.Initialize;
Nico Huber0923b792017-06-09 15:28:41 +0200604 Connectors.Initialize;
Nico Huber83693c82016-10-08 22:17:55 +0200605
Nico Huber793a8d42016-11-21 18:57:03 +0100606 if Clean_State then
607 Power_And_Clocks.Pre_All_Off;
608 Connectors.Pre_All_Off;
609 Display_Controller.All_Off;
610 Connectors.Post_All_Off;
611 PLLs.All_Off;
612 Power_And_Clocks.Post_All_Off;
Nico Huber17d64b62017-07-15 20:51:25 +0200613 Registers.Clear_Fences;
Nico Huber33912aa2016-12-06 20:36:23 +0100614 else
615 -- According to PRMs, VGA plane is the only thing
Nico Huber3a0e2a02017-07-19 14:41:46 +0200616 -- that's enabled by default after reset...
Nico Huber33912aa2016-12-06 20:36:23 +0100617 Display_Controller.Legacy_VGA_Off;
Nico Huber3a0e2a02017-07-19 14:41:46 +0200618 -- ... along with some DDI port bits since Skylake.
619 Connectors.Post_Reset_Off;
Nico Huber793a8d42016-11-21 18:57:03 +0100620 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200621
622 -------------------- Now restart from a clean state ---------------------
623 Power_And_Clocks.Initialize;
624
Nico Huber1c3b9282017-02-09 13:57:04 +0100625 if Config.Has_PCH then
626 Registers.Unset_And_Set_Mask
627 (Register => Registers.PCH_RAWCLK_FREQ,
628 Mask_Unset => PCH_RAWCLK_FREQ_MASK,
Nico Huberc9ad9de2020-12-20 02:34:37 +0100629 Mask_Set => PCH_RAWCLK_FREQ (Config.Raw_Clock));
Nico Huber1c3b9282017-02-09 13:57:04 +0100630 end if;
Nico Huberf54d0962016-10-20 14:17:18 +0200631
Nico Huber83693c82016-10-08 22:17:55 +0200632 Initialized := True;
633
634 end Initialize;
Nico Huber793f4f82022-09-04 14:24:00 +0000635 pragma Annotate
636 (GNATprove, Intentional, "unused global",
637 "The whole, abstract Device_State is modified in certain configurations.");
638 pragma Warnings (GNATprove, On, "no check message justified*");
639 pragma Warnings
640 (GNATprove, On, """Registers.GTT_State"" * is not modified*");
Nico Huber83693c82016-10-08 22:17:55 +0200641
642 function Is_Initialized return Boolean
643 with
644 Refined_Post => Is_Initialized'Result = Initialized
645 is
646 begin
647 return Initialized;
648 end Is_Initialized;
649
650 ----------------------------------------------------------------------------
651
Nico Hubercf88f3d2018-06-05 13:27:34 +0200652 pragma Warnings
653 (GNATprove, Off, """Registers.Register_State"" * is not modified*",
Nico Huberadfe11f2018-06-10 14:59:04 +0200654 Reason => "Power_Up_VGA is only effective in certain configurations.");
Nico Huber17b513e2022-09-04 13:36:02 +0200655 pragma Warnings
656 (GNATprove, Off, "no check message justified*", Reason => "see below");
Nico Huber42fb2d02017-09-01 17:01:51 +0200657 procedure Power_Up_VGA
Nico Hubercf88f3d2018-06-05 13:27:34 +0200658 with
659 Refined_Global =>
Nico Huberadfe11f2018-06-10 14:59:04 +0200660 (Input => (Cur_Configs, Config.Variable, Time.State),
Nico Hubercf88f3d2018-06-05 13:27:34 +0200661 In_Out => (Registers.Register_State),
662 Proof_In => (Initialized))
Nico Huber42fb2d02017-09-01 17:01:51 +0200663 is
664 Fake_Config : constant Pipe_Configs :=
665 (Primary =>
666 (Port => Analog,
667 Framebuffer => HW.GFX.Default_FB,
Nico Hubera02b2c62018-01-09 15:58:34 +0100668 Cursor => Default_Cursor,
Nico Huber42fb2d02017-09-01 17:01:51 +0200669 Mode => HW.GFX.Invalid_Mode),
670 others =>
671 (Port => Disabled,
672 Framebuffer => HW.GFX.Default_FB,
Nico Hubera02b2c62018-01-09 15:58:34 +0100673 Cursor => Default_Cursor,
Nico Huber42fb2d02017-09-01 17:01:51 +0200674 Mode => HW.GFX.Invalid_Mode));
675 begin
676 Power_And_Clocks.Power_Up (Cur_Configs, Fake_Config);
677 end Power_Up_VGA;
Nico Hubercf88f3d2018-06-05 13:27:34 +0200678 pragma Annotate
679 (GNATprove, Intentional, "unused global",
Nico Huberadfe11f2018-06-10 14:59:04 +0200680 "Power_Up_VGA is only effective in certain configurations.");
Nico Hubercf88f3d2018-06-05 13:27:34 +0200681 pragma Warnings (GNATprove, On, "no check message justified*");
682 pragma Warnings
683 (GNATprove, On, """Registers.Register_State"" * is not modified*");
Nico Huber42fb2d02017-09-01 17:01:51 +0200684
685 ----------------------------------------------------------------------------
686
Nico Huber5374c3a2017-07-15 21:48:06 +0200687 function FB_First_Page (FB : Framebuffer_Type) return Natural is
Nico Huber34be6542017-12-13 09:26:24 +0100688 (Natural (Phys_Offset (FB) / GTT_Page_Size));
Nico Huber5374c3a2017-07-15 21:48:06 +0200689 function FB_Pages (FB : Framebuffer_Type) return Natural is
690 (Natural (Div_Round_Up (FB_Size (FB), GTT_Page_Size)));
691 function FB_Last_Page (FB : Framebuffer_Type) return Natural is
692 (FB_First_Page (FB) + FB_Pages (FB) - 1);
693
Nico Huber34be6542017-12-13 09:26:24 +0100694 -- Check basics and that it fits in GTT. For 90 degree rotations,
695 -- the Offset should be above GTT_Rotation_Offset. The latter will
696 -- be subtracted for the aperture mapping.
Nico Huber5374c3a2017-07-15 21:48:06 +0200697 function Valid_FB (FB : Framebuffer_Type) return Boolean is
Nico Huber34be6542017-12-13 09:26:24 +0100698 (Valid_Stride (FB) and
699 FB_First_Page (FB) in GTT_Range and
Nico Huber2e87c0d2020-04-18 00:46:39 +0200700 FB_Last_Page (FB) + 128 in GTT_Range and
Nico Huber34be6542017-12-13 09:26:24 +0100701 (not Rotation_90 (FB) or
Nico Huber2e87c0d2020-04-18 00:46:39 +0200702 (FB_First_Page (FB) mod 64 = 0 and
703 FB_Last_Page (FB) + 128 + GTT_Rotation_Offset in GTT_Range and
Nico Huber34be6542017-12-13 09:26:24 +0100704 FB.Offset >= Word32 (GTT_Rotation_Offset) * GTT_Page_Size)));
Nico Huber5374c3a2017-07-15 21:48:06 +0200705
706 -- Also check that we don't overflow the GTT's 39-bit space
707 -- (always true with a 32-bit base)
708 function Valid_Phys_FB (FB : Framebuffer_Type; Phys_Base : Word32)
709 return Boolean is
710 (Valid_FB (FB) and
Nico Huber34be6542017-12-13 09:26:24 +0100711 Int64 (Phys_Base) + Int64 (Phys_Offset (FB)) + Int64 (FB_Size (FB)) <=
Nico Huber5374c3a2017-07-15 21:48:06 +0200712 Int64 (GTT_Address_Type'Last))
713 with
714 Ghost;
715
Nico Huber83693c82016-10-08 22:17:55 +0200716 procedure Write_GTT
717 (GTT_Page : GTT_Range;
718 Device_Address : GTT_Address_Type;
Nico Huber5374c3a2017-07-15 21:48:06 +0200719 Valid : Boolean)
720 is
Nico Huber83693c82016-10-08 22:17:55 +0200721 begin
722 Registers.Write_GTT (GTT_Page, Device_Address, Valid);
723 end Write_GTT;
724
Nico Huberceda17d2018-06-09 22:00:29 +0200725 procedure Read_GTT
726 (Device_Address : out GTT_Address_Type;
727 Valid : out Boolean;
728 GTT_Page : in GTT_Range)
729 is
730 begin
731 Registers.Read_GTT (Device_Address, Valid, GTT_Page);
732 end Read_GTT;
733
Nico Huber194e57e2017-07-15 21:15:46 +0200734 procedure Setup_Default_GTT (FB : Framebuffer_Type; Phys_Base : Word32)
Nico Huber5374c3a2017-07-15 21:48:06 +0200735 with
736 Pre => Is_Initialized and Valid_Phys_FB (FB, Phys_Base)
Nico Huber83693c82016-10-08 22:17:55 +0200737 is
Nico Huber194e57e2017-07-15 21:15:46 +0200738 Phys_Addr : GTT_Address_Type :=
Nico Huber34be6542017-12-13 09:26:24 +0100739 GTT_Address_Type (Phys_Base) + GTT_Address_Type (Phys_Offset (FB));
Nico Huber83693c82016-10-08 22:17:55 +0200740 begin
Nico Huber194e57e2017-07-15 21:15:46 +0200741 for Idx in FB_First_Page (FB) .. FB_Last_Page (FB) loop
Nico Huber83693c82016-10-08 22:17:55 +0200742 Registers.Write_GTT
743 (GTT_Page => Idx,
744 Device_Address => Phys_Addr,
745 Valid => True);
Nico Huber194e57e2017-07-15 21:15:46 +0200746 Phys_Addr := Phys_Addr + GTT_Page_Size;
Nico Huber83693c82016-10-08 22:17:55 +0200747 end loop;
Nico Huber2e87c0d2020-04-18 00:46:39 +0200748 -- Add another 128 dummy pages to work around buggy VT-d
749 for Idx in FB_Last_Page (FB) + 1 .. FB_Last_Page (FB) + 128 loop
750 Registers.Write_GTT (Idx, Phys_Addr, True);
751 end loop;
Nico Huber9b479412017-08-27 11:55:56 +0200752
753 if Rotation_90 (FB) and FB.Tiling = Y_Tiled and FB.V_Stride >= 32 then
754 declare
755 V_Pages : constant Natural := Natural (FB.V_Stride) / 32;
756 Bytes_Per_Row : constant GTT_Address_Type :=
757 GTT_Address_Type (Pixel_To_Bytes (32 * FB.Stride, FB));
758 begin
759 Phys_Addr := GTT_Address_Type (Phys_Base) +
Nico Huber34be6542017-12-13 09:26:24 +0100760 GTT_Address_Type (Phys_Offset (FB)) +
Nico Huber9b479412017-08-27 11:55:56 +0200761 GTT_Address_Type (FB_Size (FB));
762 for Page in FB_First_Page (FB) .. FB_Last_Page (FB) loop
763 Phys_Addr := Phys_Addr - Bytes_Per_Row;
764 Registers.Write_GTT
765 (GTT_Page => GTT_Rotation_Offset + Page,
766 Device_Address => Phys_Addr,
767 Valid => True);
768
769 if (Page - FB_First_Page (FB) + 1) mod V_Pages = 0 then
770 Phys_Addr := Phys_Addr + GTT_Page_Size +
771 GTT_Address_Type (V_Pages) * Bytes_Per_Row;
772 end if;
773 end loop;
774 end;
Nico Huber2e87c0d2020-04-18 00:46:39 +0200775 -- Add another 128 dummy pages to work around buggy VT-d
776 for Idx in FB_Last_Page (FB) + 1 .. FB_Last_Page (FB) + 128 loop
777 Registers.Write_GTT (GTT_Rotation_Offset + Idx, Phys_Addr, True);
778 end loop;
Nico Huber9b479412017-08-27 11:55:56 +0200779 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200780 end Setup_Default_GTT;
781
782 ----------------------------------------------------------------------------
783
Nico Hubereedde882017-07-16 02:54:39 +0200784 use type HW.Word16;
785 subtype Stolen_Size_Range is Int64 range 0 .. 2 ** 33;
786
787 function GGMS_Gen4 (GGC : Word16) return Natural is
788 (Natural (Shift_Right (GGC, 8) and 16#07#));
789 function GTT_Size_Gen4 (GGC : Word16) return Natural is
790 (if GGMS_Gen4 (GGC) in 1 .. 3 then
791 (GGMS_Gen4 (GGC) + 1) * 2 ** 19 else 0);
792
793 function GMS_Gen4 (GGC : Word16) return Natural is
794 (Natural (Shift_Right (GGC, 4) and 16#0f#));
795 Valid_Stolen_Size_Gen4 : constant
796 array (Natural range 1 .. 13) of Stolen_Size_Range :=
797 (1, 4, 8, 16, 32, 48, 64, 128, 256, 96, 160, 224, 352);
798 function Stolen_Size_Gen4 (GGC : Word16) return Stolen_Size_Range is
799 (if GMS_Gen4 (GGC) in Valid_Stolen_Size_Gen4'Range then
Arthur Heymans5fd9a312017-09-12 12:45:18 +0200800 Valid_Stolen_Size_Gen4 (GMS_Gen4 (GGC)) * 2 ** 20 else 0);
Nico Hubereedde882017-07-16 02:54:39 +0200801
802 function GTT_Size_Gen6 (GGC : Word16) return Natural is
803 (Natural (Shift_Right (GGC, 8) and 16#03#) * 2 ** 20);
804
805 function Stolen_Size_Gen6 (GGC : Word16) return Stolen_Size_Range is
806 (Stolen_Size_Range (Shift_Right (GGC, 3) and 16#1f#) * 32 * 2 ** 20);
807
Nico Huberfe7985f2019-10-12 22:19:24 +0200808 function GGMS_Gen8 (GGC : Word16) return Natural is
809 (Natural (Shift_Right (GGC, 6) and 16#03#));
Nico Hubereedde882017-07-16 02:54:39 +0200810 function GTT_Size_Gen8 (GGC : Word16) return Natural is
Nico Huberfe7985f2019-10-12 22:19:24 +0200811 (if GGMS_Gen8 (GGC) /= 0 then
812 Natural (Shift_Left (Word32'(1), 20 + GGMS_Gen8 (GGC))) else 0);
Nico Hubereedde882017-07-16 02:54:39 +0200813
814 function GMS_Gen8 (GGC : Word16) return Stolen_Size_Range is
815 (Stolen_Size_Range (Shift_Right (GGC, 8) and 16#ff#));
816 function Stolen_Size_Gen8 (GGC : Word16) return Stolen_Size_Range is
817 (GMS_Gen8 (GGC) * 32 * 2 ** 20);
818
819 function Stolen_Size_Gen9 (GGC : Word16) return Stolen_Size_Range is
820 (if GMS_Gen8 (GGC) < 16#f0# then
821 Stolen_Size_Gen8 (GGC)
822 else
823 (GMS_Gen8 (GGC) - 16#f0# + 1) * 4 * 2 ** 20);
824
825 procedure Decode_Stolen
826 (GTT_Size : out Natural;
827 Stolen_Size : out Stolen_Size_Range)
828 with
829 Pre => Is_Initialized
830 is
Nico Huber63ec8362018-06-09 17:42:19 +0200831 GGC_Reg : constant PCI.Index :=
Nico Huber998ee2b2018-06-12 23:02:17 +0200832 (if Config.Gen_G45 or Config.CPU_Ironlake then 16#52# else 16#50#);
Nico Hubereedde882017-07-16 02:54:39 +0200833 GGC : Word16;
834 begin
835 Dev.Read16 (GGC, GGC_Reg);
Nico Huber998ee2b2018-06-12 23:02:17 +0200836 if Config.Gen_G45 or Config.CPU_Ironlake then
837 GTT_Size := GTT_Size_Gen4 (GGC);
838 Stolen_Size := Stolen_Size_Gen4 (GGC);
839 elsif Config.CPU_Sandybridge or Config.CPU_Ivybridge or Config.CPU_Haswell
840 then
841 GTT_Size := GTT_Size_Gen6 (GGC);
842 Stolen_Size := Stolen_Size_Gen6 (GGC);
843 elsif Config.CPU_Broadwell then
844 GTT_Size := GTT_Size_Gen8 (GGC);
845 Stolen_Size := Stolen_Size_Gen8 (GGC);
846 else
847 GTT_Size := GTT_Size_Gen8 (GGC);
848 Stolen_Size := Stolen_Size_Gen9 (GGC);
849 end if;
Nico Hubereedde882017-07-16 02:54:39 +0200850 end Decode_Stolen;
851
852 -- Additional runtime validation that FB fits stolen memory and aperture.
853 procedure Validate_FB (FB : Framebuffer_Type; Valid : out Boolean)
854 with
855 Pre => Is_Initialized,
856 Post => (if Valid then Valid_FB (FB))
857 is
Nico Huber2e87c0d2020-04-18 00:46:39 +0200858 GTT_Off : constant Natural :=
859 (if Rotation_90 (FB) then GTT_Rotation_Offset else 0);
860
Nico Hubereedde882017-07-16 02:54:39 +0200861 GTT_Size, Aperture_Size : Natural;
862 Stolen_Size : Stolen_Size_Range;
863 begin
864 Valid := Valid_FB (FB);
865
866 if Valid then
867 Decode_Stolen (GTT_Size, Stolen_Size);
868 Dev.Resource_Size (Aperture_Size, PCI.Res2);
869 Valid :=
Nico Huber2e87c0d2020-04-18 00:46:39 +0200870 FB_Last_Page (FB) + 128 + GTT_Off < GTT_Size / Config.GTT_PTE_Size
871 and
872 FB_Last_Page (FB) < Natural (Stolen_Size / GTT_Page_Size)
873 and
Nico Hubereedde882017-07-16 02:54:39 +0200874 FB_Last_Page (FB) < Aperture_Size / GTT_Page_Size;
Nico Huber34be6542017-12-13 09:26:24 +0100875 pragma Debug (not Valid, Debug.Put_Line
Nico Hubereedde882017-07-16 02:54:39 +0200876 ("Stolen memory too small to hold framebuffer."));
877 end if;
878 end Validate_FB;
879
Nico Huber5374c3a2017-07-15 21:48:06 +0200880 procedure Setup_Default_FB
881 (FB : in Framebuffer_Type;
882 Clear : in Boolean := True;
883 Success : out Boolean)
884 is
Nico Huber5374c3a2017-07-15 21:48:06 +0200885 GMA_Phys_Base_Mask : constant := 16#fff0_0000#;
886
887 Phys_Base : Word32;
888 begin
Nico Hubereedde882017-07-16 02:54:39 +0200889 Validate_FB (FB, Success);
Nico Huber5374c3a2017-07-15 21:48:06 +0200890
891 if Success then
Tim Wawrzynczak1b65b842022-09-09 10:23:06 -0600892 if Config.GMA_Base_Is_64bit then
893 Dev.Read32 (Phys_Base, Config.GMA_Phys_Base_Index + 4);
894 if Phys_Base /= 0 then
895 pragma Debug (Debug.Put_Line ("Cannot handle 64-bit DSM yet."));
896 Success := False;
897 return;
898 end if;
899 end if;
900
901 Dev.Read32 (Phys_Base, Config.GMA_Phys_Base_Index);
Nico Huber5374c3a2017-07-15 21:48:06 +0200902 Phys_Base := Phys_Base and GMA_Phys_Base_Mask;
903 Success := Phys_Base /= GMA_Phys_Base_Mask and Phys_Base /= 0;
904 pragma Debug (not Success, Debug.Put_Line
905 ("Failed to read stolen memory base."));
Nico Huber0164b022017-08-24 15:12:51 +0200906
907 if Success then
908 if FB.Tiling in XY_Tiling then
909 Registers.Add_Fence
910 (First_Page => FB_First_Page (FB),
911 Last_Page => FB_Last_Page (FB),
912 Tiling => FB.Tiling,
913 Pitch => FB_Pitch (FB.Stride, FB),
914 Success => Success);
915 end if;
916 pragma Debug (not Success, Debug.Put_Line
917 ("Tiled framebuffer but no fence regs available."));
918 end if;
919
Nico Huber5374c3a2017-07-15 21:48:06 +0200920 if Success then
921 Setup_Default_GTT (FB, Phys_Base);
922 end if;
923 end if;
924
925 if Success and then Clear then
926 declare
927 use type HW.Word64;
928 Linear_FB : Word64;
929 begin
Nico Huberc3f66f62017-07-16 21:39:54 +0200930 Map_Linear_FB (Linear_FB, FB);
Nico Huber5374c3a2017-07-15 21:48:06 +0200931 if Linear_FB /= 0 then
Nico Huberc3f66f62017-07-16 21:39:54 +0200932 Framebuffer_Filler.Fill (Linear_FB, FB);
Nico Huber5374c3a2017-07-15 21:48:06 +0200933 end if;
Nico Huber5374c3a2017-07-15 21:48:06 +0200934 end;
935 end if;
936 end Setup_Default_FB;
937
Nico Huberc3f66f62017-07-16 21:39:54 +0200938 procedure Map_Linear_FB (Linear_FB : out Word64; FB : in Framebuffer_Type)
939 is
940 use type HW.Word64;
941
942 Valid : Boolean;
943 begin
944 Linear_FB := 0;
945
946 if Linear_FB_Base = 0 then
947 Dev.Map (Linear_FB_Base, PCI.Res2);
948 pragma Debug
949 (Linear_FB_Base = 0, Debug.Put_Line ("Failed to map resource2."));
950 end if;
951
952 if Linear_FB_Base /= 0 then
953 Validate_FB (FB, Valid);
954 if Valid then
Nico Huber34be6542017-12-13 09:26:24 +0100955 Linear_FB := Linear_FB_Base + Word64 (Phys_Offset (FB));
Nico Huberc3f66f62017-07-16 21:39:54 +0200956 end if;
957 end if;
958 end Map_Linear_FB;
959
Nico Huber5374c3a2017-07-15 21:48:06 +0200960 ----------------------------------------------------------------------------
961
Nico Huber99f10f32016-11-20 00:34:05 +0100962 procedure Dump_Configs (Configs : Pipe_Configs)
Nico Huber83693c82016-10-08 22:17:55 +0200963 is
964 subtype Pipe_Name is String (1 .. 9);
Nico Huber99f10f32016-11-20 00:34:05 +0100965 type Pipe_Name_Array is array (Pipe_Index) of Pipe_Name;
Nico Huber83693c82016-10-08 22:17:55 +0200966 Pipe_Names : constant Pipe_Name_Array :=
967 (Primary => "Primary ",
968 Secondary => "Secondary",
969 Tertiary => "Tertiary ");
Nico Huber5ef4d602017-12-13 13:56:47 +0100970
971 subtype Tiling_Name is String (1 .. 7);
972 type Tiling_Name_Array is array (Tiling_Type) of Tiling_Name;
973 Tilings : constant Tiling_Name_Array :=
974 (Linear => "Linear ",
975 X_Tiled => "X_Tiled",
976 Y_Tiled => "Y_Tiled");
977
978 subtype Rotation_Name is String (1 .. 11);
979 type Rotation_Name_Array is array (Rotation_Type) of Rotation_Name;
980 Rotations : constant Rotation_Name_Array :=
981 (No_Rotation => "No_Rotation",
982 Rotated_90 => "Rotated_90 ",
983 Rotated_180 => "Rotated_180",
984 Rotated_270 => "Rotated_270");
Nico Huber83693c82016-10-08 22:17:55 +0200985 begin
986 Debug.New_Line;
Paul Menzelb83107c2017-05-04 09:02:33 +0200987 Debug.Put_Line ("CONFIG =>");
Nico Huber99f10f32016-11-20 00:34:05 +0100988 for Pipe in Pipe_Index loop
989 if Pipe = Pipe_Index'First then
Nico Huber83693c82016-10-08 22:17:55 +0200990 Debug.Put (" (");
991 else
992 Debug.Put (" ");
993 end if;
994 Debug.Put_Line (Pipe_Names (Pipe) & " =>");
995 Debug.Put_Line
996 (" (Port => " & Port_Names (Configs (Pipe).Port) & ",");
997 Debug.Put_Line (" Framebuffer =>");
Nico Huber5ef4d602017-12-13 13:56:47 +0100998 Debug.Put (" (Width => ");
Nico Huber83693c82016-10-08 22:17:55 +0200999 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Width);
1000 Debug.Put_Line (",");
Nico Huber5ef4d602017-12-13 13:56:47 +01001001 Debug.Put (" Height => ");
Nico Huber83693c82016-10-08 22:17:55 +02001002 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Height);
1003 Debug.Put_Line (",");
Nico Huber5ef4d602017-12-13 13:56:47 +01001004 Debug.Put (" Start_X => ");
1005 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Start_X);
1006 Debug.Put_Line (",");
1007 Debug.Put (" Start_Y => ");
1008 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Start_Y);
1009 Debug.Put_Line (",");
1010 Debug.Put (" Stride => ");
Nico Huber83693c82016-10-08 22:17:55 +02001011 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Stride);
1012 Debug.Put_Line (",");
Nico Huber5ef4d602017-12-13 13:56:47 +01001013 Debug.Put (" V_Stride => ");
1014 Debug.Put_Int32 (Configs (Pipe).Framebuffer.V_Stride);
1015 Debug.Put_Line (",");
1016 Debug.Put (" Tiling => ");
1017 Debug.Put_Line (Tilings (Configs (Pipe).Framebuffer.Tiling) & ",");
1018 Debug.Put (" Rotation => ");
1019 Debug.Put_Line (Rotations (Configs (Pipe).Framebuffer.Rotation) & ",");
Nico Huber83693c82016-10-08 22:17:55 +02001020 Debug.Put (" Offset => ");
1021 Debug.Put_Word32 (Configs (Pipe).Framebuffer.Offset);
1022 Debug.Put_Line (",");
1023 Debug.Put (" BPC => ");
1024 Debug.Put_Int64 (Configs (Pipe).Framebuffer.BPC);
1025 Debug.Put_Line ("),");
1026 Debug.Put_Line (" Mode =>");
1027 Debug.Put (" (Dotclock => ");
1028 Debug.Put_Int64 (Configs (Pipe).Mode.Dotclock);
1029 Debug.Put_Line (",");
1030 Debug.Put (" H_Visible => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001031 Debug.Put_Int32 (Configs (Pipe).Mode.H_Visible);
Nico Huber83693c82016-10-08 22:17:55 +02001032 Debug.Put_Line (",");
1033 Debug.Put (" H_Sync_Begin => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001034 Debug.Put_Int32 (Configs (Pipe).Mode.H_Sync_Begin);
Nico Huber83693c82016-10-08 22:17:55 +02001035 Debug.Put_Line (",");
1036 Debug.Put (" H_Sync_End => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001037 Debug.Put_Int32 (Configs (Pipe).Mode.H_Sync_End);
Nico Huber83693c82016-10-08 22:17:55 +02001038 Debug.Put_Line (",");
1039 Debug.Put (" H_Total => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001040 Debug.Put_Int32 (Configs (Pipe).Mode.H_Total);
Nico Huber83693c82016-10-08 22:17:55 +02001041 Debug.Put_Line (",");
1042 Debug.Put (" V_Visible => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001043 Debug.Put_Int32 (Configs (Pipe).Mode.V_Visible);
Nico Huber83693c82016-10-08 22:17:55 +02001044 Debug.Put_Line (",");
1045 Debug.Put (" V_Sync_Begin => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001046 Debug.Put_Int32 (Configs (Pipe).Mode.V_Sync_Begin);
Nico Huber83693c82016-10-08 22:17:55 +02001047 Debug.Put_Line (",");
1048 Debug.Put (" V_Sync_End => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001049 Debug.Put_Int32 (Configs (Pipe).Mode.V_Sync_End);
Nico Huber83693c82016-10-08 22:17:55 +02001050 Debug.Put_Line (",");
1051 Debug.Put (" V_Total => ");
Nico Huberc5c767a2018-06-03 01:09:04 +02001052 Debug.Put_Int32 (Configs (Pipe).Mode.V_Total);
Nico Huber83693c82016-10-08 22:17:55 +02001053 Debug.Put_Line (",");
1054 Debug.Put_Line (" H_Sync_Active_High => " &
1055 (if Configs (Pipe).Mode.H_Sync_Active_High
1056 then "True,"
1057 else "False,"));
1058 Debug.Put_Line (" V_Sync_Active_High => " &
1059 (if Configs (Pipe).Mode.V_Sync_Active_High
1060 then "True,"
1061 else "False,"));
1062 Debug.Put (" BPC => ");
1063 Debug.Put_Int64 (Configs (Pipe).Mode.BPC);
Nico Huber99f10f32016-11-20 00:34:05 +01001064 if Pipe /= Pipe_Index'Last then
Nico Huber83693c82016-10-08 22:17:55 +02001065 Debug.Put_Line (")),");
1066 else
1067 Debug.Put_Line (")));");
1068 end if;
1069 end loop;
1070 end Dump_Configs;
1071
Nico Huberc5c66ec2019-09-28 23:59:45 +02001072 ----------------------------------------------------------------------------
1073
1074 procedure PCI_Read16 (Value : out Word16; Offset : HW.PCI.Index) is
1075 begin
1076 Dev.Read16 (Value, Offset);
1077 end PCI_Read16;
1078
Nico Huber83693c82016-10-08 22:17:55 +02001079end HW.GFX.GMA;