blob: e72bbedadbde8bcdf7ec0dfa9eb393d2d3d215fe [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
362 declare
363 DP_Port : constant GMA.DP_Port :=
364 (case Port is
365 when Internal => DP_A,
366 when DP1 => DP_B,
367 when DP2 => DP_C,
368 when DP3 => DP_D,
369 when others => GMA.DP_Port'First);
370 begin
371 DP_Aux_Ch.I2C_Read
372 (Port => DP_Port,
373 Address => 16#50#,
374 Length => Raw_EDID_Length,
375 Data => Raw_EDID,
376 Success => Success);
377 end;
378 else
379 I2C.I2C_Read
380 (Port => (if Port = Analog
381 then Config.Analog_I2C_Port
382 else To_PCH_Port (Port)),
383 Address => 16#50#,
384 Length => Raw_EDID_Length,
385 Data => Raw_EDID,
386 Success => Success);
387 end if;
388 exit when not Success; -- don't retry if reading itself failed
389
390 pragma Debug (Debug.Put_Buffer ("EDID", Raw_EDID, Raw_EDID_Length));
391 EDID.Sanitize (Raw_EDID, Success);
392 exit when Success;
393 end loop;
394 end Read_EDID;
395
Nico Huber83693c82016-10-08 22:17:55 +0200396 procedure Scan_Ports
Nico Huber99f10f32016-11-20 00:34:05 +0100397 (Configs : out Pipe_Configs;
Nico Huberaa91bb52016-11-07 12:51:20 +0100398 Ports : in Port_List;
Nico Huber99f10f32016-11-20 00:34:05 +0100399 Max_Pipe : in Pipe_Index := Pipe_Index'Last)
Nico Huber83693c82016-10-08 22:17:55 +0200400 is
401 Raw_EDID : EDID.Raw_EDID_Data := (others => 16#00#);
402 Port_Idx : Port_List_Range := Port_List_Range'First;
403 Port_Cfg : Port_Config;
404 Success : Boolean := False;
405 begin
Nico Huber99f10f32016-11-20 00:34:05 +0100406 Configs := (Pipe_Index =>
Nico Huber83693c82016-10-08 22:17:55 +0200407 (Port => Disabled,
408 Mode => Invalid_Mode,
409 Framebuffer => Default_FB));
410
Nico Huber99f10f32016-11-20 00:34:05 +0100411 for Config_Idx in Pipe_Index range Pipe_Index'First .. Max_Pipe loop
Nico Huber83693c82016-10-08 22:17:55 +0200412 while Ports (Port_Idx) /= Disabled loop
413 if not Port_Configured (Configs, Ports (Port_Idx)) then
414 Configs (Config_Idx).Port := Ports (Port_Idx);
415 Fill_Port_Config (Port_Cfg, Configs, Config_Idx, Success);
416
417 if Success then
418 -- May need power to probe port
419 if Port_Cfg.Display = DP then
420 Power_And_Clocks.Power_Up (Cur_Configs, Configs);
421 end if;
422 if Ports (Port_Idx) = Internal then
423 Panel.On;
424 end if;
425
Nico Huber995436b2016-11-20 02:21:51 +0100426 Read_EDID (Raw_EDID, Ports (Port_Idx), Success);
Nico Huber83693c82016-10-08 22:17:55 +0200427 end if;
428
Nico Huber393aa8a2016-10-21 14:18:53 +0200429 if Success and then
430 (EDID.Compatible_Display (Raw_EDID, Port_Cfg.Display) and
431 EDID.Has_Preferred_Mode (Raw_EDID))
432 then
Nico Huber83693c82016-10-08 22:17:55 +0200433 Configs (Config_Idx).Mode := EDID.Preferred_Mode (Raw_EDID);
434 else
435 Configs (Config_Idx).Port := Disabled;
Nico Huber6a356672016-10-21 15:13:55 +0200436 Success := False;
Nico Huber83693c82016-10-08 22:17:55 +0200437
438 if Ports (Port_Idx) = Internal and
439 not Port_Configured (Cur_Configs, Internal)
440 then
441 Panel.Off;
442 end if;
443 end if;
444 end if;
445
446 exit when Port_Idx = Port_List_Range'Last;
447 Port_Idx := Port_List_Range'Succ (Port_Idx);
448
449 exit when Success;
450 end loop;
451 end loop;
452
453 Power_And_Clocks.Power_Set_To (Cur_Configs);
454 end Scan_Ports;
455
Nico Huber83693c82016-10-08 22:17:55 +0200456 ----------------------------------------------------------------------------
457
Nico Huber99f10f32016-11-20 00:34:05 +0100458 procedure Update_Outputs (Configs : Pipe_Configs)
Nico Huber83693c82016-10-08 22:17:55 +0200459 is
460 Did_Power_Up : Boolean := False;
461
462 HPD, HPD_Delay_Over, Success : Boolean;
Nico Huber99f10f32016-11-20 00:34:05 +0100463 Old_Config, New_Config : Pipe_Config;
464 Old_Configs : Pipe_Configs;
Nico Huber83693c82016-10-08 22:17:55 +0200465 Port_Cfg : Port_Config;
466
467 procedure Check_HPD
468 (Port_Cfg : in Port_Config;
469 Port : in Port_Type;
470 Detected : out Boolean)
471 is
472 begin
473 HPD_Delay_Over := Time.Timed_Out (HPD_Delay (Port));
474 if HPD_Delay_Over then
475 Port_Detect.Hotplug_Detect (Port_Cfg, Detected);
476 HPD_Delay (Port) := Time.MS_From_Now (333);
477 else
478 Detected := False;
479 end if;
480 end Check_HPD;
481 begin
482 Old_Configs := Cur_Configs;
483
Nico Huber99f10f32016-11-20 00:34:05 +0100484 for I in Pipe_Index loop
Nico Huber83693c82016-10-08 22:17:55 +0200485 HPD := False;
486
487 Old_Config := Cur_Configs (I);
488 New_Config := Configs (I);
489
490 Fill_Port_Config (Port_Cfg, Old_Configs, I, Success);
491 if Success then
492 Check_HPD (Port_Cfg, Old_Config.Port, HPD);
493 end if;
494
495 -- Connector changed?
496 if (Success and then HPD) or
497 Old_Config.Port /= New_Config.Port or
498 Old_Config.Mode /= New_Config.Mode
499 then
500 if Old_Config.Port /= Disabled then
501 if Success then
502 pragma Debug (Debug.New_Line);
503 pragma Debug (Debug.Put_Line
504 ("Disabling port " & Port_Names (Old_Config.Port)));
505
506 Connectors.Pre_Off (Port_Cfg);
507
508 Display_Controller.Off
509 (To_Controller (I), To_Head (I, Old_Config.Port));
510
511 Connectors.Post_Off (Port_Cfg);
512 end if;
513
514 -- Free PLL
515 PLLs.Free (Allocated_PLLs (I));
516
517 Cur_Configs (I).Port := Disabled;
518 end if;
519
520 if New_Config.Port /= Disabled then
521 Fill_Port_Config (Port_Cfg, Configs, I, Success);
522
Nico Huberc7a4fee2016-11-03 18:18:03 +0100523 Success := Success and then
Nico Huberdcd274b2016-11-03 20:15:39 +0100524 Validate_Config (New_Config.Framebuffer, Port_Cfg, I);
Nico Huberc7a4fee2016-11-03 18:18:03 +0100525
Nico Huber83693c82016-10-08 22:17:55 +0200526 if Success and then Wait_For_HPD (New_Config.Port) then
527 Check_HPD (Port_Cfg, New_Config.Port, Success);
528 Wait_For_HPD (New_Config.Port) := not Success;
529 end if;
530
531 if Success then
532 pragma Debug (Debug.New_Line);
533 pragma Debug (Debug.Put_Line
534 ("Trying to enable port " & Port_Names (New_Config.Port)));
535
536 if not Did_Power_Up then
537 Power_And_Clocks.Power_Up (Old_Configs, Configs);
538 Did_Power_Up := True;
539 end if;
540
541 if Port_Cfg.Is_FDI then
542 Configure_FDI_Link (Port_Cfg, Success);
543 end if;
544 end if;
545
546 if Success then
547 Connector_Info.Preferred_Link_Setting
548 (Port_Cfg => Port_Cfg,
549 Success => Success);
550 end if;
551
552 while Success loop
Nico Huber47ff0692016-11-04 14:29:39 +0100553 pragma Loop_Invariant
554 (New_Config.Port in Active_Port_Type and
555 Port_Cfg.Mode = Port_Cfg.Mode'Loop_Entry);
Nico Huber83693c82016-10-08 22:17:55 +0200556
557 PLLs.Alloc
558 (Port_Cfg => Port_Cfg,
559 PLL => Allocated_PLLs (I),
560 Success => Success);
561
562 if Success then
563 for Try in 1 .. 2 loop
564 pragma Loop_Invariant
565 (New_Config.Port in Active_Port_Type);
566
567 Connectors.Pre_On
568 (Port_Cfg => Port_Cfg,
569 PLL_Hint => PLLs.Register_Value
570 (Allocated_PLLs (I)),
571 Pipe_Hint => Display_Controller.Get_Pipe_Hint
572 (To_Head (I, New_Config.Port)),
573 Success => Success);
574
575 if Success then
576 Display_Controller.On
577 (Controller => To_Controller (I),
578 Head => To_Head (I, New_Config.Port),
579 Port_Cfg => Port_Cfg,
580 Framebuffer => New_Config.Framebuffer);
581
582 Connectors.Post_On
583 (Port_Cfg => Port_Cfg,
584 PLL_Hint => PLLs.Register_Value
585 (Allocated_PLLs (I)),
586 Success => Success);
587
588 if not Success then
589 Display_Controller.Off
590 (To_Controller (I),
591 To_Head (I, New_Config.Port));
592 Connectors.Post_Off (Port_Cfg);
593 end if;
594 end if;
595
596 exit when Success;
597 end loop;
598 exit when Success; -- connection established => stop loop
599
600 -- connection failed
601 PLLs.Free (Allocated_PLLs (I));
602 end if;
603
604 Connector_Info.Next_Link_Setting
605 (Port_Cfg => Port_Cfg,
606 Success => Success);
607 end loop;
608
609 if Success then
610 pragma Debug (Debug.Put_Line
611 ("Enabled port " & Port_Names (New_Config.Port)));
612 Cur_Configs (I) := New_Config;
613 DP_Links (I) := Port_Cfg.DP;
614 else
615 Wait_For_HPD (New_Config.Port) := True;
616 if New_Config.Port = Internal then
617 Panel.Off;
618 end if;
619 end if;
620 else
621 Cur_Configs (I) := New_Config;
622 end if;
623 elsif Old_Config.Framebuffer /= New_Config.Framebuffer and
624 Old_Config.Port /= Disabled
625 then
626 Display_Controller.Update_Offset
627 (Controller => To_Controller (I),
628 Framebuffer => New_Config.Framebuffer);
629 Cur_Configs (I) := New_Config;
630 end if;
631 end loop;
632
633 if Did_Power_Up then
634 Power_And_Clocks.Power_Down (Old_Configs, Configs, Cur_Configs);
635 end if;
636
637 end Update_Outputs;
638
639 ----------------------------------------------------------------------------
640
641 procedure Initialize
642 (MMIO_Base : in Word64 := 0;
643 Write_Delay : in Word64 := 0;
644 Success : out Boolean)
645 with
646 Refined_Global =>
647 (In_Out =>
648 (Config.Valid_Port_GPU,
649 Registers.Register_State, Port_IO.State),
650 Input =>
651 (Time.State),
652 Output =>
653 (Registers.Address_State,
654 PLLs.State, Panel.Panel_State,
655 Cur_Configs, Allocated_PLLs, DP_Links,
656 HPD_Delay, Wait_For_HPD, Initialized))
657 is
658 use type HW.Word64;
659
660 Now : constant Time.T := Time.Now;
661
662 procedure Check_Platform (Success : out Boolean)
663 is
664 Audio_VID_DID : Word32;
665 begin
666 case Config.CPU is
667 when Haswell .. Skylake =>
668 Registers.Read (Registers.AUD_VID_DID, Audio_VID_DID);
669 when Ironlake .. Ivybridge =>
670 Registers.Read (Registers.PCH_AUD_VID_DID, Audio_VID_DID);
671 end case;
672 Success :=
673 (case Config.CPU is
674 when Skylake => Audio_VID_DID = 16#8086_2809#,
675 when Broadwell => Audio_VID_DID = 16#8086_2808#,
676 when Haswell => Audio_VID_DID = 16#8086_2807#,
677 when Ivybridge |
678 Sandybridge => Audio_VID_DID = 16#8086_2806# or
679 Audio_VID_DID = 16#8086_2805#,
Nico Hubereeb5a392016-10-09 19:28:30 +0200680 when Ironlake => Audio_VID_DID = 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200681 end Check_Platform;
682 begin
683 pragma Warnings (GNATprove, Off, "unused variable ""Write_Delay""",
684 Reason => "Write_Delay is used for debugging only");
685
686 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
687
688 pragma Debug (Debug.Set_Register_Write_Delay (Write_Delay));
689
690 Wait_For_HPD := HPD_Type'(others => False);
691 HPD_Delay := HPD_Delay_Type'(others => Now);
692 DP_Links := Links_Type'(others => HW.GFX.Default_DP);
693 Allocated_PLLs := (others => PLLs.Invalid);
Nico Huber99f10f32016-11-20 00:34:05 +0100694 Cur_Configs := Pipe_Configs'
695 (others => Pipe_Config'
Nico Huber83693c82016-10-08 22:17:55 +0200696 (Port => Disabled,
697 Framebuffer => HW.GFX.Default_FB,
698 Mode => HW.GFX.Invalid_Mode));
699 Registers.Set_Register_Base
700 (if MMIO_Base /= 0 then
701 MMIO_Base
702 else
703 Config.Default_MMIO_Base);
704 PLLs.Initialize;
705
706 Check_Platform (Success);
707 if not Success then
708 pragma Debug (Debug.Put_Line ("ERROR: Incompatible CPU or PCH."));
709
710 Panel.Static_Init; -- for flow analysis
711
712 Initialized := False;
713 return;
714 end if;
715
716 Panel.Setup_PP_Sequencer;
717 Port_Detect.Initialize;
718
719 Power_And_Clocks.Pre_All_Off;
720
721 Legacy_VGA_Off;
722
723 Connectors.Pre_All_Off;
724 Display_Controller.All_Off;
725 Connectors.Post_All_Off;
726 PLLs.All_Off;
727
728 Power_And_Clocks.Post_All_Off;
729
730 -------------------- Now restart from a clean state ---------------------
731 Power_And_Clocks.Initialize;
732
Nico Huberf54d0962016-10-20 14:17:18 +0200733 Registers.Unset_And_Set_Mask
734 (Register => Registers.PCH_RAWCLK_FREQ,
735 Mask_Unset => PCH_RAWCLK_FREQ_MASK,
736 Mask_Set => PCH_RAWCLK_FREQ (Config.Default_RawClk_Freq));
737
Nico Huber83693c82016-10-08 22:17:55 +0200738 Initialized := True;
739
740 end Initialize;
741
742 function Is_Initialized return Boolean
743 with
744 Refined_Post => Is_Initialized'Result = Initialized
745 is
746 begin
747 return Initialized;
748 end Is_Initialized;
749
750 ----------------------------------------------------------------------------
751
752 procedure Write_GTT
753 (GTT_Page : GTT_Range;
754 Device_Address : GTT_Address_Type;
755 Valid : Boolean) is
756 begin
757 Registers.Write_GTT (GTT_Page, Device_Address, Valid);
758 end Write_GTT;
759
760 procedure Setup_Default_GTT (FB : Framebuffer_Type; Phys_FB : Word32)
761 is
762 FB_Size : constant Pos32 :=
763 FB.Stride * FB.Height * Pos32 (((FB.BPC * 4) / 8));
764 Phys_Addr : GTT_Address_Type := GTT_Address_Type (Phys_FB);
765 begin
766 for Idx in GTT_Range range 0 .. GTT_Range (((FB_Size + 4095) / 4096) - 1)
767 loop
768 Registers.Write_GTT
769 (GTT_Page => Idx,
770 Device_Address => Phys_Addr,
771 Valid => True);
772 Phys_Addr := Phys_Addr + 4096;
773 end loop;
774 end Setup_Default_GTT;
775
776 ----------------------------------------------------------------------------
777
Nico Huber99f10f32016-11-20 00:34:05 +0100778 procedure Dump_Configs (Configs : Pipe_Configs)
Nico Huber83693c82016-10-08 22:17:55 +0200779 is
780 subtype Pipe_Name is String (1 .. 9);
Nico Huber99f10f32016-11-20 00:34:05 +0100781 type Pipe_Name_Array is array (Pipe_Index) of Pipe_Name;
Nico Huber83693c82016-10-08 22:17:55 +0200782 Pipe_Names : constant Pipe_Name_Array :=
783 (Primary => "Primary ",
784 Secondary => "Secondary",
785 Tertiary => "Tertiary ");
786 begin
787 Debug.New_Line;
788 Debug.Put_Line ("CONFIG => ");
Nico Huber99f10f32016-11-20 00:34:05 +0100789 for Pipe in Pipe_Index loop
790 if Pipe = Pipe_Index'First then
Nico Huber83693c82016-10-08 22:17:55 +0200791 Debug.Put (" (");
792 else
793 Debug.Put (" ");
794 end if;
795 Debug.Put_Line (Pipe_Names (Pipe) & " =>");
796 Debug.Put_Line
797 (" (Port => " & Port_Names (Configs (Pipe).Port) & ",");
798 Debug.Put_Line (" Framebuffer =>");
799 Debug.Put (" (Width => ");
800 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Width);
801 Debug.Put_Line (",");
802 Debug.Put (" Height => ");
803 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Height);
804 Debug.Put_Line (",");
805 Debug.Put (" Stride => ");
806 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Stride);
807 Debug.Put_Line (",");
808 Debug.Put (" Offset => ");
809 Debug.Put_Word32 (Configs (Pipe).Framebuffer.Offset);
810 Debug.Put_Line (",");
811 Debug.Put (" BPC => ");
812 Debug.Put_Int64 (Configs (Pipe).Framebuffer.BPC);
813 Debug.Put_Line ("),");
814 Debug.Put_Line (" Mode =>");
815 Debug.Put (" (Dotclock => ");
816 Debug.Put_Int64 (Configs (Pipe).Mode.Dotclock);
817 Debug.Put_Line (",");
818 Debug.Put (" H_Visible => ");
819 Debug.Put_Int16 (Configs (Pipe).Mode.H_Visible);
820 Debug.Put_Line (",");
821 Debug.Put (" H_Sync_Begin => ");
822 Debug.Put_Int16 (Configs (Pipe).Mode.H_Sync_Begin);
823 Debug.Put_Line (",");
824 Debug.Put (" H_Sync_End => ");
825 Debug.Put_Int16 (Configs (Pipe).Mode.H_Sync_End);
826 Debug.Put_Line (",");
827 Debug.Put (" H_Total => ");
828 Debug.Put_Int16 (Configs (Pipe).Mode.H_Total);
829 Debug.Put_Line (",");
830 Debug.Put (" V_Visible => ");
831 Debug.Put_Int16 (Configs (Pipe).Mode.V_Visible);
832 Debug.Put_Line (",");
833 Debug.Put (" V_Sync_Begin => ");
834 Debug.Put_Int16 (Configs (Pipe).Mode.V_Sync_Begin);
835 Debug.Put_Line (",");
836 Debug.Put (" V_Sync_End => ");
837 Debug.Put_Int16 (Configs (Pipe).Mode.V_Sync_End);
838 Debug.Put_Line (",");
839 Debug.Put (" V_Total => ");
840 Debug.Put_Int16 (Configs (Pipe).Mode.V_Total);
841 Debug.Put_Line (",");
842 Debug.Put_Line (" H_Sync_Active_High => " &
843 (if Configs (Pipe).Mode.H_Sync_Active_High
844 then "True,"
845 else "False,"));
846 Debug.Put_Line (" V_Sync_Active_High => " &
847 (if Configs (Pipe).Mode.V_Sync_Active_High
848 then "True,"
849 else "False,"));
850 Debug.Put (" BPC => ");
851 Debug.Put_Int64 (Configs (Pipe).Mode.BPC);
Nico Huber99f10f32016-11-20 00:34:05 +0100852 if Pipe /= Pipe_Index'Last then
Nico Huber83693c82016-10-08 22:17:55 +0200853 Debug.Put_Line (")),");
854 else
855 Debug.Put_Line (")));");
856 end if;
857 end loop;
858 end Dump_Configs;
859
860end HW.GFX.GMA;