blob: fbb5d98b66a223c69283e17988a8e140fd108d9e [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
2-- Copyright (C) 2014-2016 secunet Security Networks AG
3--
4-- This program is free software; you can redistribute it and/or modify
5-- it under the terms of the GNU General Public License as published by
Nico Huber125a29e2016-10-18 00:23:54 +02006-- the Free Software Foundation; either version 2 of the License, or
7-- (at your option) any later version.
Nico Huber83693c82016-10-08 22:17:55 +02008--
9-- This program is distributed in the hope that it will be useful,
10-- but WITHOUT ANY WARRANTY; without even the implied warranty of
11-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12-- GNU General Public License for more details.
13--
14
15with HW.GFX.EDID;
16with HW.GFX.GMA.Config;
17with HW.GFX.GMA.DP_Info;
18with HW.GFX.GMA.Registers;
19with HW.GFX.GMA.Power_And_Clocks;
20with HW.GFX.GMA.Panel;
21with HW.GFX.GMA.PLLs;
22with HW.GFX.GMA.Port_Detect;
23with HW.GFX.GMA.Connectors;
24with HW.GFX.GMA.Connector_Info;
25with HW.GFX.GMA.Pipe_Setup;
26
27with System;
28
29with HW.Debug;
30with GNAT.Source_Info;
31
32use type HW.Word8;
33use type HW.Int32;
34
35package body HW.GFX.GMA
36 with Refined_State =>
37 (State =>
38 (Registers.Address_State,
39 PLLs.State, Panel.Panel_State,
40 Cur_Configs, Allocated_PLLs, DP_Links,
41 HPD_Delay, Wait_For_HPD),
42 Init_State => Initialized,
43 Config_State => Config.Valid_Port_GPU,
44 Device_State =>
45 (Registers.Register_State, Registers.GTT_State))
46is
47
48 subtype Port_Name is String (1 .. 8);
49 type Port_Name_Array is array (Port_Type) of Port_Name;
50 Port_Names : constant Port_Name_Array :=
51 (Disabled => "Disabled",
52 Internal => "Internal",
53 DP1 => "DP1 ",
54 DP2 => "DP2 ",
55 DP3 => "DP3 ",
Nico Huber0d454cd2016-11-21 13:33:43 +010056 HDMI1 => "HDMI1 ",
57 HDMI2 => "HDMI2 ",
58 HDMI3 => "HDMI3 ",
Nico Huber83693c82016-10-08 22:17:55 +020059 Analog => "Analog ");
60
61 package Display_Controller renames Pipe_Setup;
62
Nico Huber99f10f32016-11-20 00:34:05 +010063 type PLLs_Type is array (Pipe_Index) of PLLs.T;
Nico Huber83693c82016-10-08 22:17:55 +020064
Nico Huber99f10f32016-11-20 00:34:05 +010065 type Links_Type is array (Pipe_Index) of DP_Link;
Nico Huber83693c82016-10-08 22:17:55 +020066
67 type HPD_Type is array (Port_Type) of Boolean;
68 type HPD_Delay_Type is array (Port_Type) of Time.T;
69
Nico Huber99f10f32016-11-20 00:34:05 +010070 Cur_Configs : Pipe_Configs;
Nico Huber83693c82016-10-08 22:17:55 +020071 Allocated_PLLs : PLLs_Type;
72 DP_Links : Links_Type;
73 HPD_Delay : HPD_Delay_Type;
74 Wait_For_HPD : HPD_Type;
75 Initialized : Boolean := False;
76
77 subtype Active_Port_Type is Port_Type range Port_Type'Succ (Disabled) .. Port_Type'Last;
78
79 ----------------------------------------------------------------------------
80
Nico Huberf54d0962016-10-20 14:17:18 +020081 PCH_RAWCLK_FREQ_MASK : constant := 16#3ff# * 2 ** 0;
82
83 function PCH_RAWCLK_FREQ (Freq : Frequency_Type) return Word32
84 is
85 begin
86 return Word32 (Freq / 1_000_000);
87 end PCH_RAWCLK_FREQ;
88
89 ----------------------------------------------------------------------------
90
Nico Huber83693c82016-10-08 22:17:55 +020091 function To_GPU_Port
Nico Huber99f10f32016-11-20 00:34:05 +010092 (Configs : Pipe_Configs;
93 Idx : Pipe_Index)
Nico Huber83693c82016-10-08 22:17:55 +020094 return GPU_Port
95 is
96 begin
97 return
98 (case Config.CPU is
99 when Ironlake .. Ivybridge => -- everything but eDP through FDI/PCH
100 (if Config.Internal_Is_EDP and then Configs (Idx).Port = Internal
101 then
102 DIGI_A
103 else
104 (case Idx is
105 -- FDIs are fixed to the CPU pipe
106 when Primary => DIGI_B,
107 when Secondary => DIGI_C,
108 when Tertiary => DIGI_D)),
109 when Haswell .. Skylake => -- everything but VGA directly on CPU
110 (case Configs (Idx).Port is
Nico Huber0d454cd2016-11-21 13:33:43 +0100111 when Disabled => GPU_Port'First,
112 when Internal => DIGI_A, -- LVDS not available
113 when HDMI1 | DP1 => DIGI_B,
114 when HDMI2 | DP2 => DIGI_C,
115 when HDMI3 | DP3 => DIGI_D,
116 when Analog => DIGI_E));
Nico Huber83693c82016-10-08 22:17:55 +0200117 end To_GPU_Port;
118
119 function To_PCH_Port (Port : Active_Port_Type) return PCH_Port
120 is
121 begin
122 return
123 (case Port is
124 when Internal => PCH_LVDS, -- will be ignored if Internal is DP
125 when Analog => PCH_DAC,
Nico Huber0d454cd2016-11-21 13:33:43 +0100126 when HDMI1 => PCH_HDMI_B,
127 when HDMI2 => PCH_HDMI_C,
128 when HDMI3 => PCH_HDMI_D,
Nico Huber83693c82016-10-08 22:17:55 +0200129 when DP1 => PCH_DP_B,
130 when DP2 => PCH_DP_C,
131 when DP3 => PCH_DP_D);
132 end To_PCH_Port;
133
134 function To_Display_Type (Port : Active_Port_Type) return Display_Type
135 with Pre => True
136 is
137 begin
138 return
139 (case Port is
140 when Internal => Config.Internal_Display,
141 when Analog => VGA,
Nico Huber0d454cd2016-11-21 13:33:43 +0100142 when HDMI1 |
143 HDMI2 |
144 HDMI3 => HDMI,
Nico Huber83693c82016-10-08 22:17:55 +0200145 when DP1 |
146 DP2 |
147 DP3 => DP);
148 end To_Display_Type;
149
150 procedure Configure_FDI_Link
151 (Port_Cfg : in out Port_Config;
152 Success : out Boolean)
Nico Huber47ff0692016-11-04 14:29:39 +0100153 with
154 Post => Port_Cfg.Mode = Port_Cfg.Mode'Old
Nico Huber83693c82016-10-08 22:17:55 +0200155 is
156 procedure Limit_Lane_Count
157 is
158 FDI_TX_CTL_FDI_TX_ENABLE : constant := 1 * 2 ** 31;
159 Enabled : Boolean;
160 begin
161 -- if DIGI_D enabled: (FDI names are off by one)
162 Registers.Is_Set_Mask
163 (Register => Registers.FDI_TX_CTL_C,
164 Mask => FDI_TX_CTL_FDI_TX_ENABLE,
165 Result => Enabled);
166 if Enabled then
167 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_2;
168 end if;
169 end Limit_Lane_Count;
170 begin
171 Port_Cfg.FDI.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
172 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count :=
173 Config.FDI_Lane_Count (Port_Cfg.Port);
174 Port_Cfg.FDI.Receiver_Caps.Enhanced_Framing := True;
175 if Config.Has_FDI_C and then Port_Cfg.Port = DIGI_C then
176 Limit_Lane_Count;
177 end if;
178 DP_Info.Preferred_Link_Setting (Port_Cfg.FDI, Port_Cfg.Mode, Success);
179 end Configure_FDI_Link;
180
Nico Huberc7a4fee2016-11-03 18:18:03 +0100181 function Validate_Config
182 (Framebuffer : Framebuffer_Type;
Nico Huberdcd274b2016-11-03 20:15:39 +0100183 Port_Cfg : Port_Config;
Nico Huber99f10f32016-11-20 00:34:05 +0100184 I : Pipe_Index)
Nico Huberc7a4fee2016-11-03 18:18:03 +0100185 return Boolean
Nico Huber47ff0692016-11-04 14:29:39 +0100186 with
187 Post =>
188 (if Validate_Config'Result then
189 Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and
190 Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible))
Nico Huberc7a4fee2016-11-03 18:18:03 +0100191 is
192 begin
193 -- No downscaling
Nico Huberdcd274b2016-11-03 20:15:39 +0100194 -- Respect maximum scalable width
Nico Huber3675db52016-11-04 16:27:29 +0100195 -- VGA plane is only allowed on the primary pipe
196 -- Only 32bpp RGB (ignored for VGA plane)
197 -- Stride must be a multiple of 64 (ignored for VGA plane)
Nico Huberc7a4fee2016-11-03 18:18:03 +0100198 return
Nico Huberdcd274b2016-11-03 20:15:39 +0100199 ((Framebuffer.Width = Pos32 (Port_Cfg.Mode.H_Visible) and
200 Framebuffer.Height = Pos32 (Port_Cfg.Mode.V_Visible)) or
201 (Framebuffer.Width <= Config.Maximum_Scalable_Width (I) and
202 Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and
203 Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible))) and
Nico Huber3675db52016-11-04 16:27:29 +0100204 (Framebuffer.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or I = Primary) and
205 (Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
206 (Framebuffer.BPC = 8 and
207 Framebuffer.Stride mod 64 = 0));
Nico Huberc7a4fee2016-11-03 18:18:03 +0100208 end Validate_Config;
209
Nico Huber83693c82016-10-08 22:17:55 +0200210 procedure Fill_Port_Config
211 (Port_Cfg : out Port_Config;
Nico Huber99f10f32016-11-20 00:34:05 +0100212 Configs : in Pipe_Configs;
213 Idx : in Pipe_Index;
Nico Huber83693c82016-10-08 22:17:55 +0200214 Success : out Boolean)
215 with Pre => True
216 is
217 begin
218 Success :=
219 Config.Supported_Pipe (Idx) and then
220 Config.Valid_Port (Configs (Idx).Port) and then
221 Configs (Idx).Port /= Disabled;
222
223 if Success then
224 declare
225 Port : constant Port_Type := Configs (Idx).Port;
226 Mode : constant Mode_Type := Configs (Idx).Mode;
227 Link : constant DP_Link := DP_Links (Idx);
228 begin
229 Port_Cfg := Port_Config'
230 (Port => To_GPU_Port (Configs, Idx),
231 PCH_Port => To_PCH_Port (Port),
232 Display => To_Display_Type (Port),
233 Mode => Mode,
234 Is_FDI => Config.FDI_Port (To_GPU_Port (Configs, Idx)),
235 FDI => Default_DP,
236 DP => Link);
237 if Port_Cfg.Mode.BPC = Auto_BPC then
238 Port_Cfg.Mode.BPC := Connector_Info.Default_BPC (Port_Cfg);
239 end if;
Nico Huber74ec9622016-11-19 03:00:43 +0100240 if Port_Cfg.Display = HDMI then
241 declare
242 pragma Assert (Config.HDMI_Max_Clock_24bpp * 8
243 / Port_Cfg.Mode.BPC >= Frequency_Type'First);
244 Max_Dotclock : constant Frequency_Type :=
245 Config.HDMI_Max_Clock_24bpp * 8 / Port_Cfg.Mode.BPC;
246 begin
247 if Port_Cfg.Mode.Dotclock > Max_Dotclock then
248 pragma Debug (Debug.Put ("Dotclock "));
249 pragma Debug (Debug.Put_Int64 (Port_Cfg.Mode.Dotclock));
250 pragma Debug (Debug.Put (" too high, limiting to "));
251 pragma Debug (Debug.Put_Int64 (Max_Dotclock));
252 pragma Debug (Debug.Put_Line ("."));
253 Port_Cfg.Mode.Dotclock := Max_Dotclock;
254 end if;
255 end;
256 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200257 end;
258 else
259 Port_Cfg := Port_Config'
260 (Port => GPU_Port'First,
261 PCH_Port => PCH_Port'First,
262 Display => Display_Type'First,
263 Mode => Invalid_Mode,
264 Is_FDI => False,
265 FDI => Default_DP,
266 DP => Default_DP);
267 end if;
268 end Fill_Port_Config;
269
270 ----------------------------------------------------------------------------
271
272 function To_Controller
Nico Huber99f10f32016-11-20 00:34:05 +0100273 (Dsp_Config : Pipe_Index) return Display_Controller.Controller_Type
Nico Huber83693c82016-10-08 22:17:55 +0200274 is
275 Result : Display_Controller.Controller_Type;
276 begin
277 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
278
279 case Dsp_Config is
280 when Primary =>
281 Result := Display_Controller.Controllers (Display_Controller.A);
282 when Secondary =>
283 Result := Display_Controller.Controllers (Display_Controller.B);
284 when Tertiary =>
285 Result := Display_Controller.Controllers (Display_Controller.C);
286 end case;
287 return Result;
288 end To_Controller;
289
290 ----------------------------------------------------------------------------
291
292 function To_Head
Nico Huber99f10f32016-11-20 00:34:05 +0100293 (N_Config : Pipe_Index;
Nico Huber83693c82016-10-08 22:17:55 +0200294 Port : Active_Port_Type)
295 return Display_Controller.Head_Type
296 is
297 Result : Display_Controller.Head_Type;
298 begin
299 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
300
301 if Config.Has_EDP_Pipe and then Port = Internal then
302 Result := Display_Controller.Heads (Display_Controller.Head_EDP);
303 else
304 case N_Config is
305 when Primary =>
306 Result := Display_Controller.Heads (Display_Controller.Head_A);
307 when Secondary =>
308 Result := Display_Controller.Heads (Display_Controller.Head_B);
309 when Tertiary =>
310 Result := Display_Controller.Heads (Display_Controller.Head_C);
311 end case;
312 end if;
313 return Result;
314 end To_Head;
315
316 ----------------------------------------------------------------------------
317
318 procedure Legacy_VGA_Off
319 is
320 Reg8 : Word8;
321 begin
322 -- disable legacy VGA plane, taking over control now
323 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
324 Port_IO.InB (Reg8, VGA_SR_DATA);
325 Port_IO.OutB (VGA_SR_DATA, Reg8 or 1 * 2 ** 5);
326 Time.U_Delay (100); -- PRM says 100us, Linux does 300
327 Registers.Set_Mask (Registers.VGACNTRL, 1 * 2 ** 31);
328 end Legacy_VGA_Off;
329
330 ----------------------------------------------------------------------------
331
332 function Port_Configured
Nico Huber99f10f32016-11-20 00:34:05 +0100333 (Configs : Pipe_Configs;
Nico Huber83693c82016-10-08 22:17:55 +0200334 Port : Port_Type)
335 return Boolean
336 with
337 Global => null
338 is
339 begin
340 return Configs (Primary).Port = Port or
341 Configs (Secondary).Port = Port or
342 Configs (Tertiary).Port = Port;
343 end Port_Configured;
344
345 procedure Scan_Ports
Nico Huber99f10f32016-11-20 00:34:05 +0100346 (Configs : out Pipe_Configs;
Nico Huberaa91bb52016-11-07 12:51:20 +0100347 Ports : in Port_List;
Nico Huber99f10f32016-11-20 00:34:05 +0100348 Max_Pipe : in Pipe_Index := Pipe_Index'Last)
Nico Huber83693c82016-10-08 22:17:55 +0200349 is
350 Raw_EDID : EDID.Raw_EDID_Data := (others => 16#00#);
351 Port_Idx : Port_List_Range := Port_List_Range'First;
352 Port_Cfg : Port_Config;
353 Success : Boolean := False;
354 begin
Nico Huber99f10f32016-11-20 00:34:05 +0100355 Configs := (Pipe_Index =>
Nico Huber83693c82016-10-08 22:17:55 +0200356 (Port => Disabled,
357 Mode => Invalid_Mode,
358 Framebuffer => Default_FB));
359
Nico Huber99f10f32016-11-20 00:34:05 +0100360 for Config_Idx in Pipe_Index range Pipe_Index'First .. Max_Pipe loop
Nico Huber83693c82016-10-08 22:17:55 +0200361 while Ports (Port_Idx) /= Disabled loop
362 if not Port_Configured (Configs, Ports (Port_Idx)) then
363 Configs (Config_Idx).Port := Ports (Port_Idx);
364 Fill_Port_Config (Port_Cfg, Configs, Config_Idx, Success);
365
366 if Success then
367 -- May need power to probe port
368 if Port_Cfg.Display = DP then
369 Power_And_Clocks.Power_Up (Cur_Configs, Configs);
370 end if;
371 if Ports (Port_Idx) = Internal then
372 Panel.On;
373 end if;
374
375 Connector_Info.Read_EDID (Raw_EDID, Port_Cfg, Success);
376 end if;
377
Nico Huber393aa8a2016-10-21 14:18:53 +0200378 if Success and then
379 (EDID.Compatible_Display (Raw_EDID, Port_Cfg.Display) and
380 EDID.Has_Preferred_Mode (Raw_EDID))
381 then
Nico Huber83693c82016-10-08 22:17:55 +0200382 Configs (Config_Idx).Mode := EDID.Preferred_Mode (Raw_EDID);
383 else
384 Configs (Config_Idx).Port := Disabled;
Nico Huber6a356672016-10-21 15:13:55 +0200385 Success := False;
Nico Huber83693c82016-10-08 22:17:55 +0200386
387 if Ports (Port_Idx) = Internal and
388 not Port_Configured (Cur_Configs, Internal)
389 then
390 Panel.Off;
391 end if;
392 end if;
393 end if;
394
395 exit when Port_Idx = Port_List_Range'Last;
396 Port_Idx := Port_List_Range'Succ (Port_Idx);
397
398 exit when Success;
399 end loop;
400 end loop;
401
402 Power_And_Clocks.Power_Set_To (Cur_Configs);
403 end Scan_Ports;
404
Nico Huber83693c82016-10-08 22:17:55 +0200405 ----------------------------------------------------------------------------
406
Nico Huber99f10f32016-11-20 00:34:05 +0100407 procedure Update_Outputs (Configs : Pipe_Configs)
Nico Huber83693c82016-10-08 22:17:55 +0200408 is
409 Did_Power_Up : Boolean := False;
410
411 HPD, HPD_Delay_Over, Success : Boolean;
Nico Huber99f10f32016-11-20 00:34:05 +0100412 Old_Config, New_Config : Pipe_Config;
413 Old_Configs : Pipe_Configs;
Nico Huber83693c82016-10-08 22:17:55 +0200414 Port_Cfg : Port_Config;
415
416 procedure Check_HPD
417 (Port_Cfg : in Port_Config;
418 Port : in Port_Type;
419 Detected : out Boolean)
420 is
421 begin
422 HPD_Delay_Over := Time.Timed_Out (HPD_Delay (Port));
423 if HPD_Delay_Over then
424 Port_Detect.Hotplug_Detect (Port_Cfg, Detected);
425 HPD_Delay (Port) := Time.MS_From_Now (333);
426 else
427 Detected := False;
428 end if;
429 end Check_HPD;
430 begin
431 Old_Configs := Cur_Configs;
432
Nico Huber99f10f32016-11-20 00:34:05 +0100433 for I in Pipe_Index loop
Nico Huber83693c82016-10-08 22:17:55 +0200434 HPD := False;
435
436 Old_Config := Cur_Configs (I);
437 New_Config := Configs (I);
438
439 Fill_Port_Config (Port_Cfg, Old_Configs, I, Success);
440 if Success then
441 Check_HPD (Port_Cfg, Old_Config.Port, HPD);
442 end if;
443
444 -- Connector changed?
445 if (Success and then HPD) or
446 Old_Config.Port /= New_Config.Port or
447 Old_Config.Mode /= New_Config.Mode
448 then
449 if Old_Config.Port /= Disabled then
450 if Success then
451 pragma Debug (Debug.New_Line);
452 pragma Debug (Debug.Put_Line
453 ("Disabling port " & Port_Names (Old_Config.Port)));
454
455 Connectors.Pre_Off (Port_Cfg);
456
457 Display_Controller.Off
458 (To_Controller (I), To_Head (I, Old_Config.Port));
459
460 Connectors.Post_Off (Port_Cfg);
461 end if;
462
463 -- Free PLL
464 PLLs.Free (Allocated_PLLs (I));
465
466 Cur_Configs (I).Port := Disabled;
467 end if;
468
469 if New_Config.Port /= Disabled then
470 Fill_Port_Config (Port_Cfg, Configs, I, Success);
471
Nico Huberc7a4fee2016-11-03 18:18:03 +0100472 Success := Success and then
Nico Huberdcd274b2016-11-03 20:15:39 +0100473 Validate_Config (New_Config.Framebuffer, Port_Cfg, I);
Nico Huberc7a4fee2016-11-03 18:18:03 +0100474
Nico Huber83693c82016-10-08 22:17:55 +0200475 if Success and then Wait_For_HPD (New_Config.Port) then
476 Check_HPD (Port_Cfg, New_Config.Port, Success);
477 Wait_For_HPD (New_Config.Port) := not Success;
478 end if;
479
480 if Success then
481 pragma Debug (Debug.New_Line);
482 pragma Debug (Debug.Put_Line
483 ("Trying to enable port " & Port_Names (New_Config.Port)));
484
485 if not Did_Power_Up then
486 Power_And_Clocks.Power_Up (Old_Configs, Configs);
487 Did_Power_Up := True;
488 end if;
489
490 if Port_Cfg.Is_FDI then
491 Configure_FDI_Link (Port_Cfg, Success);
492 end if;
493 end if;
494
495 if Success then
496 Connector_Info.Preferred_Link_Setting
497 (Port_Cfg => Port_Cfg,
498 Success => Success);
499 end if;
500
501 while Success loop
Nico Huber47ff0692016-11-04 14:29:39 +0100502 pragma Loop_Invariant
503 (New_Config.Port in Active_Port_Type and
504 Port_Cfg.Mode = Port_Cfg.Mode'Loop_Entry);
Nico Huber83693c82016-10-08 22:17:55 +0200505
506 PLLs.Alloc
507 (Port_Cfg => Port_Cfg,
508 PLL => Allocated_PLLs (I),
509 Success => Success);
510
511 if Success then
512 for Try in 1 .. 2 loop
513 pragma Loop_Invariant
514 (New_Config.Port in Active_Port_Type);
515
516 Connectors.Pre_On
517 (Port_Cfg => Port_Cfg,
518 PLL_Hint => PLLs.Register_Value
519 (Allocated_PLLs (I)),
520 Pipe_Hint => Display_Controller.Get_Pipe_Hint
521 (To_Head (I, New_Config.Port)),
522 Success => Success);
523
524 if Success then
525 Display_Controller.On
526 (Controller => To_Controller (I),
527 Head => To_Head (I, New_Config.Port),
528 Port_Cfg => Port_Cfg,
529 Framebuffer => New_Config.Framebuffer);
530
531 Connectors.Post_On
532 (Port_Cfg => Port_Cfg,
533 PLL_Hint => PLLs.Register_Value
534 (Allocated_PLLs (I)),
535 Success => Success);
536
537 if not Success then
538 Display_Controller.Off
539 (To_Controller (I),
540 To_Head (I, New_Config.Port));
541 Connectors.Post_Off (Port_Cfg);
542 end if;
543 end if;
544
545 exit when Success;
546 end loop;
547 exit when Success; -- connection established => stop loop
548
549 -- connection failed
550 PLLs.Free (Allocated_PLLs (I));
551 end if;
552
553 Connector_Info.Next_Link_Setting
554 (Port_Cfg => Port_Cfg,
555 Success => Success);
556 end loop;
557
558 if Success then
559 pragma Debug (Debug.Put_Line
560 ("Enabled port " & Port_Names (New_Config.Port)));
561 Cur_Configs (I) := New_Config;
562 DP_Links (I) := Port_Cfg.DP;
563 else
564 Wait_For_HPD (New_Config.Port) := True;
565 if New_Config.Port = Internal then
566 Panel.Off;
567 end if;
568 end if;
569 else
570 Cur_Configs (I) := New_Config;
571 end if;
572 elsif Old_Config.Framebuffer /= New_Config.Framebuffer and
573 Old_Config.Port /= Disabled
574 then
575 Display_Controller.Update_Offset
576 (Controller => To_Controller (I),
577 Framebuffer => New_Config.Framebuffer);
578 Cur_Configs (I) := New_Config;
579 end if;
580 end loop;
581
582 if Did_Power_Up then
583 Power_And_Clocks.Power_Down (Old_Configs, Configs, Cur_Configs);
584 end if;
585
586 end Update_Outputs;
587
588 ----------------------------------------------------------------------------
589
590 procedure Initialize
591 (MMIO_Base : in Word64 := 0;
592 Write_Delay : in Word64 := 0;
593 Success : out Boolean)
594 with
595 Refined_Global =>
596 (In_Out =>
597 (Config.Valid_Port_GPU,
598 Registers.Register_State, Port_IO.State),
599 Input =>
600 (Time.State),
601 Output =>
602 (Registers.Address_State,
603 PLLs.State, Panel.Panel_State,
604 Cur_Configs, Allocated_PLLs, DP_Links,
605 HPD_Delay, Wait_For_HPD, Initialized))
606 is
607 use type HW.Word64;
608
609 Now : constant Time.T := Time.Now;
610
611 procedure Check_Platform (Success : out Boolean)
612 is
613 Audio_VID_DID : Word32;
614 begin
615 case Config.CPU is
616 when Haswell .. Skylake =>
617 Registers.Read (Registers.AUD_VID_DID, Audio_VID_DID);
618 when Ironlake .. Ivybridge =>
619 Registers.Read (Registers.PCH_AUD_VID_DID, Audio_VID_DID);
620 end case;
621 Success :=
622 (case Config.CPU is
623 when Skylake => Audio_VID_DID = 16#8086_2809#,
624 when Broadwell => Audio_VID_DID = 16#8086_2808#,
625 when Haswell => Audio_VID_DID = 16#8086_2807#,
626 when Ivybridge |
627 Sandybridge => Audio_VID_DID = 16#8086_2806# or
628 Audio_VID_DID = 16#8086_2805#,
Nico Hubereeb5a392016-10-09 19:28:30 +0200629 when Ironlake => Audio_VID_DID = 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200630 end Check_Platform;
631 begin
632 pragma Warnings (GNATprove, Off, "unused variable ""Write_Delay""",
633 Reason => "Write_Delay is used for debugging only");
634
635 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
636
637 pragma Debug (Debug.Set_Register_Write_Delay (Write_Delay));
638
639 Wait_For_HPD := HPD_Type'(others => False);
640 HPD_Delay := HPD_Delay_Type'(others => Now);
641 DP_Links := Links_Type'(others => HW.GFX.Default_DP);
642 Allocated_PLLs := (others => PLLs.Invalid);
Nico Huber99f10f32016-11-20 00:34:05 +0100643 Cur_Configs := Pipe_Configs'
644 (others => Pipe_Config'
Nico Huber83693c82016-10-08 22:17:55 +0200645 (Port => Disabled,
646 Framebuffer => HW.GFX.Default_FB,
647 Mode => HW.GFX.Invalid_Mode));
648 Registers.Set_Register_Base
649 (if MMIO_Base /= 0 then
650 MMIO_Base
651 else
652 Config.Default_MMIO_Base);
653 PLLs.Initialize;
654
655 Check_Platform (Success);
656 if not Success then
657 pragma Debug (Debug.Put_Line ("ERROR: Incompatible CPU or PCH."));
658
659 Panel.Static_Init; -- for flow analysis
660
661 Initialized := False;
662 return;
663 end if;
664
665 Panel.Setup_PP_Sequencer;
666 Port_Detect.Initialize;
667
668 Power_And_Clocks.Pre_All_Off;
669
670 Legacy_VGA_Off;
671
672 Connectors.Pre_All_Off;
673 Display_Controller.All_Off;
674 Connectors.Post_All_Off;
675 PLLs.All_Off;
676
677 Power_And_Clocks.Post_All_Off;
678
679 -------------------- Now restart from a clean state ---------------------
680 Power_And_Clocks.Initialize;
681
Nico Huberf54d0962016-10-20 14:17:18 +0200682 Registers.Unset_And_Set_Mask
683 (Register => Registers.PCH_RAWCLK_FREQ,
684 Mask_Unset => PCH_RAWCLK_FREQ_MASK,
685 Mask_Set => PCH_RAWCLK_FREQ (Config.Default_RawClk_Freq));
686
Nico Huber83693c82016-10-08 22:17:55 +0200687 Initialized := True;
688
689 end Initialize;
690
691 function Is_Initialized return Boolean
692 with
693 Refined_Post => Is_Initialized'Result = Initialized
694 is
695 begin
696 return Initialized;
697 end Is_Initialized;
698
699 ----------------------------------------------------------------------------
700
701 procedure Write_GTT
702 (GTT_Page : GTT_Range;
703 Device_Address : GTT_Address_Type;
704 Valid : Boolean) is
705 begin
706 Registers.Write_GTT (GTT_Page, Device_Address, Valid);
707 end Write_GTT;
708
709 procedure Setup_Default_GTT (FB : Framebuffer_Type; Phys_FB : Word32)
710 is
711 FB_Size : constant Pos32 :=
712 FB.Stride * FB.Height * Pos32 (((FB.BPC * 4) / 8));
713 Phys_Addr : GTT_Address_Type := GTT_Address_Type (Phys_FB);
714 begin
715 for Idx in GTT_Range range 0 .. GTT_Range (((FB_Size + 4095) / 4096) - 1)
716 loop
717 Registers.Write_GTT
718 (GTT_Page => Idx,
719 Device_Address => Phys_Addr,
720 Valid => True);
721 Phys_Addr := Phys_Addr + 4096;
722 end loop;
723 end Setup_Default_GTT;
724
725 ----------------------------------------------------------------------------
726
Nico Huber99f10f32016-11-20 00:34:05 +0100727 procedure Dump_Configs (Configs : Pipe_Configs)
Nico Huber83693c82016-10-08 22:17:55 +0200728 is
729 subtype Pipe_Name is String (1 .. 9);
Nico Huber99f10f32016-11-20 00:34:05 +0100730 type Pipe_Name_Array is array (Pipe_Index) of Pipe_Name;
Nico Huber83693c82016-10-08 22:17:55 +0200731 Pipe_Names : constant Pipe_Name_Array :=
732 (Primary => "Primary ",
733 Secondary => "Secondary",
734 Tertiary => "Tertiary ");
735 begin
736 Debug.New_Line;
737 Debug.Put_Line ("CONFIG => ");
Nico Huber99f10f32016-11-20 00:34:05 +0100738 for Pipe in Pipe_Index loop
739 if Pipe = Pipe_Index'First then
Nico Huber83693c82016-10-08 22:17:55 +0200740 Debug.Put (" (");
741 else
742 Debug.Put (" ");
743 end if;
744 Debug.Put_Line (Pipe_Names (Pipe) & " =>");
745 Debug.Put_Line
746 (" (Port => " & Port_Names (Configs (Pipe).Port) & ",");
747 Debug.Put_Line (" Framebuffer =>");
748 Debug.Put (" (Width => ");
749 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Width);
750 Debug.Put_Line (",");
751 Debug.Put (" Height => ");
752 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Height);
753 Debug.Put_Line (",");
754 Debug.Put (" Stride => ");
755 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Stride);
756 Debug.Put_Line (",");
757 Debug.Put (" Offset => ");
758 Debug.Put_Word32 (Configs (Pipe).Framebuffer.Offset);
759 Debug.Put_Line (",");
760 Debug.Put (" BPC => ");
761 Debug.Put_Int64 (Configs (Pipe).Framebuffer.BPC);
762 Debug.Put_Line ("),");
763 Debug.Put_Line (" Mode =>");
764 Debug.Put (" (Dotclock => ");
765 Debug.Put_Int64 (Configs (Pipe).Mode.Dotclock);
766 Debug.Put_Line (",");
767 Debug.Put (" H_Visible => ");
768 Debug.Put_Int16 (Configs (Pipe).Mode.H_Visible);
769 Debug.Put_Line (",");
770 Debug.Put (" H_Sync_Begin => ");
771 Debug.Put_Int16 (Configs (Pipe).Mode.H_Sync_Begin);
772 Debug.Put_Line (",");
773 Debug.Put (" H_Sync_End => ");
774 Debug.Put_Int16 (Configs (Pipe).Mode.H_Sync_End);
775 Debug.Put_Line (",");
776 Debug.Put (" H_Total => ");
777 Debug.Put_Int16 (Configs (Pipe).Mode.H_Total);
778 Debug.Put_Line (",");
779 Debug.Put (" V_Visible => ");
780 Debug.Put_Int16 (Configs (Pipe).Mode.V_Visible);
781 Debug.Put_Line (",");
782 Debug.Put (" V_Sync_Begin => ");
783 Debug.Put_Int16 (Configs (Pipe).Mode.V_Sync_Begin);
784 Debug.Put_Line (",");
785 Debug.Put (" V_Sync_End => ");
786 Debug.Put_Int16 (Configs (Pipe).Mode.V_Sync_End);
787 Debug.Put_Line (",");
788 Debug.Put (" V_Total => ");
789 Debug.Put_Int16 (Configs (Pipe).Mode.V_Total);
790 Debug.Put_Line (",");
791 Debug.Put_Line (" H_Sync_Active_High => " &
792 (if Configs (Pipe).Mode.H_Sync_Active_High
793 then "True,"
794 else "False,"));
795 Debug.Put_Line (" V_Sync_Active_High => " &
796 (if Configs (Pipe).Mode.V_Sync_Active_High
797 then "True,"
798 else "False,"));
799 Debug.Put (" BPC => ");
800 Debug.Put_Int64 (Configs (Pipe).Mode.BPC);
Nico Huber99f10f32016-11-20 00:34:05 +0100801 if Pipe /= Pipe_Index'Last then
Nico Huber83693c82016-10-08 22:17:55 +0200802 Debug.Put_Line (")),");
803 else
804 Debug.Put_Line (")));");
805 end if;
806 end loop;
807 end Dump_Configs;
808
809end HW.GFX.GMA;