blob: f8b0e7be08748c16404534cd458d57081daee3c6 [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 ",
56 Digital1 => "Digital1",
57 Digital2 => "Digital2",
58 Digital3 => "Digital3",
59 Analog => "Analog ");
60
61 package Display_Controller renames Pipe_Setup;
62
63 type PLLs_Type is array (Config_Index) of PLLs.T;
64
65 type Links_Type is array (Config_Index) of DP_Link;
66
67 type HPD_Type is array (Port_Type) of Boolean;
68 type HPD_Delay_Type is array (Port_Type) of Time.T;
69
70 Cur_Configs : Configs_Type;
71 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
92 (Configs : Configs_Type;
93 Idx : Config_Index)
94 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
111 when Disabled => GPU_Port'First,
112 when Internal => DIGI_A, -- LVDS not available
113 when Digital1 | DP1 => DIGI_B,
114 when Digital2 | DP2 => DIGI_C,
115 when Digital3 | DP3 => DIGI_D,
116 when Analog => DIGI_E));
117 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,
126 when Digital1 => PCH_HDMI_B,
127 when Digital2 => PCH_HDMI_C,
128 when Digital3 => PCH_HDMI_D,
129 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,
142 when Digital1 |
143 Digital2 |
144 Digital3 => HDMI,
145 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;
184 I : Config_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 Huberc7a4fee2016-11-03 18:18:03 +0100195 -- Only 32bpp RGB
196 -- Stride must be a multiple of 64
197 return
Nico Huberdcd274b2016-11-03 20:15:39 +0100198 ((Framebuffer.Width = Pos32 (Port_Cfg.Mode.H_Visible) and
199 Framebuffer.Height = Pos32 (Port_Cfg.Mode.V_Visible)) or
200 (Framebuffer.Width <= Config.Maximum_Scalable_Width (I) and
201 Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and
202 Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible))) and
Nico Huberc7a4fee2016-11-03 18:18:03 +0100203 Framebuffer.BPC = 8 and
204 Framebuffer.Stride mod 64 = 0;
205 end Validate_Config;
206
Nico Huber83693c82016-10-08 22:17:55 +0200207 procedure Fill_Port_Config
208 (Port_Cfg : out Port_Config;
209 Configs : in Configs_Type;
210 Idx : in Config_Index;
211 Success : out Boolean)
212 with Pre => True
213 is
214 begin
215 Success :=
216 Config.Supported_Pipe (Idx) and then
217 Config.Valid_Port (Configs (Idx).Port) and then
218 Configs (Idx).Port /= Disabled;
219
220 if Success then
221 declare
222 Port : constant Port_Type := Configs (Idx).Port;
223 Mode : constant Mode_Type := Configs (Idx).Mode;
224 Link : constant DP_Link := DP_Links (Idx);
225 begin
226 Port_Cfg := Port_Config'
227 (Port => To_GPU_Port (Configs, Idx),
228 PCH_Port => To_PCH_Port (Port),
229 Display => To_Display_Type (Port),
230 Mode => Mode,
231 Is_FDI => Config.FDI_Port (To_GPU_Port (Configs, Idx)),
232 FDI => Default_DP,
233 DP => Link);
234 if Port_Cfg.Mode.BPC = Auto_BPC then
235 Port_Cfg.Mode.BPC := Connector_Info.Default_BPC (Port_Cfg);
236 end if;
237 end;
238 else
239 Port_Cfg := Port_Config'
240 (Port => GPU_Port'First,
241 PCH_Port => PCH_Port'First,
242 Display => Display_Type'First,
243 Mode => Invalid_Mode,
244 Is_FDI => False,
245 FDI => Default_DP,
246 DP => Default_DP);
247 end if;
248 end Fill_Port_Config;
249
250 ----------------------------------------------------------------------------
251
252 function To_Controller
253 (Dsp_Config : Config_Index) return Display_Controller.Controller_Type
254 is
255 Result : Display_Controller.Controller_Type;
256 begin
257 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
258
259 case Dsp_Config is
260 when Primary =>
261 Result := Display_Controller.Controllers (Display_Controller.A);
262 when Secondary =>
263 Result := Display_Controller.Controllers (Display_Controller.B);
264 when Tertiary =>
265 Result := Display_Controller.Controllers (Display_Controller.C);
266 end case;
267 return Result;
268 end To_Controller;
269
270 ----------------------------------------------------------------------------
271
272 function To_Head
273 (N_Config : Config_Index;
274 Port : Active_Port_Type)
275 return Display_Controller.Head_Type
276 is
277 Result : Display_Controller.Head_Type;
278 begin
279 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
280
281 if Config.Has_EDP_Pipe and then Port = Internal then
282 Result := Display_Controller.Heads (Display_Controller.Head_EDP);
283 else
284 case N_Config is
285 when Primary =>
286 Result := Display_Controller.Heads (Display_Controller.Head_A);
287 when Secondary =>
288 Result := Display_Controller.Heads (Display_Controller.Head_B);
289 when Tertiary =>
290 Result := Display_Controller.Heads (Display_Controller.Head_C);
291 end case;
292 end if;
293 return Result;
294 end To_Head;
295
296 ----------------------------------------------------------------------------
297
298 procedure Legacy_VGA_Off
299 is
300 Reg8 : Word8;
301 begin
302 -- disable legacy VGA plane, taking over control now
303 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
304 Port_IO.InB (Reg8, VGA_SR_DATA);
305 Port_IO.OutB (VGA_SR_DATA, Reg8 or 1 * 2 ** 5);
306 Time.U_Delay (100); -- PRM says 100us, Linux does 300
307 Registers.Set_Mask (Registers.VGACNTRL, 1 * 2 ** 31);
308 end Legacy_VGA_Off;
309
310 ----------------------------------------------------------------------------
311
312 function Port_Configured
313 (Configs : Configs_Type;
314 Port : Port_Type)
315 return Boolean
316 with
317 Global => null
318 is
319 begin
320 return Configs (Primary).Port = Port or
321 Configs (Secondary).Port = Port or
322 Configs (Tertiary).Port = Port;
323 end Port_Configured;
324
325 procedure Scan_Ports
326 (Configs : out Configs_Type;
327 Ports : in Port_List)
328 is
329 Raw_EDID : EDID.Raw_EDID_Data := (others => 16#00#);
330 Port_Idx : Port_List_Range := Port_List_Range'First;
331 Port_Cfg : Port_Config;
332 Success : Boolean := False;
333 begin
334 Configs := (Config_Index =>
335 (Port => Disabled,
336 Mode => Invalid_Mode,
337 Framebuffer => Default_FB));
338
339 for Config_Idx in Config_Index loop
340 while Ports (Port_Idx) /= Disabled loop
341 if not Port_Configured (Configs, Ports (Port_Idx)) then
342 Configs (Config_Idx).Port := Ports (Port_Idx);
343 Fill_Port_Config (Port_Cfg, Configs, Config_Idx, Success);
344
345 if Success then
346 -- May need power to probe port
347 if Port_Cfg.Display = DP then
348 Power_And_Clocks.Power_Up (Cur_Configs, Configs);
349 end if;
350 if Ports (Port_Idx) = Internal then
351 Panel.On;
352 end if;
353
354 Connector_Info.Read_EDID (Raw_EDID, Port_Cfg, Success);
355 end if;
356
Nico Huber393aa8a2016-10-21 14:18:53 +0200357 if Success and then
358 (EDID.Compatible_Display (Raw_EDID, Port_Cfg.Display) and
359 EDID.Has_Preferred_Mode (Raw_EDID))
360 then
Nico Huber83693c82016-10-08 22:17:55 +0200361 Configs (Config_Idx).Mode := EDID.Preferred_Mode (Raw_EDID);
362 else
363 Configs (Config_Idx).Port := Disabled;
Nico Huber6a356672016-10-21 15:13:55 +0200364 Success := False;
Nico Huber83693c82016-10-08 22:17:55 +0200365
366 if Ports (Port_Idx) = Internal and
367 not Port_Configured (Cur_Configs, Internal)
368 then
369 Panel.Off;
370 end if;
371 end if;
372 end if;
373
374 exit when Port_Idx = Port_List_Range'Last;
375 Port_Idx := Port_List_Range'Succ (Port_Idx);
376
377 exit when Success;
378 end loop;
379 end loop;
380
381 Power_And_Clocks.Power_Set_To (Cur_Configs);
382 end Scan_Ports;
383
384 procedure Auto_Configure
385 (Configs : in out Configs_Type;
386 Keep_Power : in Boolean := False)
387 is
388 Raw_EDID : EDID.Raw_EDID_Data := (others => 16#00#);
389 Success : Boolean;
390
391 Config_Idx : Config_Index;
392 Port_Cfg : Port_Config;
393
394 function Free_Config return Boolean
395 with
396 Pre => True
397 is
398 begin
399 return Port_Configured (Configs, Disabled);
400 end Free_Config;
401
402 function First_Free_Config return Config_Index
403 with
404 Pre => Free_Config
405 is
406 begin
407 return (if Configs (Primary).Port = Disabled then Primary else
408 (if Configs (Secondary).Port = Disabled then Secondary
409 else Tertiary));
410 end First_Free_Config;
411 begin
412 -- TODO: Only check ports with hot-plug event?
413
414 if Config.Has_Internal_Display and then
415 not Keep_Power and then
416 not Port_Configured (Cur_Configs, Internal)
417 then
418 Panel.On (Wait => False);
419 end if;
420
421 -- Check if displays are still connected
422 for I in Config_Index loop
423 if Configs (I).Port /= Disabled then
424 Fill_Port_Config (Port_Cfg, Configs, I, Success);
425 if Success then
426 Connector_Info.Read_EDID
427 (Raw_EDID => Raw_EDID,
428 Port_Cfg => Port_Cfg,
429 Success => Success);
430 end if;
431 if not Success or else
432 not EDID.Has_Preferred_Mode (Raw_EDID) or else
433 Configs (I).Mode /= EDID.Preferred_Mode (Raw_EDID)
434 then
435 Configs (I).Port := Disabled;
436 end if;
437 end if;
438 end loop;
439
440 -- Add new displays as long as there is a free pipe config
441 for Port in Active_Port_Type loop
442 if Free_Config and then not Port_Configured (Configs, Port) then
443 Config_Idx := First_Free_Config;
444 Configs (Config_Idx).Port := Port;
445 Fill_Port_Config (Port_Cfg, Configs, Config_Idx, Success);
446
447 if Success then
448 -- Need power to probe port
449 if not Keep_Power and then To_Display_Type (Port) = DP then
450 Power_And_Clocks.Power_Up (Cur_Configs, Configs);
451 end if;
452 if not Keep_Power and then Port = Internal then
453 Panel.Wait_On;
454 end if;
455
456 Connector_Info.Read_EDID
457 (Raw_EDID => Raw_EDID,
458 Port_Cfg => Port_Cfg,
459 Success => Success);
460 end if;
461
Nico Huber393aa8a2016-10-21 14:18:53 +0200462 if Success and then
463 (EDID.Compatible_Display (Raw_EDID, Port_Cfg.Display) and
464 EDID.Has_Preferred_Mode (Raw_EDID))
465 then
Nico Huber83693c82016-10-08 22:17:55 +0200466 Configs (Config_Idx) := Config_Type'
467 (Port => Port,
468 Framebuffer => Configs (Config_Idx).Framebuffer,
469 Mode => EDID.Preferred_Mode (Raw_EDID));
470 else
471 Configs (Config_Idx).Port := Disabled;
472 end if;
473 end if;
474 end loop;
475
476 if not Keep_Power then
477 Power_And_Clocks.Power_Set_To (Cur_Configs);
478
479 if Config.Has_Internal_Display and then
480 not Port_Configured (Cur_Configs, Internal)
481 then
482 Panel.Off;
483 end if;
484 end if;
485 end Auto_Configure;
486
487 ----------------------------------------------------------------------------
488
489 procedure Update_Outputs (Configs : Configs_Type)
490 is
491 Did_Power_Up : Boolean := False;
492
493 HPD, HPD_Delay_Over, Success : Boolean;
494 Old_Config, New_Config : Config_Type;
495 Old_Configs : Configs_Type;
496 Port_Cfg : Port_Config;
497
498 procedure Check_HPD
499 (Port_Cfg : in Port_Config;
500 Port : in Port_Type;
501 Detected : out Boolean)
502 is
503 begin
504 HPD_Delay_Over := Time.Timed_Out (HPD_Delay (Port));
505 if HPD_Delay_Over then
506 Port_Detect.Hotplug_Detect (Port_Cfg, Detected);
507 HPD_Delay (Port) := Time.MS_From_Now (333);
508 else
509 Detected := False;
510 end if;
511 end Check_HPD;
512 begin
513 Old_Configs := Cur_Configs;
514
515 for I in Config_Index loop
516 HPD := False;
517
518 Old_Config := Cur_Configs (I);
519 New_Config := Configs (I);
520
521 Fill_Port_Config (Port_Cfg, Old_Configs, I, Success);
522 if Success then
523 Check_HPD (Port_Cfg, Old_Config.Port, HPD);
524 end if;
525
526 -- Connector changed?
527 if (Success and then HPD) or
528 Old_Config.Port /= New_Config.Port or
529 Old_Config.Mode /= New_Config.Mode
530 then
531 if Old_Config.Port /= Disabled then
532 if Success then
533 pragma Debug (Debug.New_Line);
534 pragma Debug (Debug.Put_Line
535 ("Disabling port " & Port_Names (Old_Config.Port)));
536
537 Connectors.Pre_Off (Port_Cfg);
538
539 Display_Controller.Off
540 (To_Controller (I), To_Head (I, Old_Config.Port));
541
542 Connectors.Post_Off (Port_Cfg);
543 end if;
544
545 -- Free PLL
546 PLLs.Free (Allocated_PLLs (I));
547
548 Cur_Configs (I).Port := Disabled;
549 end if;
550
551 if New_Config.Port /= Disabled then
552 Fill_Port_Config (Port_Cfg, Configs, I, Success);
553
Nico Huberc7a4fee2016-11-03 18:18:03 +0100554 Success := Success and then
Nico Huberdcd274b2016-11-03 20:15:39 +0100555 Validate_Config (New_Config.Framebuffer, Port_Cfg, I);
Nico Huberc7a4fee2016-11-03 18:18:03 +0100556
Nico Huber83693c82016-10-08 22:17:55 +0200557 if Success and then Wait_For_HPD (New_Config.Port) then
558 Check_HPD (Port_Cfg, New_Config.Port, Success);
559 Wait_For_HPD (New_Config.Port) := not Success;
560 end if;
561
562 if Success then
563 pragma Debug (Debug.New_Line);
564 pragma Debug (Debug.Put_Line
565 ("Trying to enable port " & Port_Names (New_Config.Port)));
566
567 if not Did_Power_Up then
568 Power_And_Clocks.Power_Up (Old_Configs, Configs);
569 Did_Power_Up := True;
570 end if;
571
572 if Port_Cfg.Is_FDI then
573 Configure_FDI_Link (Port_Cfg, Success);
574 end if;
575 end if;
576
577 if Success then
578 Connector_Info.Preferred_Link_Setting
579 (Port_Cfg => Port_Cfg,
580 Success => Success);
581 end if;
582
583 while Success loop
Nico Huber47ff0692016-11-04 14:29:39 +0100584 pragma Loop_Invariant
585 (New_Config.Port in Active_Port_Type and
586 Port_Cfg.Mode = Port_Cfg.Mode'Loop_Entry);
Nico Huber83693c82016-10-08 22:17:55 +0200587
588 PLLs.Alloc
589 (Port_Cfg => Port_Cfg,
590 PLL => Allocated_PLLs (I),
591 Success => Success);
592
593 if Success then
594 for Try in 1 .. 2 loop
595 pragma Loop_Invariant
596 (New_Config.Port in Active_Port_Type);
597
598 Connectors.Pre_On
599 (Port_Cfg => Port_Cfg,
600 PLL_Hint => PLLs.Register_Value
601 (Allocated_PLLs (I)),
602 Pipe_Hint => Display_Controller.Get_Pipe_Hint
603 (To_Head (I, New_Config.Port)),
604 Success => Success);
605
606 if Success then
607 Display_Controller.On
608 (Controller => To_Controller (I),
609 Head => To_Head (I, New_Config.Port),
610 Port_Cfg => Port_Cfg,
611 Framebuffer => New_Config.Framebuffer);
612
613 Connectors.Post_On
614 (Port_Cfg => Port_Cfg,
615 PLL_Hint => PLLs.Register_Value
616 (Allocated_PLLs (I)),
617 Success => Success);
618
619 if not Success then
620 Display_Controller.Off
621 (To_Controller (I),
622 To_Head (I, New_Config.Port));
623 Connectors.Post_Off (Port_Cfg);
624 end if;
625 end if;
626
627 exit when Success;
628 end loop;
629 exit when Success; -- connection established => stop loop
630
631 -- connection failed
632 PLLs.Free (Allocated_PLLs (I));
633 end if;
634
635 Connector_Info.Next_Link_Setting
636 (Port_Cfg => Port_Cfg,
637 Success => Success);
638 end loop;
639
640 if Success then
641 pragma Debug (Debug.Put_Line
642 ("Enabled port " & Port_Names (New_Config.Port)));
643 Cur_Configs (I) := New_Config;
644 DP_Links (I) := Port_Cfg.DP;
645 else
646 Wait_For_HPD (New_Config.Port) := True;
647 if New_Config.Port = Internal then
648 Panel.Off;
649 end if;
650 end if;
651 else
652 Cur_Configs (I) := New_Config;
653 end if;
654 elsif Old_Config.Framebuffer /= New_Config.Framebuffer and
655 Old_Config.Port /= Disabled
656 then
657 Display_Controller.Update_Offset
658 (Controller => To_Controller (I),
659 Framebuffer => New_Config.Framebuffer);
660 Cur_Configs (I) := New_Config;
661 end if;
662 end loop;
663
664 if Did_Power_Up then
665 Power_And_Clocks.Power_Down (Old_Configs, Configs, Cur_Configs);
666 end if;
667
668 end Update_Outputs;
669
670 ----------------------------------------------------------------------------
671
672 procedure Initialize
673 (MMIO_Base : in Word64 := 0;
674 Write_Delay : in Word64 := 0;
675 Success : out Boolean)
676 with
677 Refined_Global =>
678 (In_Out =>
679 (Config.Valid_Port_GPU,
680 Registers.Register_State, Port_IO.State),
681 Input =>
682 (Time.State),
683 Output =>
684 (Registers.Address_State,
685 PLLs.State, Panel.Panel_State,
686 Cur_Configs, Allocated_PLLs, DP_Links,
687 HPD_Delay, Wait_For_HPD, Initialized))
688 is
689 use type HW.Word64;
690
691 Now : constant Time.T := Time.Now;
692
693 procedure Check_Platform (Success : out Boolean)
694 is
695 Audio_VID_DID : Word32;
696 begin
697 case Config.CPU is
698 when Haswell .. Skylake =>
699 Registers.Read (Registers.AUD_VID_DID, Audio_VID_DID);
700 when Ironlake .. Ivybridge =>
701 Registers.Read (Registers.PCH_AUD_VID_DID, Audio_VID_DID);
702 end case;
703 Success :=
704 (case Config.CPU is
705 when Skylake => Audio_VID_DID = 16#8086_2809#,
706 when Broadwell => Audio_VID_DID = 16#8086_2808#,
707 when Haswell => Audio_VID_DID = 16#8086_2807#,
708 when Ivybridge |
709 Sandybridge => Audio_VID_DID = 16#8086_2806# or
710 Audio_VID_DID = 16#8086_2805#,
Nico Hubereeb5a392016-10-09 19:28:30 +0200711 when Ironlake => Audio_VID_DID = 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200712 end Check_Platform;
713 begin
714 pragma Warnings (GNATprove, Off, "unused variable ""Write_Delay""",
715 Reason => "Write_Delay is used for debugging only");
716
717 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
718
719 pragma Debug (Debug.Set_Register_Write_Delay (Write_Delay));
720
721 Wait_For_HPD := HPD_Type'(others => False);
722 HPD_Delay := HPD_Delay_Type'(others => Now);
723 DP_Links := Links_Type'(others => HW.GFX.Default_DP);
724 Allocated_PLLs := (others => PLLs.Invalid);
725 Cur_Configs := Configs_Type'
726 (others => Config_Type'
727 (Port => Disabled,
728 Framebuffer => HW.GFX.Default_FB,
729 Mode => HW.GFX.Invalid_Mode));
730 Registers.Set_Register_Base
731 (if MMIO_Base /= 0 then
732 MMIO_Base
733 else
734 Config.Default_MMIO_Base);
735 PLLs.Initialize;
736
737 Check_Platform (Success);
738 if not Success then
739 pragma Debug (Debug.Put_Line ("ERROR: Incompatible CPU or PCH."));
740
741 Panel.Static_Init; -- for flow analysis
742
743 Initialized := False;
744 return;
745 end if;
746
747 Panel.Setup_PP_Sequencer;
748 Port_Detect.Initialize;
749
750 Power_And_Clocks.Pre_All_Off;
751
752 Legacy_VGA_Off;
753
754 Connectors.Pre_All_Off;
755 Display_Controller.All_Off;
756 Connectors.Post_All_Off;
757 PLLs.All_Off;
758
759 Power_And_Clocks.Post_All_Off;
760
761 -------------------- Now restart from a clean state ---------------------
762 Power_And_Clocks.Initialize;
763
Nico Huberf54d0962016-10-20 14:17:18 +0200764 Registers.Unset_And_Set_Mask
765 (Register => Registers.PCH_RAWCLK_FREQ,
766 Mask_Unset => PCH_RAWCLK_FREQ_MASK,
767 Mask_Set => PCH_RAWCLK_FREQ (Config.Default_RawClk_Freq));
768
Nico Huber83693c82016-10-08 22:17:55 +0200769 Initialized := True;
770
771 end Initialize;
772
773 function Is_Initialized return Boolean
774 with
775 Refined_Post => Is_Initialized'Result = Initialized
776 is
777 begin
778 return Initialized;
779 end Is_Initialized;
780
781 ----------------------------------------------------------------------------
782
783 procedure Write_GTT
784 (GTT_Page : GTT_Range;
785 Device_Address : GTT_Address_Type;
786 Valid : Boolean) is
787 begin
788 Registers.Write_GTT (GTT_Page, Device_Address, Valid);
789 end Write_GTT;
790
791 procedure Setup_Default_GTT (FB : Framebuffer_Type; Phys_FB : Word32)
792 is
793 FB_Size : constant Pos32 :=
794 FB.Stride * FB.Height * Pos32 (((FB.BPC * 4) / 8));
795 Phys_Addr : GTT_Address_Type := GTT_Address_Type (Phys_FB);
796 begin
797 for Idx in GTT_Range range 0 .. GTT_Range (((FB_Size + 4095) / 4096) - 1)
798 loop
799 Registers.Write_GTT
800 (GTT_Page => Idx,
801 Device_Address => Phys_Addr,
802 Valid => True);
803 Phys_Addr := Phys_Addr + 4096;
804 end loop;
805 end Setup_Default_GTT;
806
807 ----------------------------------------------------------------------------
808
809 procedure Dump_Configs (Configs : Configs_Type)
810 is
811 subtype Pipe_Name is String (1 .. 9);
812 type Pipe_Name_Array is array (Config_Index) of Pipe_Name;
813 Pipe_Names : constant Pipe_Name_Array :=
814 (Primary => "Primary ",
815 Secondary => "Secondary",
816 Tertiary => "Tertiary ");
817 begin
818 Debug.New_Line;
819 Debug.Put_Line ("CONFIG => ");
820 for Pipe in Config_Index loop
821 if Pipe = Config_Index'First then
822 Debug.Put (" (");
823 else
824 Debug.Put (" ");
825 end if;
826 Debug.Put_Line (Pipe_Names (Pipe) & " =>");
827 Debug.Put_Line
828 (" (Port => " & Port_Names (Configs (Pipe).Port) & ",");
829 Debug.Put_Line (" Framebuffer =>");
830 Debug.Put (" (Width => ");
831 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Width);
832 Debug.Put_Line (",");
833 Debug.Put (" Height => ");
834 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Height);
835 Debug.Put_Line (",");
836 Debug.Put (" Stride => ");
837 Debug.Put_Int32 (Configs (Pipe).Framebuffer.Stride);
838 Debug.Put_Line (",");
839 Debug.Put (" Offset => ");
840 Debug.Put_Word32 (Configs (Pipe).Framebuffer.Offset);
841 Debug.Put_Line (",");
842 Debug.Put (" BPC => ");
843 Debug.Put_Int64 (Configs (Pipe).Framebuffer.BPC);
844 Debug.Put_Line ("),");
845 Debug.Put_Line (" Mode =>");
846 Debug.Put (" (Dotclock => ");
847 Debug.Put_Int64 (Configs (Pipe).Mode.Dotclock);
848 Debug.Put_Line (",");
849 Debug.Put (" H_Visible => ");
850 Debug.Put_Int16 (Configs (Pipe).Mode.H_Visible);
851 Debug.Put_Line (",");
852 Debug.Put (" H_Sync_Begin => ");
853 Debug.Put_Int16 (Configs (Pipe).Mode.H_Sync_Begin);
854 Debug.Put_Line (",");
855 Debug.Put (" H_Sync_End => ");
856 Debug.Put_Int16 (Configs (Pipe).Mode.H_Sync_End);
857 Debug.Put_Line (",");
858 Debug.Put (" H_Total => ");
859 Debug.Put_Int16 (Configs (Pipe).Mode.H_Total);
860 Debug.Put_Line (",");
861 Debug.Put (" V_Visible => ");
862 Debug.Put_Int16 (Configs (Pipe).Mode.V_Visible);
863 Debug.Put_Line (",");
864 Debug.Put (" V_Sync_Begin => ");
865 Debug.Put_Int16 (Configs (Pipe).Mode.V_Sync_Begin);
866 Debug.Put_Line (",");
867 Debug.Put (" V_Sync_End => ");
868 Debug.Put_Int16 (Configs (Pipe).Mode.V_Sync_End);
869 Debug.Put_Line (",");
870 Debug.Put (" V_Total => ");
871 Debug.Put_Int16 (Configs (Pipe).Mode.V_Total);
872 Debug.Put_Line (",");
873 Debug.Put_Line (" H_Sync_Active_High => " &
874 (if Configs (Pipe).Mode.H_Sync_Active_High
875 then "True,"
876 else "False,"));
877 Debug.Put_Line (" V_Sync_Active_High => " &
878 (if Configs (Pipe).Mode.V_Sync_Active_High
879 then "True,"
880 else "False,"));
881 Debug.Put (" BPC => ");
882 Debug.Put_Int64 (Configs (Pipe).Mode.BPC);
883 if Pipe /= Config_Index'Last then
884 Debug.Put_Line (")),");
885 else
886 Debug.Put_Line (")));");
887 end if;
888 end loop;
889 end Dump_Configs;
890
891end HW.GFX.GMA;