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