blob: 7e9a959ecd7282c052efe1fcdef55e713604cbab [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
Nico Huber3d06de82018-05-29 01:35:04 +02002-- Copyright (C) 2014-2018 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 Huber5374c3a2017-07-15 21:48:06 +020021with HW.GFX.Framebuffer_Filler;
22
Nico Huber83693c82016-10-08 22:17:55 +020023with HW.GFX.GMA.Config;
Nico Huber8c45bcf2016-11-20 17:30:57 +010024with HW.GFX.GMA.Config_Helpers;
Nico Huber83693c82016-10-08 22:17:55 +020025with HW.GFX.GMA.Registers;
26with HW.GFX.GMA.Power_And_Clocks;
27with HW.GFX.GMA.Panel;
28with HW.GFX.GMA.PLLs;
29with HW.GFX.GMA.Port_Detect;
30with HW.GFX.GMA.Connectors;
31with HW.GFX.GMA.Connector_Info;
32with HW.GFX.GMA.Pipe_Setup;
33
Nico Huber83693c82016-10-08 22:17:55 +020034with HW.Debug;
35with GNAT.Source_Info;
36
Nico Huber83693c82016-10-08 22:17:55 +020037use type HW.Int32;
38
39package body HW.GFX.GMA
40 with Refined_State =>
41 (State =>
Nico Huber2b6f6992017-07-09 18:11:34 +020042 (Dev.Address_State,
43 Registers.Address_State,
Nico Huber83693c82016-10-08 22:17:55 +020044 PLLs.State, Panel.Panel_State,
Nico Huber1a712d32017-01-09 15:11:04 +010045 Cur_Configs, Allocated_PLLs,
Nico Huberc3f66f62017-07-16 21:39:54 +020046 HPD_Delay, Wait_For_HPD,
47 Linear_FB_Base),
Nico Huber83693c82016-10-08 22:17:55 +020048 Init_State => Initialized,
Arthur Heymansd1988d12018-03-28 16:27:57 +020049 Config_State => (Config.Valid_Port_GPU, Config.Raw_Clock),
Nico Huber83693c82016-10-08 22:17:55 +020050 Device_State =>
Nico Huber2b6f6992017-07-09 18:11:34 +020051 (Dev.PCI_State, Registers.Register_State, Registers.GTT_State))
Nico Huber83693c82016-10-08 22:17:55 +020052is
Nico Huber2b6f6992017-07-09 18:11:34 +020053 pragma Disable_Atomic_Synchronization;
Nico Huber83693c82016-10-08 22:17:55 +020054
55 subtype Port_Name is String (1 .. 8);
56 type Port_Name_Array is array (Port_Type) of Port_Name;
57 Port_Names : constant Port_Name_Array :=
58 (Disabled => "Disabled",
59 Internal => "Internal",
60 DP1 => "DP1 ",
61 DP2 => "DP2 ",
62 DP3 => "DP3 ",
Nico Huber0d454cd2016-11-21 13:33:43 +010063 HDMI1 => "HDMI1 ",
64 HDMI2 => "HDMI2 ",
65 HDMI3 => "HDMI3 ",
Nico Huber83693c82016-10-08 22:17:55 +020066 Analog => "Analog ");
67
Nico Huber2b6f6992017-07-09 18:11:34 +020068 package Dev is new HW.PCI.Dev (PCI.Address'(0, 2, 0));
69
Nico Huber83693c82016-10-08 22:17:55 +020070 package Display_Controller renames Pipe_Setup;
71
Nico Huber99f10f32016-11-20 00:34:05 +010072 type PLLs_Type is array (Pipe_Index) of PLLs.T;
Nico Huber83693c82016-10-08 22:17:55 +020073
Nico Huber83693c82016-10-08 22:17:55 +020074 type HPD_Type is array (Port_Type) of Boolean;
Nico Huber3be61d42017-01-09 13:58:18 +010075 type HPD_Delay_Type is array (Active_Port_Type) of Time.T;
Nico Huber83693c82016-10-08 22:17:55 +020076
Nico Huber83693c82016-10-08 22:17:55 +020077 Allocated_PLLs : PLLs_Type;
Nico Huber83693c82016-10-08 22:17:55 +020078 HPD_Delay : HPD_Delay_Type;
79 Wait_For_HPD : HPD_Type;
80 Initialized : Boolean := False;
81
Nico Huberc3f66f62017-07-16 21:39:54 +020082 Linear_FB_Base : Word64;
83
Nico Huber83693c82016-10-08 22:17:55 +020084 ----------------------------------------------------------------------------
85
Nico Huberf54d0962016-10-20 14:17:18 +020086 PCH_RAWCLK_FREQ_MASK : constant := 16#3ff# * 2 ** 0;
87
88 function PCH_RAWCLK_FREQ (Freq : Frequency_Type) return Word32
89 is
90 begin
91 return Word32 (Freq / 1_000_000);
92 end PCH_RAWCLK_FREQ;
93
94 ----------------------------------------------------------------------------
95
Nico Huber43370ba2017-01-09 15:26:19 +010096 procedure Enable_Output
97 (Pipe : in Pipe_Index;
98 Pipe_Cfg : in Pipe_Config;
99 Success : out Boolean)
100 is
101 Port_Cfg : Port_Config;
102 begin
Nico Huber3be61d42017-01-09 13:58:18 +0100103 pragma Debug (Debug.New_Line);
104 pragma Debug (Debug.Put_Line
105 ("Trying to enable port " & Port_Names (Pipe_Cfg.Port)));
106
Nico Huber43370ba2017-01-09 15:26:19 +0100107 Config_Helpers.Fill_Port_Config
108 (Port_Cfg, Pipe, Pipe_Cfg.Port, Pipe_Cfg.Mode, Success);
109
110 if Success then
111 Success := Config_Helpers.Validate_Config
Nico Hubercbbaade2018-01-02 13:59:36 +0100112 (Pipe_Cfg.Framebuffer, Port_Cfg.Mode, Pipe);
Nico Huber43370ba2017-01-09 15:26:19 +0100113 end if;
114
Nico Huber43370ba2017-01-09 15:26:19 +0100115 if Success then
Nico Huber43370ba2017-01-09 15:26:19 +0100116 Connector_Info.Preferred_Link_Setting (Port_Cfg, Success);
117 end if;
118
119 -- loop over all possible DP-lane configurations
120 -- (non-DP ports use a single fake configuration)
121 while Success loop
122 pragma Loop_Invariant
123 (Pipe_Cfg.Port in Active_Port_Type and
124 Port_Cfg.Mode = Port_Cfg.Mode'Loop_Entry);
125
126 PLLs.Alloc
127 (Port_Cfg => Port_Cfg,
128 PLL => Allocated_PLLs (Pipe),
129 Success => Success);
130
131 if Success then
132 -- try each DP-lane configuration twice
133 for Try in 1 .. 2 loop
134 pragma Loop_Invariant
135 (Pipe_Cfg.Port in Active_Port_Type);
136
Nico Huber4798c662017-01-11 12:44:48 +0100137 -- Clear pending hot-plug events before every try
138 Port_Detect.Clear_Hotplug_Detect (Pipe_Cfg.Port);
139
Nico Huber43370ba2017-01-09 15:26:19 +0100140 Connectors.Pre_On
141 (Pipe => Pipe,
142 Port_Cfg => Port_Cfg,
143 PLL_Hint => PLLs.Register_Value (Allocated_PLLs (Pipe)),
144 Success => Success);
145
146 if Success then
147 Display_Controller.On
148 (Pipe => Pipe,
149 Port_Cfg => Port_Cfg,
Nico Huber4dc4c612018-01-10 15:55:09 +0100150 Framebuffer => Pipe_Cfg.Framebuffer,
151 Cursor => Pipe_Cfg.Cursor);
Nico Huber43370ba2017-01-09 15:26:19 +0100152
153 Connectors.Post_On
Arthur Heymans60d0e5f2018-03-28 17:08:27 +0200154 (Pipe => Pipe,
155 Port_Cfg => Port_Cfg,
Nico Huber43370ba2017-01-09 15:26:19 +0100156 PLL_Hint => PLLs.Register_Value (Allocated_PLLs (Pipe)),
157 Success => Success);
158
159 if not Success then
160 Display_Controller.Off (Pipe);
161 Connectors.Post_Off (Port_Cfg);
162 end if;
163 end if;
164
165 exit when Success;
166 end loop;
167 exit when Success; -- connection established => stop loop
168
169 -- connection failed
170 PLLs.Free (Allocated_PLLs (Pipe));
171 end if;
172
173 Connector_Info.Next_Link_Setting (Port_Cfg, Success);
174 end loop;
175
176 if Success then
177 pragma Debug (Debug.Put_Line
178 ("Enabled port " & Port_Names (Pipe_Cfg.Port)));
179 else
180 Wait_For_HPD (Pipe_Cfg.Port) := True;
181 if Pipe_Cfg.Port = Internal then
182 Panel.Off;
183 end if;
184 end if;
185 end Enable_Output;
186
Nico Huber3be61d42017-01-09 13:58:18 +0100187 procedure Disable_Output (Pipe : Pipe_Index; Pipe_Cfg : Pipe_Config)
188 is
189 Port_Cfg : Port_Config;
190 Success : Boolean;
191 begin
192 Config_Helpers.Fill_Port_Config
193 (Port_Cfg, Pipe, Pipe_Cfg.Port, Pipe_Cfg.Mode, Success);
194 if Success then
195 pragma Debug (Debug.New_Line);
196 pragma Debug (Debug.Put_Line
197 ("Disabling port " & Port_Names (Pipe_Cfg.Port)));
198 pragma Debug (Debug.New_Line);
199
200 Connectors.Pre_Off (Port_Cfg);
201 Display_Controller.Off (Pipe);
202 Connectors.Post_Off (Port_Cfg);
203
204 PLLs.Free (Allocated_PLLs (Pipe));
205 end if;
206 end Disable_Output;
207
Nico Huber99f10f32016-11-20 00:34:05 +0100208 procedure Update_Outputs (Configs : Pipe_Configs)
Nico Huber83693c82016-10-08 22:17:55 +0200209 is
Nico Huber3be61d42017-01-09 13:58:18 +0100210 procedure Check_HPD (Port : in Active_Port_Type; Detected : out Boolean)
211 is
212 HPD_Delay_Over : constant Boolean := Time.Timed_Out (HPD_Delay (Port));
213 begin
214 if HPD_Delay_Over then
215 Port_Detect.Hotplug_Detect (Port, Detected);
216 HPD_Delay (Port) := Time.MS_From_Now (333);
217 else
218 Detected := False;
219 end if;
220 end Check_HPD;
Nico Huberb56b9c52017-01-11 15:12:23 +0100221
Nico Huber564103f2017-01-11 15:33:07 +0100222 Power_Changed : Boolean := False;
Nico Huberb56b9c52017-01-11 15:12:23 +0100223 Old_Configs : Pipe_Configs;
Nico Huber564103f2017-01-11 15:33:07 +0100224
225 -- Only called when we actually tried to change something
226 -- so we don't congest the log with unnecessary messages.
227 procedure Update_Power
228 is
229 begin
230 if not Power_Changed then
231 Power_And_Clocks.Power_Up (Old_Configs, Configs);
232 Power_Changed := True;
233 end if;
234 end Update_Power;
Nico Huber3d06de82018-05-29 01:35:04 +0200235
236 function Full_Update (Cur_Config, New_Config : Pipe_Config) return Boolean
237 is
238 begin
239 return
Nico Huber958c5642018-06-02 16:59:31 +0200240 Cur_Config.Port /= New_Config.Port
241 or else
242 Cur_Config.Mode /= New_Config.Mode
243 or else
Nico Huber3d06de82018-05-29 01:35:04 +0200244 (Config.Use_PDW_For_EDP_Scaling and then
245 (Cur_Config.Port = Internal and
Nico Huber958c5642018-06-02 16:59:31 +0200246 Requires_Scaling (Cur_Config) /= Requires_Scaling (New_Config)))
247 or else
248 (Config.Has_GMCH_PFIT_CONTROL and then
249 (Requires_Scaling (Cur_Config) /= Requires_Scaling (New_Config) or
250 Scaling_Type (Cur_Config) /= Scaling_Type (New_Config)));
Nico Huber3d06de82018-05-29 01:35:04 +0200251 end Full_Update;
Nico Huber83693c82016-10-08 22:17:55 +0200252 begin
253 Old_Configs := Cur_Configs;
254
Nico Huberb56b9c52017-01-11 15:12:23 +0100255 -- disable all pipes that changed or had a hot-plug event
256 for Pipe in Pipe_Index loop
257 declare
258 Unplug_Detected : Boolean;
259 Cur_Config : Pipe_Config renames Cur_Configs (Pipe);
260 New_Config : Pipe_Config renames Configs (Pipe);
261 begin
262 if Cur_Config.Port /= Disabled then
263 Check_HPD (Cur_Config.Port, Unplug_Detected);
Nico Huber83693c82016-10-08 22:17:55 +0200264
Nico Huber3d06de82018-05-29 01:35:04 +0200265 if Full_Update (Cur_Config, New_Config) or Unplug_Detected then
Nico Huberb56b9c52017-01-11 15:12:23 +0100266 Disable_Output (Pipe, Cur_Config);
267 Cur_Config.Port := Disabled;
Nico Huber564103f2017-01-11 15:33:07 +0100268 Update_Power;
Nico Huberb56b9c52017-01-11 15:12:23 +0100269 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200270 end if;
Nico Huberb56b9c52017-01-11 15:12:23 +0100271 end;
272 end loop;
Nico Huber83693c82016-10-08 22:17:55 +0200273
Nico Huberb56b9c52017-01-11 15:12:23 +0100274 -- enable all pipes that changed and should be active
275 for Pipe in Pipe_Index loop
276 declare
277 Success : Boolean;
278 Cur_Config : Pipe_Config renames Cur_Configs (Pipe);
279 New_Config : Pipe_Config renames Configs (Pipe);
280 begin
Nico Huber3d06de82018-05-29 01:35:04 +0200281 if New_Config.Port /= Disabled and
282 Full_Update (Cur_Config, New_Config)
Nico Huberb56b9c52017-01-11 15:12:23 +0100283 then
Nico Huber3be61d42017-01-09 13:58:18 +0100284 if Wait_For_HPD (New_Config.Port) then
285 Check_HPD (New_Config.Port, Success);
286 Wait_For_HPD (New_Config.Port) := not Success;
287 else
288 Success := True;
Nico Huber8c45bcf2016-11-20 17:30:57 +0100289 end if;
Nico Huberc7a4fee2016-11-03 18:18:03 +0100290
Nico Huber3be61d42017-01-09 13:58:18 +0100291 if Success then
Nico Huber564103f2017-01-11 15:33:07 +0100292 Update_Power;
Nico Huberb56b9c52017-01-11 15:12:23 +0100293 Enable_Output (Pipe, New_Config, Success);
Nico Huber3be61d42017-01-09 13:58:18 +0100294 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200295
296 if Success then
Nico Huberb56b9c52017-01-11 15:12:23 +0100297 Cur_Config := New_Config;
Nico Huber83693c82016-10-08 22:17:55 +0200298 end if;
Nico Huber3be61d42017-01-09 13:58:18 +0100299
Nico Huberb56b9c52017-01-11 15:12:23 +0100300 -- update framebuffer offset only
301 elsif New_Config.Port /= Disabled and
Nico Huberf7f537e2018-01-02 14:15:43 +0100302 Cur_Config.Framebuffer /= New_Config.Framebuffer and
303 Config_Helpers.Validate_Config
304 (New_Config.Framebuffer, New_Config.Mode, Pipe)
Nico Huberb56b9c52017-01-11 15:12:23 +0100305 then
Nico Huberf7f537e2018-01-02 14:15:43 +0100306 Display_Controller.Setup_FB
307 (Pipe, New_Config.Mode, New_Config.Framebuffer);
Nico Huber15ffc4f2018-01-11 14:44:43 +0100308 Display_Controller.Update_Cursor
309 (Pipe, New_Config.Framebuffer, New_Config.Cursor);
Nico Huberb56b9c52017-01-11 15:12:23 +0100310 Cur_Config := New_Config;
311 end if;
312 end;
Nico Huber83693c82016-10-08 22:17:55 +0200313 end loop;
314
Nico Huber564103f2017-01-11 15:33:07 +0100315 if Power_Changed then
Nico Huber83693c82016-10-08 22:17:55 +0200316 Power_And_Clocks.Power_Down (Old_Configs, Configs, Cur_Configs);
317 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200318 end Update_Outputs;
319
320 ----------------------------------------------------------------------------
321
Nico Huber15ffc4f2018-01-11 14:44:43 +0100322 procedure Update_Cursor (Pipe : Pipe_Index; Cursor : Cursor_Type)
323 is
324 begin
325 Cur_Configs (Pipe).Cursor := Cursor;
326 Display_Controller.Update_Cursor
327 (Pipe, Cur_Configs (Pipe).Framebuffer, Cur_Configs (Pipe).Cursor);
328 end Update_Cursor;
329
330 procedure Place_Cursor
331 (Pipe : Pipe_Index;
332 X : Cursor_Pos;
333 Y : Cursor_Pos)
334 is
335 begin
336 Cur_Configs (Pipe).Cursor.Center_X := X;
337 Cur_Configs (Pipe).Cursor.Center_Y := Y;
338 Display_Controller.Place_Cursor
339 (Pipe, Cur_Configs (Pipe).Framebuffer, Cur_Configs (Pipe).Cursor);
340 end Place_Cursor;
341
342 procedure Move_Cursor
343 (Pipe : Pipe_Index;
344 X : Cursor_Pos;
345 Y : Cursor_Pos)
346 is
347 function Cap_Add (A, B : Cursor_Pos) return Cursor_Pos is
348 (if A + B < 0
349 then Int32'Max (Cursor_Pos'First, A + B)
350 else Int32'Min (Cursor_Pos'Last, A + B));
351 begin
352 Place_Cursor
353 (Pipe => Pipe,
354 X => Cap_Add (Cur_Configs (Pipe).Cursor.Center_X, X),
355 Y => Cap_Add (Cur_Configs (Pipe).Cursor.Center_Y, Y));
356 end Move_Cursor;
357
358 ----------------------------------------------------------------------------
359
Nico Huber83693c82016-10-08 22:17:55 +0200360 procedure Initialize
Nico Huber2b6f6992017-07-09 18:11:34 +0200361 (Write_Delay : in Word64 := 0;
Nico Huber793a8d42016-11-21 18:57:03 +0100362 Clean_State : in Boolean := False;
Nico Huber83693c82016-10-08 22:17:55 +0200363 Success : out Boolean)
364 with
365 Refined_Global =>
366 (In_Out =>
Nico Hubere015e822017-08-25 20:12:09 +0200367 (Config.Valid_Port_GPU, Dev.PCI_State,
Arthur Heymansd1988d12018-03-28 16:27:57 +0200368 Registers.Register_State, Port_IO.State,
369 Config.Raw_Clock),
Nico Huber83693c82016-10-08 22:17:55 +0200370 Input =>
371 (Time.State),
372 Output =>
Nico Huber2b6f6992017-07-09 18:11:34 +0200373 (Dev.Address_State,
374 Registers.Address_State,
Nico Huber83693c82016-10-08 22:17:55 +0200375 PLLs.State, Panel.Panel_State,
Nico Huber1a712d32017-01-09 15:11:04 +0100376 Cur_Configs, Allocated_PLLs,
Nico Huberc3f66f62017-07-16 21:39:54 +0200377 HPD_Delay, Wait_For_HPD,
378 Linear_FB_Base, Initialized))
Nico Huber83693c82016-10-08 22:17:55 +0200379 is
380 use type HW.Word64;
381
Nico Huber2b6f6992017-07-09 18:11:34 +0200382 PCI_MMIO_Base, PCI_GTT_Base : Word64;
383
Nico Huber83693c82016-10-08 22:17:55 +0200384 Now : constant Time.T := Time.Now;
385
386 procedure Check_Platform (Success : out Boolean)
387 is
388 Audio_VID_DID : Word32;
389 begin
390 case Config.CPU is
Arthur Heymans73ea0322018-03-28 17:17:07 +0200391 when G45 =>
392 Registers.Read (Registers.G4X_AUD_VID_DID, Audio_VID_DID);
Nico Huber83693c82016-10-08 22:17:55 +0200393 when Haswell .. Skylake =>
394 Registers.Read (Registers.AUD_VID_DID, Audio_VID_DID);
395 when Ironlake .. Ivybridge =>
396 Registers.Read (Registers.PCH_AUD_VID_DID, Audio_VID_DID);
397 end case;
398 Success :=
399 (case Config.CPU is
Nico Huber21da5742017-01-20 14:00:53 +0100400 when Broxton => Audio_VID_DID = 16#8086_280a#,
Nico Huber83693c82016-10-08 22:17:55 +0200401 when Skylake => Audio_VID_DID = 16#8086_2809#,
402 when Broadwell => Audio_VID_DID = 16#8086_2808#,
403 when Haswell => Audio_VID_DID = 16#8086_2807#,
404 when Ivybridge |
405 Sandybridge => Audio_VID_DID = 16#8086_2806# or
406 Audio_VID_DID = 16#8086_2805#,
Arthur Heymans73ea0322018-03-28 17:17:07 +0200407 when Ironlake => Audio_VID_DID = 16#0000_0000#,
408 when G45 => Audio_VID_DID = 16#8086_2801# or
409 Audio_VID_DID = 16#8086_2802# or
410 Audio_VID_DID = 16#8086_2803#);
Nico Huber83693c82016-10-08 22:17:55 +0200411 end Check_Platform;
Nico Hubere7ac6eb2017-09-04 23:54:13 +0200412
413 procedure Check_Platform_PCI (Success : out Boolean)
414 is
415 use type HW.Word16;
416 Vendor, Device : Word16;
417 begin
418 Dev.Read16 (Vendor, PCI.Vendor_Id);
419 Dev.Read16 (Device, PCI.Device_Id);
420
421 Success := Vendor = 16#8086# and Config.Compatible_GPU (Device);
422 end Check_Platform_PCI;
Nico Huber83693c82016-10-08 22:17:55 +0200423 begin
Nico Huber83693c82016-10-08 22:17:55 +0200424 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
425
426 pragma Debug (Debug.Set_Register_Write_Delay (Write_Delay));
427
Nico Huberc3f66f62017-07-16 21:39:54 +0200428 Linear_FB_Base := 0;
Nico Huber83693c82016-10-08 22:17:55 +0200429 Wait_For_HPD := HPD_Type'(others => False);
430 HPD_Delay := HPD_Delay_Type'(others => Now);
Nico Huber83693c82016-10-08 22:17:55 +0200431 Allocated_PLLs := (others => PLLs.Invalid);
Nico Huber99f10f32016-11-20 00:34:05 +0100432 Cur_Configs := Pipe_Configs'
433 (others => Pipe_Config'
Nico Huber83693c82016-10-08 22:17:55 +0200434 (Port => Disabled,
435 Framebuffer => HW.GFX.Default_FB,
Nico Hubera02b2c62018-01-09 15:58:34 +0100436 Cursor => Default_Cursor,
Nico Huber83693c82016-10-08 22:17:55 +0200437 Mode => HW.GFX.Invalid_Mode));
Nico Huber83693c82016-10-08 22:17:55 +0200438 PLLs.Initialize;
439
Nico Huber2b6f6992017-07-09 18:11:34 +0200440 Dev.Initialize (Success);
441
442 if Success then
443 Dev.Map (PCI_MMIO_Base, PCI.Res0, Length => Config.GTT_Offset);
444 Dev.Map (PCI_GTT_Base, PCI.Res0, Offset => Config.GTT_Offset);
445 if PCI_MMIO_Base /= 0 and PCI_GTT_Base /= 0 then
446 Registers.Set_Register_Base (PCI_MMIO_Base, PCI_GTT_Base);
447 else
448 pragma Debug (Debug.Put_Line
449 ("ERROR: Couldn't map resoure0."));
450 Registers.Set_Register_Base (Config.Default_MMIO_Base);
451 Success := Config.Default_MMIO_Base_Set;
452 end if;
Nico Hubere7ac6eb2017-09-04 23:54:13 +0200453
454 if Success then
455 Check_Platform_PCI (Success);
456 end if;
Nico Huber2b6f6992017-07-09 18:11:34 +0200457 else
458 pragma Debug (Debug.Put_Line
459 ("WARNING: Couldn't initialize PCI dev."));
460 Registers.Set_Register_Base (Config.Default_MMIO_Base);
461 Success := Config.Default_MMIO_Base_Set;
Nico Huber2b6f6992017-07-09 18:11:34 +0200462
Nico Hubere7ac6eb2017-09-04 23:54:13 +0200463 if Success then
464 Check_Platform (Success);
465 end if;
Nico Huber2b6f6992017-07-09 18:11:34 +0200466 end if;
467
Nico Huber83693c82016-10-08 22:17:55 +0200468 if not Success then
469 pragma Debug (Debug.Put_Line ("ERROR: Incompatible CPU or PCH."));
470
471 Panel.Static_Init; -- for flow analysis
472
473 Initialized := False;
474 return;
475 end if;
476
477 Panel.Setup_PP_Sequencer;
478 Port_Detect.Initialize;
Nico Huber0923b792017-06-09 15:28:41 +0200479 Connectors.Initialize;
Nico Huber83693c82016-10-08 22:17:55 +0200480
Nico Huber793a8d42016-11-21 18:57:03 +0100481 if Clean_State then
482 Power_And_Clocks.Pre_All_Off;
483 Connectors.Pre_All_Off;
484 Display_Controller.All_Off;
485 Connectors.Post_All_Off;
486 PLLs.All_Off;
487 Power_And_Clocks.Post_All_Off;
Nico Huber17d64b62017-07-15 20:51:25 +0200488 Registers.Clear_Fences;
Nico Huber33912aa2016-12-06 20:36:23 +0100489 else
490 -- According to PRMs, VGA plane is the only thing
Nico Huber3a0e2a02017-07-19 14:41:46 +0200491 -- that's enabled by default after reset...
Nico Huber33912aa2016-12-06 20:36:23 +0100492 Display_Controller.Legacy_VGA_Off;
Nico Huber3a0e2a02017-07-19 14:41:46 +0200493 -- ... along with some DDI port bits since Skylake.
494 Connectors.Post_Reset_Off;
Nico Huber793a8d42016-11-21 18:57:03 +0100495 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200496
497 -------------------- Now restart from a clean state ---------------------
498 Power_And_Clocks.Initialize;
499
Nico Huber1c3b9282017-02-09 13:57:04 +0100500 if Config.Has_PCH then
501 Registers.Unset_And_Set_Mask
502 (Register => Registers.PCH_RAWCLK_FREQ,
503 Mask_Unset => PCH_RAWCLK_FREQ_MASK,
504 Mask_Set => PCH_RAWCLK_FREQ (Config.Default_RawClk_Freq));
505 end if;
Nico Huberf54d0962016-10-20 14:17:18 +0200506
Nico Huber83693c82016-10-08 22:17:55 +0200507 Initialized := True;
508
509 end Initialize;
510
511 function Is_Initialized return Boolean
512 with
513 Refined_Post => Is_Initialized'Result = Initialized
514 is
515 begin
516 return Initialized;
517 end Is_Initialized;
518
519 ----------------------------------------------------------------------------
520
Nico Huber42fb2d02017-09-01 17:01:51 +0200521 procedure Power_Up_VGA
522 is
523 Fake_Config : constant Pipe_Configs :=
524 (Primary =>
525 (Port => Analog,
526 Framebuffer => HW.GFX.Default_FB,
Nico Hubera02b2c62018-01-09 15:58:34 +0100527 Cursor => Default_Cursor,
Nico Huber42fb2d02017-09-01 17:01:51 +0200528 Mode => HW.GFX.Invalid_Mode),
529 others =>
530 (Port => Disabled,
531 Framebuffer => HW.GFX.Default_FB,
Nico Hubera02b2c62018-01-09 15:58:34 +0100532 Cursor => Default_Cursor,
Nico Huber42fb2d02017-09-01 17:01:51 +0200533 Mode => HW.GFX.Invalid_Mode));
534 begin
535 Power_And_Clocks.Power_Up (Cur_Configs, Fake_Config);
536 end Power_Up_VGA;
537
538 ----------------------------------------------------------------------------
539
Nico Huber5374c3a2017-07-15 21:48:06 +0200540 function FB_First_Page (FB : Framebuffer_Type) return Natural is
Nico Huber34be6542017-12-13 09:26:24 +0100541 (Natural (Phys_Offset (FB) / GTT_Page_Size));
Nico Huber5374c3a2017-07-15 21:48:06 +0200542 function FB_Pages (FB : Framebuffer_Type) return Natural is
543 (Natural (Div_Round_Up (FB_Size (FB), GTT_Page_Size)));
544 function FB_Last_Page (FB : Framebuffer_Type) return Natural is
545 (FB_First_Page (FB) + FB_Pages (FB) - 1);
546
Nico Huber34be6542017-12-13 09:26:24 +0100547 -- Check basics and that it fits in GTT. For 90 degree rotations,
548 -- the Offset should be above GTT_Rotation_Offset. The latter will
549 -- be subtracted for the aperture mapping.
Nico Huber5374c3a2017-07-15 21:48:06 +0200550 function Valid_FB (FB : Framebuffer_Type) return Boolean is
Nico Huber34be6542017-12-13 09:26:24 +0100551 (Valid_Stride (FB) and
552 FB_First_Page (FB) in GTT_Range and
553 FB_Last_Page (FB) in GTT_Range and
554 (not Rotation_90 (FB) or
555 (FB_Last_Page (FB) + GTT_Rotation_Offset in GTT_Range and
556 FB.Offset >= Word32 (GTT_Rotation_Offset) * GTT_Page_Size)));
Nico Huber5374c3a2017-07-15 21:48:06 +0200557
558 -- Also check that we don't overflow the GTT's 39-bit space
559 -- (always true with a 32-bit base)
560 function Valid_Phys_FB (FB : Framebuffer_Type; Phys_Base : Word32)
561 return Boolean is
562 (Valid_FB (FB) and
Nico Huber34be6542017-12-13 09:26:24 +0100563 Int64 (Phys_Base) + Int64 (Phys_Offset (FB)) + Int64 (FB_Size (FB)) <=
Nico Huber5374c3a2017-07-15 21:48:06 +0200564 Int64 (GTT_Address_Type'Last))
565 with
566 Ghost;
567
Nico Huber83693c82016-10-08 22:17:55 +0200568 procedure Write_GTT
569 (GTT_Page : GTT_Range;
570 Device_Address : GTT_Address_Type;
Nico Huber5374c3a2017-07-15 21:48:06 +0200571 Valid : Boolean)
572 is
Nico Huber83693c82016-10-08 22:17:55 +0200573 begin
574 Registers.Write_GTT (GTT_Page, Device_Address, Valid);
575 end Write_GTT;
576
Nico Huber194e57e2017-07-15 21:15:46 +0200577 procedure Setup_Default_GTT (FB : Framebuffer_Type; Phys_Base : Word32)
Nico Huber5374c3a2017-07-15 21:48:06 +0200578 with
579 Pre => Is_Initialized and Valid_Phys_FB (FB, Phys_Base)
Nico Huber83693c82016-10-08 22:17:55 +0200580 is
Nico Huber194e57e2017-07-15 21:15:46 +0200581 Phys_Addr : GTT_Address_Type :=
Nico Huber34be6542017-12-13 09:26:24 +0100582 GTT_Address_Type (Phys_Base) + GTT_Address_Type (Phys_Offset (FB));
Nico Huber83693c82016-10-08 22:17:55 +0200583 begin
Nico Huber194e57e2017-07-15 21:15:46 +0200584 for Idx in FB_First_Page (FB) .. FB_Last_Page (FB) loop
Nico Huber83693c82016-10-08 22:17:55 +0200585 Registers.Write_GTT
586 (GTT_Page => Idx,
587 Device_Address => Phys_Addr,
588 Valid => True);
Nico Huber194e57e2017-07-15 21:15:46 +0200589 Phys_Addr := Phys_Addr + GTT_Page_Size;
Nico Huber83693c82016-10-08 22:17:55 +0200590 end loop;
Nico Huber9b479412017-08-27 11:55:56 +0200591
592 if Rotation_90 (FB) and FB.Tiling = Y_Tiled and FB.V_Stride >= 32 then
593 declare
594 V_Pages : constant Natural := Natural (FB.V_Stride) / 32;
595 Bytes_Per_Row : constant GTT_Address_Type :=
596 GTT_Address_Type (Pixel_To_Bytes (32 * FB.Stride, FB));
597 begin
598 Phys_Addr := GTT_Address_Type (Phys_Base) +
Nico Huber34be6542017-12-13 09:26:24 +0100599 GTT_Address_Type (Phys_Offset (FB)) +
Nico Huber9b479412017-08-27 11:55:56 +0200600 GTT_Address_Type (FB_Size (FB));
601 for Page in FB_First_Page (FB) .. FB_Last_Page (FB) loop
602 Phys_Addr := Phys_Addr - Bytes_Per_Row;
603 Registers.Write_GTT
604 (GTT_Page => GTT_Rotation_Offset + Page,
605 Device_Address => Phys_Addr,
606 Valid => True);
607
608 if (Page - FB_First_Page (FB) + 1) mod V_Pages = 0 then
609 Phys_Addr := Phys_Addr + GTT_Page_Size +
610 GTT_Address_Type (V_Pages) * Bytes_Per_Row;
611 end if;
612 end loop;
613 end;
614 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200615 end Setup_Default_GTT;
616
617 ----------------------------------------------------------------------------
618
Nico Hubereedde882017-07-16 02:54:39 +0200619 use type HW.Word16;
620 subtype Stolen_Size_Range is Int64 range 0 .. 2 ** 33;
621
622 function GGMS_Gen4 (GGC : Word16) return Natural is
623 (Natural (Shift_Right (GGC, 8) and 16#07#));
624 function GTT_Size_Gen4 (GGC : Word16) return Natural is
625 (if GGMS_Gen4 (GGC) in 1 .. 3 then
626 (GGMS_Gen4 (GGC) + 1) * 2 ** 19 else 0);
627
628 function GMS_Gen4 (GGC : Word16) return Natural is
629 (Natural (Shift_Right (GGC, 4) and 16#0f#));
630 Valid_Stolen_Size_Gen4 : constant
631 array (Natural range 1 .. 13) of Stolen_Size_Range :=
632 (1, 4, 8, 16, 32, 48, 64, 128, 256, 96, 160, 224, 352);
633 function Stolen_Size_Gen4 (GGC : Word16) return Stolen_Size_Range is
634 (if GMS_Gen4 (GGC) in Valid_Stolen_Size_Gen4'Range then
Arthur Heymans5fd9a312017-09-12 12:45:18 +0200635 Valid_Stolen_Size_Gen4 (GMS_Gen4 (GGC)) * 2 ** 20 else 0);
Nico Hubereedde882017-07-16 02:54:39 +0200636
637 function GTT_Size_Gen6 (GGC : Word16) return Natural is
638 (Natural (Shift_Right (GGC, 8) and 16#03#) * 2 ** 20);
639
640 function Stolen_Size_Gen6 (GGC : Word16) return Stolen_Size_Range is
641 (Stolen_Size_Range (Shift_Right (GGC, 3) and 16#1f#) * 32 * 2 ** 20);
642
643 function GTT_Size_Gen8 (GGC : Word16) return Natural is
644 (Natural (Shift_Right (GGC, 6) and 16#03#) * 2 ** 20);
645
646 function GMS_Gen8 (GGC : Word16) return Stolen_Size_Range is
647 (Stolen_Size_Range (Shift_Right (GGC, 8) and 16#ff#));
648 function Stolen_Size_Gen8 (GGC : Word16) return Stolen_Size_Range is
649 (GMS_Gen8 (GGC) * 32 * 2 ** 20);
650
651 function Stolen_Size_Gen9 (GGC : Word16) return Stolen_Size_Range is
652 (if GMS_Gen8 (GGC) < 16#f0# then
653 Stolen_Size_Gen8 (GGC)
654 else
655 (GMS_Gen8 (GGC) - 16#f0# + 1) * 4 * 2 ** 20);
656
657 procedure Decode_Stolen
658 (GTT_Size : out Natural;
659 Stolen_Size : out Stolen_Size_Range)
660 with
661 Pre => Is_Initialized
662 is
663 GGC_Reg : constant :=
664 (case Config.CPU is
Arthur Heymans73ea0322018-03-28 17:17:07 +0200665 when G45 | Ironlake => 16#52#,
Nico Hubereedde882017-07-16 02:54:39 +0200666 when Sandybridge .. Skylake => 16#50#);
667 GGC : Word16;
668 begin
669 Dev.Read16 (GGC, GGC_Reg);
670 case Config.CPU is
Arthur Heymans73ea0322018-03-28 17:17:07 +0200671 when G45 | Ironlake =>
Nico Hubereedde882017-07-16 02:54:39 +0200672 GTT_Size := GTT_Size_Gen4 (GGC);
673 Stolen_Size := Stolen_Size_Gen4 (GGC);
674 when Sandybridge .. Haswell =>
675 GTT_Size := GTT_Size_Gen6 (GGC);
676 Stolen_Size := Stolen_Size_Gen6 (GGC);
677 when Broadwell =>
678 GTT_Size := GTT_Size_Gen8 (GGC);
679 Stolen_Size := Stolen_Size_Gen8 (GGC);
680 when Broxton .. Skylake =>
681 GTT_Size := GTT_Size_Gen8 (GGC);
682 Stolen_Size := Stolen_Size_Gen9 (GGC);
683 end case;
684 end Decode_Stolen;
685
686 -- Additional runtime validation that FB fits stolen memory and aperture.
687 procedure Validate_FB (FB : Framebuffer_Type; Valid : out Boolean)
688 with
689 Pre => Is_Initialized,
690 Post => (if Valid then Valid_FB (FB))
691 is
692 GTT_Size, Aperture_Size : Natural;
693 Stolen_Size : Stolen_Size_Range;
694 begin
695 Valid := Valid_FB (FB);
696
697 if Valid then
698 Decode_Stolen (GTT_Size, Stolen_Size);
699 Dev.Resource_Size (Aperture_Size, PCI.Res2);
700 Valid :=
701 FB_Last_Page (FB) < GTT_Size / Config.GTT_PTE_Size and
702 FB_Last_Page (FB) < Natural (Stolen_Size / GTT_Page_Size) and
703 FB_Last_Page (FB) < Aperture_Size / GTT_Page_Size;
Nico Huber34be6542017-12-13 09:26:24 +0100704 pragma Debug (not Valid, Debug.Put_Line
Nico Hubereedde882017-07-16 02:54:39 +0200705 ("Stolen memory too small to hold framebuffer."));
706 end if;
707 end Validate_FB;
708
Nico Huber5374c3a2017-07-15 21:48:06 +0200709 procedure Setup_Default_FB
710 (FB : in Framebuffer_Type;
711 Clear : in Boolean := True;
712 Success : out Boolean)
713 is
714 GMA_Phys_Base : constant PCI.Index := 16#5c#;
715 GMA_Phys_Base_Mask : constant := 16#fff0_0000#;
716
717 Phys_Base : Word32;
718 begin
Nico Hubereedde882017-07-16 02:54:39 +0200719 Validate_FB (FB, Success);
Nico Huber5374c3a2017-07-15 21:48:06 +0200720
721 if Success then
722 Dev.Read32 (Phys_Base, GMA_Phys_Base);
723 Phys_Base := Phys_Base and GMA_Phys_Base_Mask;
724 Success := Phys_Base /= GMA_Phys_Base_Mask and Phys_Base /= 0;
725 pragma Debug (not Success, Debug.Put_Line
726 ("Failed to read stolen memory base."));
Nico Huber0164b022017-08-24 15:12:51 +0200727
728 if Success then
729 if FB.Tiling in XY_Tiling then
730 Registers.Add_Fence
731 (First_Page => FB_First_Page (FB),
732 Last_Page => FB_Last_Page (FB),
733 Tiling => FB.Tiling,
734 Pitch => FB_Pitch (FB.Stride, FB),
735 Success => Success);
736 end if;
737 pragma Debug (not Success, Debug.Put_Line
738 ("Tiled framebuffer but no fence regs available."));
739 end if;
740
Nico Huber5374c3a2017-07-15 21:48:06 +0200741 if Success then
742 Setup_Default_GTT (FB, Phys_Base);
743 end if;
744 end if;
745
746 if Success and then Clear then
747 declare
748 use type HW.Word64;
749 Linear_FB : Word64;
750 begin
Nico Huberc3f66f62017-07-16 21:39:54 +0200751 Map_Linear_FB (Linear_FB, FB);
Nico Huber5374c3a2017-07-15 21:48:06 +0200752 if Linear_FB /= 0 then
Nico Huberc3f66f62017-07-16 21:39:54 +0200753 Framebuffer_Filler.Fill (Linear_FB, FB);
Nico Huber5374c3a2017-07-15 21:48:06 +0200754 end if;
Nico Huber5374c3a2017-07-15 21:48:06 +0200755 end;
756 end if;
757 end Setup_Default_FB;
758
Nico Huberc3f66f62017-07-16 21:39:54 +0200759 procedure Map_Linear_FB (Linear_FB : out Word64; FB : in Framebuffer_Type)
760 is
761 use type HW.Word64;
762
763 Valid : Boolean;
764 begin
765 Linear_FB := 0;
766
767 if Linear_FB_Base = 0 then
768 Dev.Map (Linear_FB_Base, PCI.Res2);
769 pragma Debug
770 (Linear_FB_Base = 0, Debug.Put_Line ("Failed to map resource2."));
771 end if;
772
773 if Linear_FB_Base /= 0 then
774 Validate_FB (FB, Valid);
775 if Valid then
Nico Huber34be6542017-12-13 09:26:24 +0100776 Linear_FB := Linear_FB_Base + Word64 (Phys_Offset (FB));
Nico Huberc3f66f62017-07-16 21:39:54 +0200777 end if;
778 end if;
779 end Map_Linear_FB;
780
Nico Huber5374c3a2017-07-15 21:48:06 +0200781 ----------------------------------------------------------------------------
782
Nico Huber99f10f32016-11-20 00:34:05 +0100783 procedure Dump_Configs (Configs : Pipe_Configs)
Nico Huber83693c82016-10-08 22:17:55 +0200784 is
785 subtype Pipe_Name is String (1 .. 9);
Nico Huber99f10f32016-11-20 00:34:05 +0100786 type Pipe_Name_Array is array (Pipe_Index) of Pipe_Name;
Nico Huber83693c82016-10-08 22:17:55 +0200787 Pipe_Names : constant Pipe_Name_Array :=
788 (Primary => "Primary ",
789 Secondary => "Secondary",
790 Tertiary => "Tertiary ");
Nico Huber5ef4d602017-12-13 13:56:47 +0100791
792 subtype Tiling_Name is String (1 .. 7);
793 type Tiling_Name_Array is array (Tiling_Type) of Tiling_Name;
794 Tilings : constant Tiling_Name_Array :=
795 (Linear => "Linear ",
796 X_Tiled => "X_Tiled",
797 Y_Tiled => "Y_Tiled");
798
799 subtype Rotation_Name is String (1 .. 11);
800 type Rotation_Name_Array is array (Rotation_Type) of Rotation_Name;
801 Rotations : constant Rotation_Name_Array :=
802 (No_Rotation => "No_Rotation",
803 Rotated_90 => "Rotated_90 ",
804 Rotated_180 => "Rotated_180",
805 Rotated_270 => "Rotated_270");
Nico Huber83693c82016-10-08 22:17:55 +0200806 begin
807 Debug.New_Line;
Paul Menzelb83107c2017-05-04 09:02:33 +0200808 Debug.Put_Line ("CONFIG =>");
Nico Huber99f10f32016-11-20 00:34:05 +0100809 for Pipe in Pipe_Index loop
810 if Pipe = Pipe_Index'First then
Nico Huber83693c82016-10-08 22:17:55 +0200811 Debug.Put (" (");
812 else
813 Debug.Put (" ");
814 end if;
815 Debug.Put_Line (Pipe_Names (Pipe) & " =>");
816 Debug.Put_Line
817 (" (Port => " & Port_Names (Configs (Pipe).Port) & ",");
818 Debug.Put_Line (" Framebuffer =>");
Nico Huber5ef4d602017-12-13 13:56:47 +0100819 Debug.Put (" (Width => ");
Nico Huber83693c82016-10-08 22:17:55 +0200820 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Width);
821 Debug.Put_Line (",");
Nico Huber5ef4d602017-12-13 13:56:47 +0100822 Debug.Put (" Height => ");
Nico Huber83693c82016-10-08 22:17:55 +0200823 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Height);
824 Debug.Put_Line (",");
Nico Huber5ef4d602017-12-13 13:56:47 +0100825 Debug.Put (" Start_X => ");
826 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Start_X);
827 Debug.Put_Line (",");
828 Debug.Put (" Start_Y => ");
829 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Start_Y);
830 Debug.Put_Line (",");
831 Debug.Put (" Stride => ");
Nico Huber83693c82016-10-08 22:17:55 +0200832 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Stride);
833 Debug.Put_Line (",");
Nico Huber5ef4d602017-12-13 13:56:47 +0100834 Debug.Put (" V_Stride => ");
835 Debug.Put_Int32 (Configs (Pipe).Framebuffer.V_Stride);
836 Debug.Put_Line (",");
837 Debug.Put (" Tiling => ");
838 Debug.Put_Line (Tilings (Configs (Pipe).Framebuffer.Tiling) & ",");
839 Debug.Put (" Rotation => ");
840 Debug.Put_Line (Rotations (Configs (Pipe).Framebuffer.Rotation) & ",");
Nico Huber83693c82016-10-08 22:17:55 +0200841 Debug.Put (" Offset => ");
842 Debug.Put_Word32 (Configs (Pipe).Framebuffer.Offset);
843 Debug.Put_Line (",");
844 Debug.Put (" BPC => ");
845 Debug.Put_Int64 (Configs (Pipe).Framebuffer.BPC);
846 Debug.Put_Line ("),");
847 Debug.Put_Line (" Mode =>");
848 Debug.Put (" (Dotclock => ");
849 Debug.Put_Int64 (Configs (Pipe).Mode.Dotclock);
850 Debug.Put_Line (",");
851 Debug.Put (" H_Visible => ");
852 Debug.Put_Int16 (Configs (Pipe).Mode.H_Visible);
853 Debug.Put_Line (",");
854 Debug.Put (" H_Sync_Begin => ");
855 Debug.Put_Int16 (Configs (Pipe).Mode.H_Sync_Begin);
856 Debug.Put_Line (",");
857 Debug.Put (" H_Sync_End => ");
858 Debug.Put_Int16 (Configs (Pipe).Mode.H_Sync_End);
859 Debug.Put_Line (",");
860 Debug.Put (" H_Total => ");
861 Debug.Put_Int16 (Configs (Pipe).Mode.H_Total);
862 Debug.Put_Line (",");
863 Debug.Put (" V_Visible => ");
864 Debug.Put_Int16 (Configs (Pipe).Mode.V_Visible);
865 Debug.Put_Line (",");
866 Debug.Put (" V_Sync_Begin => ");
867 Debug.Put_Int16 (Configs (Pipe).Mode.V_Sync_Begin);
868 Debug.Put_Line (",");
869 Debug.Put (" V_Sync_End => ");
870 Debug.Put_Int16 (Configs (Pipe).Mode.V_Sync_End);
871 Debug.Put_Line (",");
872 Debug.Put (" V_Total => ");
873 Debug.Put_Int16 (Configs (Pipe).Mode.V_Total);
874 Debug.Put_Line (",");
875 Debug.Put_Line (" H_Sync_Active_High => " &
876 (if Configs (Pipe).Mode.H_Sync_Active_High
877 then "True,"
878 else "False,"));
879 Debug.Put_Line (" V_Sync_Active_High => " &
880 (if Configs (Pipe).Mode.V_Sync_Active_High
881 then "True,"
882 else "False,"));
883 Debug.Put (" BPC => ");
884 Debug.Put_Int64 (Configs (Pipe).Mode.BPC);
Nico Huber99f10f32016-11-20 00:34:05 +0100885 if Pipe /= Pipe_Index'Last then
Nico Huber83693c82016-10-08 22:17:55 +0200886 Debug.Put_Line (")),");
887 else
888 Debug.Put_Line (")));");
889 end if;
890 end loop;
891 end Dump_Configs;
892
893end HW.GFX.GMA;