blob: 18523557839b50eae51c896d241ea1a4f9ed557a [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
Nico Huber995436b2016-11-20 02:21:51 +010015with HW.GFX.I2C;
Nico Huber83693c82016-10-08 22:17:55 +020016with HW.GFX.EDID;
17with HW.GFX.GMA.Config;
Nico Huber995436b2016-11-20 02:21:51 +010018with HW.GFX.GMA.I2C;
19with HW.GFX.GMA.DP_Aux_Ch;
Nico Huber83693c82016-10-08 22:17:55 +020020with HW.GFX.GMA.DP_Info;
21with HW.GFX.GMA.Registers;
22with HW.GFX.GMA.Power_And_Clocks;
23with HW.GFX.GMA.Panel;
24with HW.GFX.GMA.PLLs;
25with HW.GFX.GMA.Port_Detect;
26with HW.GFX.GMA.Connectors;
27with HW.GFX.GMA.Connector_Info;
28with HW.GFX.GMA.Pipe_Setup;
29
30with System;
31
32with HW.Debug;
33with GNAT.Source_Info;
34
35use type HW.Word8;
36use type HW.Int32;
37
38package body HW.GFX.GMA
39 with Refined_State =>
40 (State =>
41 (Registers.Address_State,
42 PLLs.State, Panel.Panel_State,
43 Cur_Configs, Allocated_PLLs, DP_Links,
44 HPD_Delay, Wait_For_HPD),
45 Init_State => Initialized,
46 Config_State => Config.Valid_Port_GPU,
47 Device_State =>
48 (Registers.Register_State, Registers.GTT_State))
49is
50
51 subtype Port_Name is String (1 .. 8);
52 type Port_Name_Array is array (Port_Type) of Port_Name;
53 Port_Names : constant Port_Name_Array :=
54 (Disabled => "Disabled",
55 Internal => "Internal",
56 DP1 => "DP1 ",
57 DP2 => "DP2 ",
58 DP3 => "DP3 ",
Nico Huber0d454cd2016-11-21 13:33:43 +010059 HDMI1 => "HDMI1 ",
60 HDMI2 => "HDMI2 ",
61 HDMI3 => "HDMI3 ",
Nico Huber83693c82016-10-08 22:17:55 +020062 Analog => "Analog ");
63
64 package Display_Controller renames Pipe_Setup;
65
Nico Huber99f10f32016-11-20 00:34:05 +010066 type PLLs_Type is array (Pipe_Index) of PLLs.T;
Nico Huber83693c82016-10-08 22:17:55 +020067
Nico Huber99f10f32016-11-20 00:34:05 +010068 type Links_Type is array (Pipe_Index) of DP_Link;
Nico Huber83693c82016-10-08 22:17:55 +020069
70 type HPD_Type is array (Port_Type) of Boolean;
71 type HPD_Delay_Type is array (Port_Type) of Time.T;
72
Nico Huber99f10f32016-11-20 00:34:05 +010073 Cur_Configs : Pipe_Configs;
Nico Huber83693c82016-10-08 22:17:55 +020074 Allocated_PLLs : PLLs_Type;
75 DP_Links : Links_Type;
76 HPD_Delay : HPD_Delay_Type;
77 Wait_For_HPD : HPD_Type;
78 Initialized : Boolean := False;
79
80 subtype Active_Port_Type is Port_Type range Port_Type'Succ (Disabled) .. Port_Type'Last;
81
82 ----------------------------------------------------------------------------
83
Nico Huberf54d0962016-10-20 14:17:18 +020084 PCH_RAWCLK_FREQ_MASK : constant := 16#3ff# * 2 ** 0;
85
86 function PCH_RAWCLK_FREQ (Freq : Frequency_Type) return Word32
87 is
88 begin
89 return Word32 (Freq / 1_000_000);
90 end PCH_RAWCLK_FREQ;
91
92 ----------------------------------------------------------------------------
93
Nico Huber83693c82016-10-08 22:17:55 +020094 function To_GPU_Port
Nico Huber99f10f32016-11-20 00:34:05 +010095 (Configs : Pipe_Configs;
96 Idx : Pipe_Index)
Nico Huber83693c82016-10-08 22:17:55 +020097 return GPU_Port
98 is
99 begin
100 return
101 (case Config.CPU is
102 when Ironlake .. Ivybridge => -- everything but eDP through FDI/PCH
103 (if Config.Internal_Is_EDP and then Configs (Idx).Port = Internal
104 then
105 DIGI_A
106 else
107 (case Idx is
108 -- FDIs are fixed to the CPU pipe
109 when Primary => DIGI_B,
110 when Secondary => DIGI_C,
111 when Tertiary => DIGI_D)),
112 when Haswell .. Skylake => -- everything but VGA directly on CPU
113 (case Configs (Idx).Port is
Nico Huber0d454cd2016-11-21 13:33:43 +0100114 when Disabled => GPU_Port'First,
115 when Internal => DIGI_A, -- LVDS not available
116 when HDMI1 | DP1 => DIGI_B,
117 when HDMI2 | DP2 => DIGI_C,
118 when HDMI3 | DP3 => DIGI_D,
119 when Analog => DIGI_E));
Nico Huber83693c82016-10-08 22:17:55 +0200120 end To_GPU_Port;
121
122 function To_PCH_Port (Port : Active_Port_Type) return PCH_Port
Nico Huber995436b2016-11-20 02:21:51 +0100123 with Pre => True
Nico Huber83693c82016-10-08 22:17:55 +0200124 is
125 begin
126 return
127 (case Port is
128 when Internal => PCH_LVDS, -- will be ignored if Internal is DP
129 when Analog => PCH_DAC,
Nico Huber0d454cd2016-11-21 13:33:43 +0100130 when HDMI1 => PCH_HDMI_B,
131 when HDMI2 => PCH_HDMI_C,
132 when HDMI3 => PCH_HDMI_D,
Nico Huber83693c82016-10-08 22:17:55 +0200133 when DP1 => PCH_DP_B,
134 when DP2 => PCH_DP_C,
135 when DP3 => PCH_DP_D);
136 end To_PCH_Port;
137
138 function To_Display_Type (Port : Active_Port_Type) return Display_Type
139 with Pre => True
140 is
141 begin
142 return
143 (case Port is
144 when Internal => Config.Internal_Display,
145 when Analog => VGA,
Nico Huber0d454cd2016-11-21 13:33:43 +0100146 when HDMI1 |
147 HDMI2 |
148 HDMI3 => HDMI,
Nico Huber83693c82016-10-08 22:17:55 +0200149 when DP1 |
150 DP2 |
151 DP3 => DP);
152 end To_Display_Type;
153
154 procedure Configure_FDI_Link
155 (Port_Cfg : in out Port_Config;
156 Success : out Boolean)
Nico Huber47ff0692016-11-04 14:29:39 +0100157 with
158 Post => Port_Cfg.Mode = Port_Cfg.Mode'Old
Nico Huber83693c82016-10-08 22:17:55 +0200159 is
160 procedure Limit_Lane_Count
161 is
162 FDI_TX_CTL_FDI_TX_ENABLE : constant := 1 * 2 ** 31;
163 Enabled : Boolean;
164 begin
165 -- if DIGI_D enabled: (FDI names are off by one)
166 Registers.Is_Set_Mask
167 (Register => Registers.FDI_TX_CTL_C,
168 Mask => FDI_TX_CTL_FDI_TX_ENABLE,
169 Result => Enabled);
170 if Enabled then
171 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_2;
172 end if;
173 end Limit_Lane_Count;
174 begin
175 Port_Cfg.FDI.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
176 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count :=
177 Config.FDI_Lane_Count (Port_Cfg.Port);
178 Port_Cfg.FDI.Receiver_Caps.Enhanced_Framing := True;
179 if Config.Has_FDI_C and then Port_Cfg.Port = DIGI_C then
180 Limit_Lane_Count;
181 end if;
182 DP_Info.Preferred_Link_Setting (Port_Cfg.FDI, Port_Cfg.Mode, Success);
183 end Configure_FDI_Link;
184
Nico Huberc7a4fee2016-11-03 18:18:03 +0100185 function Validate_Config
186 (Framebuffer : Framebuffer_Type;
Nico Huberdcd274b2016-11-03 20:15:39 +0100187 Port_Cfg : Port_Config;
Nico Huber99f10f32016-11-20 00:34:05 +0100188 I : Pipe_Index)
Nico Huberc7a4fee2016-11-03 18:18:03 +0100189 return Boolean
Nico Huber47ff0692016-11-04 14:29:39 +0100190 with
191 Post =>
192 (if Validate_Config'Result then
193 Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and
194 Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible))
Nico Huberc7a4fee2016-11-03 18:18:03 +0100195 is
196 begin
197 -- No downscaling
Nico Huberdcd274b2016-11-03 20:15:39 +0100198 -- Respect maximum scalable width
Nico Huber3675db52016-11-04 16:27:29 +0100199 -- VGA plane is only allowed on the primary pipe
200 -- Only 32bpp RGB (ignored for VGA plane)
201 -- Stride must be a multiple of 64 (ignored for VGA plane)
Nico Huberc7a4fee2016-11-03 18:18:03 +0100202 return
Nico Huberdcd274b2016-11-03 20:15:39 +0100203 ((Framebuffer.Width = Pos32 (Port_Cfg.Mode.H_Visible) and
204 Framebuffer.Height = Pos32 (Port_Cfg.Mode.V_Visible)) or
205 (Framebuffer.Width <= Config.Maximum_Scalable_Width (I) and
206 Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and
207 Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible))) and
Nico Huber3675db52016-11-04 16:27:29 +0100208 (Framebuffer.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or I = Primary) and
209 (Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
210 (Framebuffer.BPC = 8 and
211 Framebuffer.Stride mod 64 = 0));
Nico Huberc7a4fee2016-11-03 18:18:03 +0100212 end Validate_Config;
213
Nico Huber83693c82016-10-08 22:17:55 +0200214 procedure Fill_Port_Config
215 (Port_Cfg : out Port_Config;
Nico Huber99f10f32016-11-20 00:34:05 +0100216 Configs : in Pipe_Configs;
217 Idx : in Pipe_Index;
Nico Huber83693c82016-10-08 22:17:55 +0200218 Success : out Boolean)
219 with Pre => True
220 is
221 begin
222 Success :=
223 Config.Supported_Pipe (Idx) and then
224 Config.Valid_Port (Configs (Idx).Port) and then
225 Configs (Idx).Port /= Disabled;
226
227 if Success then
228 declare
229 Port : constant Port_Type := Configs (Idx).Port;
230 Mode : constant Mode_Type := Configs (Idx).Mode;
231 Link : constant DP_Link := DP_Links (Idx);
232 begin
233 Port_Cfg := Port_Config'
234 (Port => To_GPU_Port (Configs, Idx),
235 PCH_Port => To_PCH_Port (Port),
236 Display => To_Display_Type (Port),
237 Mode => Mode,
238 Is_FDI => Config.FDI_Port (To_GPU_Port (Configs, Idx)),
239 FDI => Default_DP,
240 DP => Link);
241 if Port_Cfg.Mode.BPC = Auto_BPC then
242 Port_Cfg.Mode.BPC := Connector_Info.Default_BPC (Port_Cfg);
243 end if;
Nico Huber74ec9622016-11-19 03:00:43 +0100244 if Port_Cfg.Display = HDMI then
245 declare
246 pragma Assert (Config.HDMI_Max_Clock_24bpp * 8
247 / Port_Cfg.Mode.BPC >= Frequency_Type'First);
248 Max_Dotclock : constant Frequency_Type :=
249 Config.HDMI_Max_Clock_24bpp * 8 / Port_Cfg.Mode.BPC;
250 begin
251 if Port_Cfg.Mode.Dotclock > Max_Dotclock then
252 pragma Debug (Debug.Put ("Dotclock "));
253 pragma Debug (Debug.Put_Int64 (Port_Cfg.Mode.Dotclock));
254 pragma Debug (Debug.Put (" too high, limiting to "));
255 pragma Debug (Debug.Put_Int64 (Max_Dotclock));
256 pragma Debug (Debug.Put_Line ("."));
257 Port_Cfg.Mode.Dotclock := Max_Dotclock;
258 end if;
259 end;
260 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200261 end;
262 else
263 Port_Cfg := Port_Config'
264 (Port => GPU_Port'First,
265 PCH_Port => PCH_Port'First,
266 Display => Display_Type'First,
267 Mode => Invalid_Mode,
268 Is_FDI => False,
269 FDI => Default_DP,
270 DP => Default_DP);
271 end if;
272 end Fill_Port_Config;
273
274 ----------------------------------------------------------------------------
275
276 function To_Controller
Nico Huber99f10f32016-11-20 00:34:05 +0100277 (Dsp_Config : Pipe_Index) return Display_Controller.Controller_Type
Nico Huber83693c82016-10-08 22:17:55 +0200278 is
279 Result : Display_Controller.Controller_Type;
280 begin
281 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
282
283 case Dsp_Config is
284 when Primary =>
285 Result := Display_Controller.Controllers (Display_Controller.A);
286 when Secondary =>
287 Result := Display_Controller.Controllers (Display_Controller.B);
288 when Tertiary =>
289 Result := Display_Controller.Controllers (Display_Controller.C);
290 end case;
291 return Result;
292 end To_Controller;
293
294 ----------------------------------------------------------------------------
295
296 function To_Head
Nico Huber99f10f32016-11-20 00:34:05 +0100297 (N_Config : Pipe_Index;
Nico Huber83693c82016-10-08 22:17:55 +0200298 Port : Active_Port_Type)
299 return Display_Controller.Head_Type
300 is
301 Result : Display_Controller.Head_Type;
302 begin
303 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
304
305 if Config.Has_EDP_Pipe and then Port = Internal then
306 Result := Display_Controller.Heads (Display_Controller.Head_EDP);
307 else
308 case N_Config is
309 when Primary =>
310 Result := Display_Controller.Heads (Display_Controller.Head_A);
311 when Secondary =>
312 Result := Display_Controller.Heads (Display_Controller.Head_B);
313 when Tertiary =>
314 Result := Display_Controller.Heads (Display_Controller.Head_C);
315 end case;
316 end if;
317 return Result;
318 end To_Head;
319
320 ----------------------------------------------------------------------------
321
322 procedure Legacy_VGA_Off
323 is
324 Reg8 : Word8;
325 begin
326 -- disable legacy VGA plane, taking over control now
327 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
328 Port_IO.InB (Reg8, VGA_SR_DATA);
329 Port_IO.OutB (VGA_SR_DATA, Reg8 or 1 * 2 ** 5);
330 Time.U_Delay (100); -- PRM says 100us, Linux does 300
331 Registers.Set_Mask (Registers.VGACNTRL, 1 * 2 ** 31);
332 end Legacy_VGA_Off;
333
334 ----------------------------------------------------------------------------
335
336 function Port_Configured
Nico Huber99f10f32016-11-20 00:34:05 +0100337 (Configs : Pipe_Configs;
Nico Huber83693c82016-10-08 22:17:55 +0200338 Port : Port_Type)
339 return Boolean
340 with
341 Global => null
342 is
343 begin
344 return Configs (Primary).Port = Port or
345 Configs (Secondary).Port = Port or
346 Configs (Tertiary).Port = Port;
347 end Port_Configured;
348
Nico Huber995436b2016-11-20 02:21:51 +0100349 procedure Read_EDID
350 (Raw_EDID : out EDID.Raw_EDID_Data;
351 Port : in Active_Port_Type;
352 Success : out Boolean)
353 with
354 Post => (if Success then EDID.Valid (Raw_EDID))
355 is
356 Raw_EDID_Length : GFX.I2C.Transfer_Length := Raw_EDID'Length;
357 begin
358 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
359
360 for I in 1 .. 2 loop
361 if To_Display_Type (Port) = DP then
Nico Huber1b2c9a32016-11-20 03:42:08 +0100362 -- May need power to read edid
363 declare
364 Temp_Configs : Pipe_Configs := Cur_Configs;
365 begin
366 Temp_Configs (Primary).Port := Port;
367 Power_And_Clocks.Power_Up (Cur_Configs, Temp_Configs);
368 end;
369
Nico Huber995436b2016-11-20 02:21:51 +0100370 declare
371 DP_Port : constant GMA.DP_Port :=
372 (case Port is
373 when Internal => DP_A,
374 when DP1 => DP_B,
375 when DP2 => DP_C,
376 when DP3 => DP_D,
377 when others => GMA.DP_Port'First);
378 begin
379 DP_Aux_Ch.I2C_Read
380 (Port => DP_Port,
381 Address => 16#50#,
382 Length => Raw_EDID_Length,
383 Data => Raw_EDID,
384 Success => Success);
385 end;
386 else
387 I2C.I2C_Read
388 (Port => (if Port = Analog
389 then Config.Analog_I2C_Port
390 else To_PCH_Port (Port)),
391 Address => 16#50#,
392 Length => Raw_EDID_Length,
393 Data => Raw_EDID,
394 Success => Success);
395 end if;
396 exit when not Success; -- don't retry if reading itself failed
397
398 pragma Debug (Debug.Put_Buffer ("EDID", Raw_EDID, Raw_EDID_Length));
399 EDID.Sanitize (Raw_EDID, Success);
400 exit when Success;
401 end loop;
402 end Read_EDID;
403
Nico Huber1b2c9a32016-11-20 03:42:08 +0100404 procedure Probe_Port
405 (Pipe_Cfg : in out Pipe_Config;
406 Port : in Active_Port_Type;
407 Success : out Boolean)
Nico Huber83693c82016-10-08 22:17:55 +0200408 is
409 Raw_EDID : EDID.Raw_EDID_Data := (others => 16#00#);
Nico Huber1b2c9a32016-11-20 03:42:08 +0100410 begin
411 Success := Config.Valid_Port (Port);
412
413 if Success then
414 if Port = Internal then
415 Panel.On;
416 end if;
417 Read_EDID (Raw_EDID, Port, Success);
418 end if;
419
420 if Success and then
421 (EDID.Compatible_Display (Raw_EDID, To_Display_Type (Port)) and
422 EDID.Has_Preferred_Mode (Raw_EDID))
423 then
424 Pipe_Cfg.Port := Port;
425 Pipe_Cfg.Mode := EDID.Preferred_Mode (Raw_EDID);
426 else
427 Success := False;
428 if Port = Internal then
429 Panel.Off;
430 end if;
431 end if;
432 end Probe_Port;
433
434 procedure Scan_Ports
435 (Configs : out Pipe_Configs;
436 Ports : in Port_List;
437 Max_Pipe : in Pipe_Index := Pipe_Index'Last)
438 is
Nico Huber83693c82016-10-08 22:17:55 +0200439 Port_Idx : Port_List_Range := Port_List_Range'First;
Nico Huber1b2c9a32016-11-20 03:42:08 +0100440 Success : Boolean;
Nico Huber83693c82016-10-08 22:17:55 +0200441 begin
Nico Huber99f10f32016-11-20 00:34:05 +0100442 Configs := (Pipe_Index =>
Nico Huber83693c82016-10-08 22:17:55 +0200443 (Port => Disabled,
444 Mode => Invalid_Mode,
445 Framebuffer => Default_FB));
446
Nico Huber1b2c9a32016-11-20 03:42:08 +0100447 for Pipe in Pipe_Index range
448 Pipe_Index'First .. Pipe_Index'Min (Max_Pipe, Config.Max_Pipe)
449 loop
Nico Huber83693c82016-10-08 22:17:55 +0200450 while Ports (Port_Idx) /= Disabled loop
451 if not Port_Configured (Configs, Ports (Port_Idx)) then
Nico Huber1b2c9a32016-11-20 03:42:08 +0100452 Probe_Port (Configs (Pipe), Ports (Port_Idx), Success);
453 else
454 Success := False;
Nico Huber83693c82016-10-08 22:17:55 +0200455 end if;
456
457 exit when Port_Idx = Port_List_Range'Last;
458 Port_Idx := Port_List_Range'Succ (Port_Idx);
459
460 exit when Success;
461 end loop;
462 end loop;
463
Nico Huber1b2c9a32016-11-20 03:42:08 +0100464 -- Restore power settings
Nico Huber83693c82016-10-08 22:17:55 +0200465 Power_And_Clocks.Power_Set_To (Cur_Configs);
466 end Scan_Ports;
467
Nico Huber83693c82016-10-08 22:17:55 +0200468 ----------------------------------------------------------------------------
469
Nico Huber99f10f32016-11-20 00:34:05 +0100470 procedure Update_Outputs (Configs : Pipe_Configs)
Nico Huber83693c82016-10-08 22:17:55 +0200471 is
472 Did_Power_Up : Boolean := False;
473
474 HPD, HPD_Delay_Over, Success : Boolean;
Nico Huber99f10f32016-11-20 00:34:05 +0100475 Old_Config, New_Config : Pipe_Config;
476 Old_Configs : Pipe_Configs;
Nico Huber83693c82016-10-08 22:17:55 +0200477 Port_Cfg : Port_Config;
478
479 procedure Check_HPD
480 (Port_Cfg : in Port_Config;
481 Port : in Port_Type;
482 Detected : out Boolean)
483 is
484 begin
485 HPD_Delay_Over := Time.Timed_Out (HPD_Delay (Port));
486 if HPD_Delay_Over then
487 Port_Detect.Hotplug_Detect (Port_Cfg, Detected);
488 HPD_Delay (Port) := Time.MS_From_Now (333);
489 else
490 Detected := False;
491 end if;
492 end Check_HPD;
493 begin
494 Old_Configs := Cur_Configs;
495
Nico Huber99f10f32016-11-20 00:34:05 +0100496 for I in Pipe_Index loop
Nico Huber83693c82016-10-08 22:17:55 +0200497 HPD := False;
498
499 Old_Config := Cur_Configs (I);
500 New_Config := Configs (I);
501
502 Fill_Port_Config (Port_Cfg, Old_Configs, I, Success);
503 if Success then
504 Check_HPD (Port_Cfg, Old_Config.Port, HPD);
505 end if;
506
507 -- Connector changed?
508 if (Success and then HPD) or
509 Old_Config.Port /= New_Config.Port or
510 Old_Config.Mode /= New_Config.Mode
511 then
512 if Old_Config.Port /= Disabled then
513 if Success then
514 pragma Debug (Debug.New_Line);
515 pragma Debug (Debug.Put_Line
516 ("Disabling port " & Port_Names (Old_Config.Port)));
517
518 Connectors.Pre_Off (Port_Cfg);
519
520 Display_Controller.Off
521 (To_Controller (I), To_Head (I, Old_Config.Port));
522
523 Connectors.Post_Off (Port_Cfg);
524 end if;
525
526 -- Free PLL
527 PLLs.Free (Allocated_PLLs (I));
528
529 Cur_Configs (I).Port := Disabled;
530 end if;
531
532 if New_Config.Port /= Disabled then
533 Fill_Port_Config (Port_Cfg, Configs, I, Success);
534
Nico Huberc7a4fee2016-11-03 18:18:03 +0100535 Success := Success and then
Nico Huberdcd274b2016-11-03 20:15:39 +0100536 Validate_Config (New_Config.Framebuffer, Port_Cfg, I);
Nico Huberc7a4fee2016-11-03 18:18:03 +0100537
Nico Huber83693c82016-10-08 22:17:55 +0200538 if Success and then Wait_For_HPD (New_Config.Port) then
539 Check_HPD (Port_Cfg, New_Config.Port, Success);
540 Wait_For_HPD (New_Config.Port) := not Success;
541 end if;
542
543 if Success then
544 pragma Debug (Debug.New_Line);
545 pragma Debug (Debug.Put_Line
546 ("Trying to enable port " & Port_Names (New_Config.Port)));
547
548 if not Did_Power_Up then
549 Power_And_Clocks.Power_Up (Old_Configs, Configs);
550 Did_Power_Up := True;
551 end if;
552
553 if Port_Cfg.Is_FDI then
554 Configure_FDI_Link (Port_Cfg, Success);
555 end if;
556 end if;
557
558 if Success then
559 Connector_Info.Preferred_Link_Setting
560 (Port_Cfg => Port_Cfg,
561 Success => Success);
562 end if;
563
564 while Success loop
Nico Huber47ff0692016-11-04 14:29:39 +0100565 pragma Loop_Invariant
566 (New_Config.Port in Active_Port_Type and
567 Port_Cfg.Mode = Port_Cfg.Mode'Loop_Entry);
Nico Huber83693c82016-10-08 22:17:55 +0200568
569 PLLs.Alloc
570 (Port_Cfg => Port_Cfg,
571 PLL => Allocated_PLLs (I),
572 Success => Success);
573
574 if Success then
575 for Try in 1 .. 2 loop
576 pragma Loop_Invariant
577 (New_Config.Port in Active_Port_Type);
578
579 Connectors.Pre_On
580 (Port_Cfg => Port_Cfg,
581 PLL_Hint => PLLs.Register_Value
582 (Allocated_PLLs (I)),
583 Pipe_Hint => Display_Controller.Get_Pipe_Hint
584 (To_Head (I, New_Config.Port)),
585 Success => Success);
586
587 if Success then
588 Display_Controller.On
589 (Controller => To_Controller (I),
590 Head => To_Head (I, New_Config.Port),
591 Port_Cfg => Port_Cfg,
592 Framebuffer => New_Config.Framebuffer);
593
594 Connectors.Post_On
595 (Port_Cfg => Port_Cfg,
596 PLL_Hint => PLLs.Register_Value
597 (Allocated_PLLs (I)),
598 Success => Success);
599
600 if not Success then
601 Display_Controller.Off
602 (To_Controller (I),
603 To_Head (I, New_Config.Port));
604 Connectors.Post_Off (Port_Cfg);
605 end if;
606 end if;
607
608 exit when Success;
609 end loop;
610 exit when Success; -- connection established => stop loop
611
612 -- connection failed
613 PLLs.Free (Allocated_PLLs (I));
614 end if;
615
616 Connector_Info.Next_Link_Setting
617 (Port_Cfg => Port_Cfg,
618 Success => Success);
619 end loop;
620
621 if Success then
622 pragma Debug (Debug.Put_Line
623 ("Enabled port " & Port_Names (New_Config.Port)));
624 Cur_Configs (I) := New_Config;
625 DP_Links (I) := Port_Cfg.DP;
626 else
627 Wait_For_HPD (New_Config.Port) := True;
628 if New_Config.Port = Internal then
629 Panel.Off;
630 end if;
631 end if;
632 else
633 Cur_Configs (I) := New_Config;
634 end if;
635 elsif Old_Config.Framebuffer /= New_Config.Framebuffer and
636 Old_Config.Port /= Disabled
637 then
638 Display_Controller.Update_Offset
639 (Controller => To_Controller (I),
640 Framebuffer => New_Config.Framebuffer);
641 Cur_Configs (I) := New_Config;
642 end if;
643 end loop;
644
645 if Did_Power_Up then
646 Power_And_Clocks.Power_Down (Old_Configs, Configs, Cur_Configs);
647 end if;
648
649 end Update_Outputs;
650
651 ----------------------------------------------------------------------------
652
653 procedure Initialize
654 (MMIO_Base : in Word64 := 0;
655 Write_Delay : in Word64 := 0;
656 Success : out Boolean)
657 with
658 Refined_Global =>
659 (In_Out =>
660 (Config.Valid_Port_GPU,
661 Registers.Register_State, Port_IO.State),
662 Input =>
663 (Time.State),
664 Output =>
665 (Registers.Address_State,
666 PLLs.State, Panel.Panel_State,
667 Cur_Configs, Allocated_PLLs, DP_Links,
668 HPD_Delay, Wait_For_HPD, Initialized))
669 is
670 use type HW.Word64;
671
672 Now : constant Time.T := Time.Now;
673
674 procedure Check_Platform (Success : out Boolean)
675 is
676 Audio_VID_DID : Word32;
677 begin
678 case Config.CPU is
679 when Haswell .. Skylake =>
680 Registers.Read (Registers.AUD_VID_DID, Audio_VID_DID);
681 when Ironlake .. Ivybridge =>
682 Registers.Read (Registers.PCH_AUD_VID_DID, Audio_VID_DID);
683 end case;
684 Success :=
685 (case Config.CPU is
686 when Skylake => Audio_VID_DID = 16#8086_2809#,
687 when Broadwell => Audio_VID_DID = 16#8086_2808#,
688 when Haswell => Audio_VID_DID = 16#8086_2807#,
689 when Ivybridge |
690 Sandybridge => Audio_VID_DID = 16#8086_2806# or
691 Audio_VID_DID = 16#8086_2805#,
Nico Hubereeb5a392016-10-09 19:28:30 +0200692 when Ironlake => Audio_VID_DID = 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200693 end Check_Platform;
694 begin
695 pragma Warnings (GNATprove, Off, "unused variable ""Write_Delay""",
696 Reason => "Write_Delay is used for debugging only");
697
698 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
699
700 pragma Debug (Debug.Set_Register_Write_Delay (Write_Delay));
701
702 Wait_For_HPD := HPD_Type'(others => False);
703 HPD_Delay := HPD_Delay_Type'(others => Now);
704 DP_Links := Links_Type'(others => HW.GFX.Default_DP);
705 Allocated_PLLs := (others => PLLs.Invalid);
Nico Huber99f10f32016-11-20 00:34:05 +0100706 Cur_Configs := Pipe_Configs'
707 (others => Pipe_Config'
Nico Huber83693c82016-10-08 22:17:55 +0200708 (Port => Disabled,
709 Framebuffer => HW.GFX.Default_FB,
710 Mode => HW.GFX.Invalid_Mode));
711 Registers.Set_Register_Base
712 (if MMIO_Base /= 0 then
713 MMIO_Base
714 else
715 Config.Default_MMIO_Base);
716 PLLs.Initialize;
717
718 Check_Platform (Success);
719 if not Success then
720 pragma Debug (Debug.Put_Line ("ERROR: Incompatible CPU or PCH."));
721
722 Panel.Static_Init; -- for flow analysis
723
724 Initialized := False;
725 return;
726 end if;
727
728 Panel.Setup_PP_Sequencer;
729 Port_Detect.Initialize;
730
731 Power_And_Clocks.Pre_All_Off;
732
733 Legacy_VGA_Off;
734
735 Connectors.Pre_All_Off;
736 Display_Controller.All_Off;
737 Connectors.Post_All_Off;
738 PLLs.All_Off;
739
740 Power_And_Clocks.Post_All_Off;
741
742 -------------------- Now restart from a clean state ---------------------
743 Power_And_Clocks.Initialize;
744
Nico Huberf54d0962016-10-20 14:17:18 +0200745 Registers.Unset_And_Set_Mask
746 (Register => Registers.PCH_RAWCLK_FREQ,
747 Mask_Unset => PCH_RAWCLK_FREQ_MASK,
748 Mask_Set => PCH_RAWCLK_FREQ (Config.Default_RawClk_Freq));
749
Nico Huber83693c82016-10-08 22:17:55 +0200750 Initialized := True;
751
752 end Initialize;
753
754 function Is_Initialized return Boolean
755 with
756 Refined_Post => Is_Initialized'Result = Initialized
757 is
758 begin
759 return Initialized;
760 end Is_Initialized;
761
762 ----------------------------------------------------------------------------
763
764 procedure Write_GTT
765 (GTT_Page : GTT_Range;
766 Device_Address : GTT_Address_Type;
767 Valid : Boolean) is
768 begin
769 Registers.Write_GTT (GTT_Page, Device_Address, Valid);
770 end Write_GTT;
771
772 procedure Setup_Default_GTT (FB : Framebuffer_Type; Phys_FB : Word32)
773 is
774 FB_Size : constant Pos32 :=
775 FB.Stride * FB.Height * Pos32 (((FB.BPC * 4) / 8));
776 Phys_Addr : GTT_Address_Type := GTT_Address_Type (Phys_FB);
777 begin
778 for Idx in GTT_Range range 0 .. GTT_Range (((FB_Size + 4095) / 4096) - 1)
779 loop
780 Registers.Write_GTT
781 (GTT_Page => Idx,
782 Device_Address => Phys_Addr,
783 Valid => True);
784 Phys_Addr := Phys_Addr + 4096;
785 end loop;
786 end Setup_Default_GTT;
787
788 ----------------------------------------------------------------------------
789
Nico Huber99f10f32016-11-20 00:34:05 +0100790 procedure Dump_Configs (Configs : Pipe_Configs)
Nico Huber83693c82016-10-08 22:17:55 +0200791 is
792 subtype Pipe_Name is String (1 .. 9);
Nico Huber99f10f32016-11-20 00:34:05 +0100793 type Pipe_Name_Array is array (Pipe_Index) of Pipe_Name;
Nico Huber83693c82016-10-08 22:17:55 +0200794 Pipe_Names : constant Pipe_Name_Array :=
795 (Primary => "Primary ",
796 Secondary => "Secondary",
797 Tertiary => "Tertiary ");
798 begin
799 Debug.New_Line;
800 Debug.Put_Line ("CONFIG => ");
Nico Huber99f10f32016-11-20 00:34:05 +0100801 for Pipe in Pipe_Index loop
802 if Pipe = Pipe_Index'First then
Nico Huber83693c82016-10-08 22:17:55 +0200803 Debug.Put (" (");
804 else
805 Debug.Put (" ");
806 end if;
807 Debug.Put_Line (Pipe_Names (Pipe) & " =>");
808 Debug.Put_Line
809 (" (Port => " & Port_Names (Configs (Pipe).Port) & ",");
810 Debug.Put_Line (" Framebuffer =>");
811 Debug.Put (" (Width => ");
812 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Width);
813 Debug.Put_Line (",");
814 Debug.Put (" Height => ");
815 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Height);
816 Debug.Put_Line (",");
817 Debug.Put (" Stride => ");
818 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Stride);
819 Debug.Put_Line (",");
820 Debug.Put (" Offset => ");
821 Debug.Put_Word32 (Configs (Pipe).Framebuffer.Offset);
822 Debug.Put_Line (",");
823 Debug.Put (" BPC => ");
824 Debug.Put_Int64 (Configs (Pipe).Framebuffer.BPC);
825 Debug.Put_Line ("),");
826 Debug.Put_Line (" Mode =>");
827 Debug.Put (" (Dotclock => ");
828 Debug.Put_Int64 (Configs (Pipe).Mode.Dotclock);
829 Debug.Put_Line (",");
830 Debug.Put (" H_Visible => ");
831 Debug.Put_Int16 (Configs (Pipe).Mode.H_Visible);
832 Debug.Put_Line (",");
833 Debug.Put (" H_Sync_Begin => ");
834 Debug.Put_Int16 (Configs (Pipe).Mode.H_Sync_Begin);
835 Debug.Put_Line (",");
836 Debug.Put (" H_Sync_End => ");
837 Debug.Put_Int16 (Configs (Pipe).Mode.H_Sync_End);
838 Debug.Put_Line (",");
839 Debug.Put (" H_Total => ");
840 Debug.Put_Int16 (Configs (Pipe).Mode.H_Total);
841 Debug.Put_Line (",");
842 Debug.Put (" V_Visible => ");
843 Debug.Put_Int16 (Configs (Pipe).Mode.V_Visible);
844 Debug.Put_Line (",");
845 Debug.Put (" V_Sync_Begin => ");
846 Debug.Put_Int16 (Configs (Pipe).Mode.V_Sync_Begin);
847 Debug.Put_Line (",");
848 Debug.Put (" V_Sync_End => ");
849 Debug.Put_Int16 (Configs (Pipe).Mode.V_Sync_End);
850 Debug.Put_Line (",");
851 Debug.Put (" V_Total => ");
852 Debug.Put_Int16 (Configs (Pipe).Mode.V_Total);
853 Debug.Put_Line (",");
854 Debug.Put_Line (" H_Sync_Active_High => " &
855 (if Configs (Pipe).Mode.H_Sync_Active_High
856 then "True,"
857 else "False,"));
858 Debug.Put_Line (" V_Sync_Active_High => " &
859 (if Configs (Pipe).Mode.V_Sync_Active_High
860 then "True,"
861 else "False,"));
862 Debug.Put (" BPC => ");
863 Debug.Put_Int64 (Configs (Pipe).Mode.BPC);
Nico Huber99f10f32016-11-20 00:34:05 +0100864 if Pipe /= Pipe_Index'Last then
Nico Huber83693c82016-10-08 22:17:55 +0200865 Debug.Put_Line (")),");
866 else
867 Debug.Put_Line (")));");
868 end if;
869 end loop;
870 end Dump_Configs;
871
872end HW.GFX.GMA;