mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-16 01:51:11 +00:00
gma: Split out config derivation and port probing
The GMA package has grown way too big. Move derivation of the internal configuration into new package `Config_Helpers`, EDID probing into new package `Display_Probing`. Change-Id: Ib49ac7b00367be4295d18dba3afd1a0692e0497f Signed-off-by: Nico Huber <nico.h@gmx.de> Reviewed-on: https://review.coreboot.org/17757 Reviewed-by: Adrian-Ken Rueegsegger <ken@codelabs.ch>
This commit is contained in:
@@ -7,9 +7,13 @@ gfxinit-y += hw-gfx-dp_training.adb
|
||||
gfxinit-y += hw-gfx-dp_training.ads
|
||||
gfxinit-y += hw-gfx-edid.adb
|
||||
gfxinit-y += hw-gfx-edid.ads
|
||||
gfxinit-y += hw-gfx-gma-config_helpers.adb
|
||||
gfxinit-y += hw-gfx-gma-config_helpers.ads
|
||||
gfxinit-y += hw-gfx-gma-connector_info.adb
|
||||
gfxinit-y += hw-gfx-gma-connector_info.ads
|
||||
gfxinit-y += hw-gfx-gma-connectors.ads
|
||||
gfxinit-y += hw-gfx-gma-display_probing.adb
|
||||
gfxinit-y += hw-gfx-gma-display_probing.ads
|
||||
gfxinit-y += hw-gfx-gma-dp_aux_ch.ads
|
||||
gfxinit-y += hw-gfx-gma-dp_aux_request.adb
|
||||
gfxinit-y += hw-gfx-gma-dp_aux_request.ads
|
||||
|
||||
210
common/hw-gfx-gma-config_helpers.adb
Normal file
210
common/hw-gfx-gma-config_helpers.adb
Normal file
@@ -0,0 +1,210 @@
|
||||
--
|
||||
-- Copyright (C) 2015-2016 secunet Security Networks AG
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
|
||||
with HW.GFX.GMA.Config;
|
||||
with HW.GFX.GMA.Connector_Info;
|
||||
with HW.GFX.GMA.DP_Info;
|
||||
with HW.GFX.GMA.Registers;
|
||||
|
||||
with HW.Debug;
|
||||
|
||||
package body HW.GFX.GMA.Config_Helpers
|
||||
is
|
||||
|
||||
function To_GPU_Port
|
||||
(Pipe : Pipe_Index;
|
||||
Port : Active_Port_Type)
|
||||
return GPU_Port
|
||||
is
|
||||
begin
|
||||
return
|
||||
(case Config.CPU is
|
||||
when Ironlake .. Ivybridge => -- everything but eDP through FDI/PCH
|
||||
(if Config.Internal_Is_EDP and then Port = Internal then
|
||||
DIGI_A
|
||||
else
|
||||
(case Pipe is
|
||||
-- FDIs are fixed to the CPU pipe
|
||||
when Primary => DIGI_B,
|
||||
when Secondary => DIGI_C,
|
||||
when Tertiary => DIGI_D)),
|
||||
when Haswell .. Skylake => -- everything but VGA directly on CPU
|
||||
(case Port is
|
||||
when Internal => DIGI_A, -- LVDS not available
|
||||
when HDMI1 | DP1 => DIGI_B,
|
||||
when HDMI2 | DP2 => DIGI_C,
|
||||
when HDMI3 | DP3 => DIGI_D,
|
||||
when Analog => DIGI_E));
|
||||
end To_GPU_Port;
|
||||
|
||||
function To_PCH_Port (Port : Active_Port_Type) return PCH_Port
|
||||
is
|
||||
begin
|
||||
return
|
||||
(case Port is
|
||||
when Internal => PCH_LVDS, -- will be ignored if Internal is DP
|
||||
when Analog => PCH_DAC,
|
||||
when HDMI1 => PCH_HDMI_B,
|
||||
when HDMI2 => PCH_HDMI_C,
|
||||
when HDMI3 => PCH_HDMI_D,
|
||||
when DP1 => PCH_DP_B,
|
||||
when DP2 => PCH_DP_C,
|
||||
when DP3 => PCH_DP_D);
|
||||
end To_PCH_Port;
|
||||
|
||||
function To_Display_Type (Port : Active_Port_Type) return Display_Type
|
||||
is
|
||||
begin
|
||||
return Display_Type'
|
||||
(case Port is
|
||||
when Internal => Config.Internal_Display,
|
||||
when Analog => VGA,
|
||||
when HDMI1 .. HDMI3 => HDMI,
|
||||
when DP1 .. DP3 => DP);
|
||||
end To_Display_Type;
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
-- Prepares link rate and lane count settings for an FDI connection.
|
||||
procedure Configure_FDI_Link
|
||||
(Port_Cfg : in out Port_Config;
|
||||
Success : out Boolean)
|
||||
with Pre => True
|
||||
is
|
||||
procedure Limit_Lane_Count
|
||||
is
|
||||
FDI_TX_CTL_FDI_TX_ENABLE : constant := 1 * 2 ** 31;
|
||||
Enabled : Boolean;
|
||||
begin
|
||||
-- if DIGI_D enabled: (FDI names are off by one)
|
||||
Registers.Is_Set_Mask
|
||||
(Register => Registers.FDI_TX_CTL_C,
|
||||
Mask => FDI_TX_CTL_FDI_TX_ENABLE,
|
||||
Result => Enabled);
|
||||
if Enabled then
|
||||
Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_2;
|
||||
end if;
|
||||
end Limit_Lane_Count;
|
||||
begin
|
||||
Port_Cfg.FDI.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
|
||||
Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count :=
|
||||
Config.FDI_Lane_Count (Port_Cfg.Port);
|
||||
Port_Cfg.FDI.Receiver_Caps.Enhanced_Framing := True;
|
||||
if Config.Has_FDI_C and then Port_Cfg.Port = DIGI_C then
|
||||
Limit_Lane_Count;
|
||||
end if;
|
||||
DP_Info.Preferred_Link_Setting (Port_Cfg.FDI, Port_Cfg.Mode, Success);
|
||||
end Configure_FDI_Link;
|
||||
|
||||
-- Derives an internal port config.
|
||||
--
|
||||
-- This is where the magic happens that hides the hardware details
|
||||
-- from libgfxinit's users. We have to map the pipe (Pipe_Index),
|
||||
-- the user visible port (Port_Type) and the modeline (Mode_Type)
|
||||
-- that we are supposed to output to an internal representation
|
||||
-- (Port_Config) that applies to the selected hardware generation
|
||||
-- (in GMA.Config).
|
||||
procedure Fill_Port_Config
|
||||
(Port_Cfg : out Port_Config;
|
||||
Pipe : in Pipe_Index;
|
||||
Port : in Port_Type;
|
||||
Mode : in Mode_Type;
|
||||
Success : out Boolean)
|
||||
is
|
||||
begin
|
||||
Success :=
|
||||
Config.Supported_Pipe (Pipe) and then
|
||||
Config.Valid_Port (Port) and then
|
||||
Port /= Disabled; -- Valid_Port should already cover this, but the
|
||||
-- array is writeable, so it's hard to prove this.
|
||||
|
||||
if Success then
|
||||
Port_Cfg := Port_Config'
|
||||
(Port => To_GPU_Port (Pipe, Port),
|
||||
PCH_Port => To_PCH_Port (Port),
|
||||
Display => To_Display_Type (Port),
|
||||
Mode => Mode,
|
||||
Is_FDI => Config.Is_FDI_Port (Port),
|
||||
FDI => Default_DP,
|
||||
DP => Default_DP);
|
||||
|
||||
if Port_Cfg.Is_FDI then
|
||||
Configure_FDI_Link (Port_Cfg, Success);
|
||||
end if;
|
||||
|
||||
if Success then
|
||||
if Port_Cfg.Mode.BPC = Auto_BPC then
|
||||
Port_Cfg.Mode.BPC := Connector_Info.Default_BPC (Port_Cfg);
|
||||
end if;
|
||||
|
||||
if Port_Cfg.Display = HDMI then
|
||||
declare
|
||||
pragma Assert (Config.HDMI_Max_Clock_24bpp * 8
|
||||
/ Port_Cfg.Mode.BPC >= Frequency_Type'First);
|
||||
Max_Dotclock : constant Frequency_Type :=
|
||||
Config.HDMI_Max_Clock_24bpp * 8 / Port_Cfg.Mode.BPC;
|
||||
begin
|
||||
if Port_Cfg.Mode.Dotclock > Max_Dotclock then
|
||||
pragma Debug (Debug.Put ("Dotclock "));
|
||||
pragma Debug (Debug.Put_Int64 (Port_Cfg.Mode.Dotclock));
|
||||
pragma Debug (Debug.Put (" too high, limiting to "));
|
||||
pragma Debug (Debug.Put_Int64 (Max_Dotclock));
|
||||
pragma Debug (Debug.Put_Line ("."));
|
||||
Port_Cfg.Mode.Dotclock := Max_Dotclock;
|
||||
end if;
|
||||
end;
|
||||
end if;
|
||||
end if;
|
||||
else
|
||||
Port_Cfg := Port_Config'
|
||||
(Port => GPU_Port'First,
|
||||
PCH_Port => PCH_Port'First,
|
||||
Display => Display_Type'First,
|
||||
Mode => Invalid_Mode,
|
||||
Is_FDI => False,
|
||||
FDI => Default_DP,
|
||||
DP => Default_DP);
|
||||
end if;
|
||||
end Fill_Port_Config;
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
-- Validates that a given configuration should work with
|
||||
-- a given framebuffer.
|
||||
function Validate_Config
|
||||
(Framebuffer : Framebuffer_Type;
|
||||
Port_Cfg : Port_Config;
|
||||
Pipe : Pipe_Index)
|
||||
return Boolean
|
||||
is
|
||||
begin
|
||||
-- No downscaling
|
||||
-- Respect maximum scalable width
|
||||
-- VGA plane is only allowed on the primary pipe
|
||||
-- Only 32bpp RGB (ignored for VGA plane)
|
||||
-- Stride must be a multiple of 64 (ignored for VGA plane)
|
||||
return
|
||||
((Framebuffer.Width = Pos32 (Port_Cfg.Mode.H_Visible) and
|
||||
Framebuffer.Height = Pos32 (Port_Cfg.Mode.V_Visible)) or
|
||||
(Framebuffer.Width <= Config.Maximum_Scalable_Width (Pipe) and
|
||||
Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and
|
||||
Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible))) and
|
||||
(Framebuffer.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or Pipe = Primary)
|
||||
and
|
||||
(Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
|
||||
(Framebuffer.BPC = 8 and
|
||||
Framebuffer.Stride mod 64 = 0));
|
||||
end Validate_Config;
|
||||
|
||||
end HW.GFX.GMA.Config_Helpers;
|
||||
45
common/hw-gfx-gma-config_helpers.ads
Normal file
45
common/hw-gfx-gma-config_helpers.ads
Normal file
@@ -0,0 +1,45 @@
|
||||
--
|
||||
-- Copyright (C) 2015-2016 secunet Security Networks AG
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
|
||||
with HW;
|
||||
|
||||
private package HW.GFX.GMA.Config_Helpers
|
||||
is
|
||||
|
||||
function To_PCH_Port (Port : Active_Port_Type) return PCH_Port;
|
||||
|
||||
function To_Display_Type (Port : Active_Port_Type) return Display_Type;
|
||||
|
||||
procedure Fill_Port_Config
|
||||
(Port_Cfg : out Port_Config;
|
||||
Pipe : in Pipe_Index;
|
||||
Port : in Port_Type;
|
||||
Mode : in Mode_Type;
|
||||
Success : out Boolean);
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
use type HW.Pos32;
|
||||
function Validate_Config
|
||||
(Framebuffer : Framebuffer_Type;
|
||||
Port_Cfg : Port_Config;
|
||||
Pipe : Pipe_Index)
|
||||
return Boolean
|
||||
with
|
||||
Post =>
|
||||
(if Validate_Config'Result then
|
||||
Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and
|
||||
Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible));
|
||||
|
||||
end HW.GFX.GMA.Config_Helpers;
|
||||
208
common/hw-gfx-gma-display_probing.adb
Normal file
208
common/hw-gfx-gma-display_probing.adb
Normal file
@@ -0,0 +1,208 @@
|
||||
--
|
||||
-- Copyright (C) 2015-2016 secunet Security Networks AG
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
|
||||
with HW.GFX.I2C;
|
||||
with HW.GFX.EDID;
|
||||
with HW.GFX.GMA.Config;
|
||||
with HW.GFX.GMA.Config_Helpers;
|
||||
with HW.GFX.GMA.I2C;
|
||||
with HW.GFX.GMA.DP_Aux_Ch;
|
||||
with HW.GFX.GMA.Panel;
|
||||
with HW.GFX.GMA.Power_And_Clocks;
|
||||
|
||||
with HW.Debug;
|
||||
with GNAT.Source_Info;
|
||||
|
||||
package body HW.GFX.GMA.Display_Probing
|
||||
is
|
||||
|
||||
function Port_Configured
|
||||
(Configs : Pipe_Configs;
|
||||
Port : Port_Type)
|
||||
return Boolean
|
||||
with
|
||||
Global => null
|
||||
is
|
||||
begin
|
||||
return Configs (Primary).Port = Port or
|
||||
Configs (Secondary).Port = Port or
|
||||
Configs (Tertiary).Port = Port;
|
||||
end Port_Configured;
|
||||
|
||||
-- DP and HDMI share physical pins.
|
||||
function Sibling_Port (Port : Port_Type) return Port_Type
|
||||
is
|
||||
begin
|
||||
return
|
||||
(case Port is
|
||||
when HDMI1 => DP1,
|
||||
when HDMI2 => DP2,
|
||||
when HDMI3 => DP3,
|
||||
when DP1 => HDMI1,
|
||||
when DP2 => HDMI2,
|
||||
when DP3 => HDMI3,
|
||||
when others => Disabled);
|
||||
end Sibling_Port;
|
||||
|
||||
function Has_Sibling_Port (Port : Port_Type) return Boolean
|
||||
is
|
||||
begin
|
||||
return Sibling_Port (Port) /= Disabled;
|
||||
end Has_Sibling_Port;
|
||||
|
||||
procedure Read_EDID
|
||||
(Raw_EDID : out EDID.Raw_EDID_Data;
|
||||
Port : in Active_Port_Type;
|
||||
Success : out Boolean)
|
||||
with
|
||||
Post => (if Success then EDID.Valid (Raw_EDID))
|
||||
is
|
||||
Raw_EDID_Length : GFX.I2C.Transfer_Length := Raw_EDID'Length;
|
||||
begin
|
||||
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
|
||||
|
||||
for I in 1 .. 2 loop
|
||||
if Config_Helpers.To_Display_Type (Port) = DP then
|
||||
-- May need power to read edid
|
||||
declare
|
||||
Temp_Configs : Pipe_Configs := Cur_Configs;
|
||||
begin
|
||||
Temp_Configs (Primary).Port := Port;
|
||||
Power_And_Clocks.Power_Up (Cur_Configs, Temp_Configs);
|
||||
end;
|
||||
|
||||
declare
|
||||
DP_Port : constant GMA.DP_Port :=
|
||||
(case Port is
|
||||
when Internal => DP_A,
|
||||
when DP1 => DP_B,
|
||||
when DP2 => DP_C,
|
||||
when DP3 => DP_D,
|
||||
when others => GMA.DP_Port'First);
|
||||
begin
|
||||
DP_Aux_Ch.I2C_Read
|
||||
(Port => DP_Port,
|
||||
Address => 16#50#,
|
||||
Length => Raw_EDID_Length,
|
||||
Data => Raw_EDID,
|
||||
Success => Success);
|
||||
end;
|
||||
else
|
||||
I2C.I2C_Read
|
||||
(Port => (if Port = Analog
|
||||
then Config.Analog_I2C_Port
|
||||
else Config_Helpers.To_PCH_Port (Port)),
|
||||
Address => 16#50#,
|
||||
Length => Raw_EDID_Length,
|
||||
Data => Raw_EDID,
|
||||
Success => Success);
|
||||
end if;
|
||||
exit when not Success; -- don't retry if reading itself failed
|
||||
|
||||
pragma Debug (Debug.Put_Buffer ("EDID", Raw_EDID, Raw_EDID_Length));
|
||||
EDID.Sanitize (Raw_EDID, Success);
|
||||
exit when Success;
|
||||
end loop;
|
||||
end Read_EDID;
|
||||
|
||||
procedure Probe_Port
|
||||
(Pipe_Cfg : in out Pipe_Config;
|
||||
Port : in Active_Port_Type;
|
||||
Success : out Boolean)
|
||||
with Pre => True
|
||||
is
|
||||
Raw_EDID : EDID.Raw_EDID_Data := (others => 16#00#);
|
||||
begin
|
||||
Success := Config.Valid_Port (Port);
|
||||
|
||||
if Success then
|
||||
if Port = Internal then
|
||||
Panel.On;
|
||||
end if;
|
||||
Read_EDID (Raw_EDID, Port, Success);
|
||||
end if;
|
||||
|
||||
if Success and then
|
||||
(EDID.Compatible_Display
|
||||
(Raw_EDID, Config_Helpers.To_Display_Type (Port)) and
|
||||
EDID.Has_Preferred_Mode (Raw_EDID))
|
||||
then
|
||||
Pipe_Cfg.Port := Port;
|
||||
Pipe_Cfg.Mode := EDID.Preferred_Mode (Raw_EDID);
|
||||
|
||||
pragma Warnings (GNATprove, Off, "unused assignment to ""Raw_EDID""",
|
||||
Reason => "We just want to check if it's readable.");
|
||||
if Has_Sibling_Port (Port) then
|
||||
-- Probe sibling port too and bail out if something is detected.
|
||||
-- This is a precaution for adapters that expose the pins of a
|
||||
-- port for both HDMI/DVI and DP (like some ThinkPad docks). A
|
||||
-- user might have attached both by accident and there are ru-
|
||||
-- mors of displays that got fried by applying the wrong signal.
|
||||
declare
|
||||
Have_Sibling_EDID : Boolean;
|
||||
begin
|
||||
Read_EDID (Raw_EDID, Sibling_Port (Port), Have_Sibling_EDID);
|
||||
if Have_Sibling_EDID then
|
||||
Pipe_Cfg.Port := Disabled;
|
||||
Success := False;
|
||||
end if;
|
||||
end;
|
||||
end if;
|
||||
pragma Warnings (GNATprove, On, "unused assignment to ""Raw_EDID""");
|
||||
else
|
||||
Success := False;
|
||||
if Port = Internal then
|
||||
Panel.Off;
|
||||
end if;
|
||||
end if;
|
||||
end Probe_Port;
|
||||
|
||||
procedure Scan_Ports
|
||||
(Configs : out Pipe_Configs;
|
||||
Ports : in Port_List;
|
||||
Max_Pipe : in Pipe_Index := Pipe_Index'Last)
|
||||
is
|
||||
Port_Idx : Port_List_Range := Port_List_Range'First;
|
||||
Success : Boolean;
|
||||
begin
|
||||
Configs := (Pipe_Index =>
|
||||
(Port => Disabled,
|
||||
Mode => Invalid_Mode,
|
||||
Framebuffer => Default_FB));
|
||||
|
||||
for Pipe in Pipe_Index range
|
||||
Pipe_Index'First .. Pipe_Index'Min (Max_Pipe, Config.Max_Pipe)
|
||||
loop
|
||||
while Ports (Port_Idx) /= Disabled loop
|
||||
if not Port_Configured (Configs, Ports (Port_Idx)) and
|
||||
(not Has_Sibling_Port (Ports (Port_Idx)) or
|
||||
not Port_Configured (Configs, Sibling_Port (Ports (Port_Idx))))
|
||||
then
|
||||
Probe_Port (Configs (Pipe), Ports (Port_Idx), Success);
|
||||
else
|
||||
Success := False;
|
||||
end if;
|
||||
|
||||
exit when Port_Idx = Port_List_Range'Last;
|
||||
Port_Idx := Port_List_Range'Succ (Port_Idx);
|
||||
|
||||
exit when Success;
|
||||
end loop;
|
||||
end loop;
|
||||
|
||||
-- Restore power settings
|
||||
Power_And_Clocks.Power_Set_To (Cur_Configs);
|
||||
end Scan_Ports;
|
||||
|
||||
end HW.GFX.GMA.Display_Probing;
|
||||
26
common/hw-gfx-gma-display_probing.ads
Normal file
26
common/hw-gfx-gma-display_probing.ads
Normal file
@@ -0,0 +1,26 @@
|
||||
--
|
||||
-- Copyright (C) 2015-2016 secunet Security Networks AG
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
|
||||
package HW.GFX.GMA.Display_Probing
|
||||
is
|
||||
|
||||
type Port_List_Range is range 0 .. 7;
|
||||
type Port_List is array (Port_List_Range) of Port_Type;
|
||||
|
||||
procedure Scan_Ports
|
||||
(Configs : out Pipe_Configs;
|
||||
Ports : in Port_List;
|
||||
Max_Pipe : in Pipe_Index := Pipe_Index'Last);
|
||||
|
||||
end HW.GFX.GMA.Display_Probing;
|
||||
@@ -12,12 +12,8 @@
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
|
||||
with HW.GFX.I2C;
|
||||
with HW.GFX.EDID;
|
||||
with HW.GFX.GMA.Config;
|
||||
with HW.GFX.GMA.I2C;
|
||||
with HW.GFX.GMA.DP_Aux_Ch;
|
||||
with HW.GFX.GMA.DP_Info;
|
||||
with HW.GFX.GMA.Config_Helpers;
|
||||
with HW.GFX.GMA.Registers;
|
||||
with HW.GFX.GMA.Power_And_Clocks;
|
||||
with HW.GFX.GMA.Panel;
|
||||
@@ -70,15 +66,12 @@ is
|
||||
type HPD_Type is array (Port_Type) of Boolean;
|
||||
type HPD_Delay_Type is array (Port_Type) of Time.T;
|
||||
|
||||
Cur_Configs : Pipe_Configs;
|
||||
Allocated_PLLs : PLLs_Type;
|
||||
DP_Links : Links_Type;
|
||||
HPD_Delay : HPD_Delay_Type;
|
||||
Wait_For_HPD : HPD_Type;
|
||||
Initialized : Boolean := False;
|
||||
|
||||
subtype Active_Port_Type is Port_Type range Port_Type'Succ (Disabled) .. Port_Type'Last;
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
PCH_RAWCLK_FREQ_MASK : constant := 16#3ff# * 2 ** 0;
|
||||
@@ -91,200 +84,6 @@ is
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
function To_GPU_Port
|
||||
(Pipe : Pipe_Index;
|
||||
Port : Active_Port_Type)
|
||||
return GPU_Port
|
||||
is
|
||||
begin
|
||||
return
|
||||
(case Config.CPU is
|
||||
when Ironlake .. Ivybridge => -- everything but eDP through FDI/PCH
|
||||
(if Config.Internal_Is_EDP and then Port = Internal then
|
||||
DIGI_A
|
||||
else
|
||||
(case Pipe is
|
||||
-- FDIs are fixed to the CPU pipe
|
||||
when Primary => DIGI_B,
|
||||
when Secondary => DIGI_C,
|
||||
when Tertiary => DIGI_D)),
|
||||
when Haswell .. Skylake => -- everything but VGA directly on CPU
|
||||
(case Port is
|
||||
when Internal => DIGI_A, -- LVDS not available
|
||||
when HDMI1 | DP1 => DIGI_B,
|
||||
when HDMI2 | DP2 => DIGI_C,
|
||||
when HDMI3 | DP3 => DIGI_D,
|
||||
when Analog => DIGI_E));
|
||||
end To_GPU_Port;
|
||||
|
||||
function To_PCH_Port (Port : Active_Port_Type) return PCH_Port
|
||||
with Pre => True
|
||||
is
|
||||
begin
|
||||
return
|
||||
(case Port is
|
||||
when Internal => PCH_LVDS, -- will be ignored if Internal is DP
|
||||
when Analog => PCH_DAC,
|
||||
when HDMI1 => PCH_HDMI_B,
|
||||
when HDMI2 => PCH_HDMI_C,
|
||||
when HDMI3 => PCH_HDMI_D,
|
||||
when DP1 => PCH_DP_B,
|
||||
when DP2 => PCH_DP_C,
|
||||
when DP3 => PCH_DP_D);
|
||||
end To_PCH_Port;
|
||||
|
||||
function To_Display_Type (Port : Active_Port_Type) return Display_Type
|
||||
with Pre => True
|
||||
is
|
||||
begin
|
||||
return Display_Type'
|
||||
(case Port is
|
||||
when Internal => Config.Internal_Display,
|
||||
when Analog => VGA,
|
||||
when HDMI1 .. HDMI3 => HDMI,
|
||||
when DP1 .. DP3 => DP);
|
||||
end To_Display_Type;
|
||||
|
||||
-- Prepares link rate and lane count settings for an FDI connection.
|
||||
procedure Configure_FDI_Link
|
||||
(Port_Cfg : in out Port_Config;
|
||||
Success : out Boolean)
|
||||
with Pre => True
|
||||
is
|
||||
procedure Limit_Lane_Count
|
||||
is
|
||||
FDI_TX_CTL_FDI_TX_ENABLE : constant := 1 * 2 ** 31;
|
||||
Enabled : Boolean;
|
||||
begin
|
||||
-- if DIGI_D enabled: (FDI names are off by one)
|
||||
Registers.Is_Set_Mask
|
||||
(Register => Registers.FDI_TX_CTL_C,
|
||||
Mask => FDI_TX_CTL_FDI_TX_ENABLE,
|
||||
Result => Enabled);
|
||||
if Enabled then
|
||||
Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_2;
|
||||
end if;
|
||||
end Limit_Lane_Count;
|
||||
begin
|
||||
Port_Cfg.FDI.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
|
||||
Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count :=
|
||||
Config.FDI_Lane_Count (Port_Cfg.Port);
|
||||
Port_Cfg.FDI.Receiver_Caps.Enhanced_Framing := True;
|
||||
if Config.Has_FDI_C and then Port_Cfg.Port = DIGI_C then
|
||||
Limit_Lane_Count;
|
||||
end if;
|
||||
DP_Info.Preferred_Link_Setting (Port_Cfg.FDI, Port_Cfg.Mode, Success);
|
||||
end Configure_FDI_Link;
|
||||
|
||||
-- Validates that a given configuration should work with
|
||||
-- a given framebuffer.
|
||||
function Validate_Config
|
||||
(Framebuffer : Framebuffer_Type;
|
||||
Port_Cfg : Port_Config;
|
||||
I : Pipe_Index)
|
||||
return Boolean
|
||||
with
|
||||
Post =>
|
||||
(if Validate_Config'Result then
|
||||
Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and
|
||||
Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible))
|
||||
is
|
||||
begin
|
||||
-- No downscaling
|
||||
-- Respect maximum scalable width
|
||||
-- VGA plane is only allowed on the primary pipe
|
||||
-- Only 32bpp RGB (ignored for VGA plane)
|
||||
-- Stride must be a multiple of 64 (ignored for VGA plane)
|
||||
return
|
||||
((Framebuffer.Width = Pos32 (Port_Cfg.Mode.H_Visible) and
|
||||
Framebuffer.Height = Pos32 (Port_Cfg.Mode.V_Visible)) or
|
||||
(Framebuffer.Width <= Config.Maximum_Scalable_Width (I) and
|
||||
Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and
|
||||
Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible))) and
|
||||
(Framebuffer.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or I = Primary) and
|
||||
(Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
|
||||
(Framebuffer.BPC = 8 and
|
||||
Framebuffer.Stride mod 64 = 0));
|
||||
end Validate_Config;
|
||||
|
||||
-- Derives an internal port config.
|
||||
--
|
||||
-- This is where the magic happens that hides the hardware details
|
||||
-- from libgfxinit's users. We have to map the pipe (Pipe_Index),
|
||||
-- the user visible port (Port_Type) and the modeline (Mode_Type)
|
||||
-- that we are supposed to output to an internal representation
|
||||
-- (Port_Config) that applies to the selected hardware generation
|
||||
-- (in GMA.Config).
|
||||
procedure Fill_Port_Config
|
||||
(Port_Cfg : out Port_Config;
|
||||
Pipe : in Pipe_Index;
|
||||
Port : in Port_Type;
|
||||
Mode : in Mode_Type;
|
||||
Success : out Boolean)
|
||||
with Pre => True
|
||||
is
|
||||
begin
|
||||
Success :=
|
||||
GMA.Config.Supported_Pipe (Pipe) and then
|
||||
GMA.Config.Valid_Port (Port) and then
|
||||
Port /= Disabled; -- Valid_Port should already cover this, but the
|
||||
-- array is writeable, so it's hard to prove this.
|
||||
|
||||
if Success then
|
||||
declare
|
||||
Link : constant DP_Link := DP_Links (Pipe);
|
||||
begin
|
||||
Port_Cfg := Port_Config'
|
||||
(Port => To_GPU_Port (Pipe, Port),
|
||||
PCH_Port => To_PCH_Port (Port),
|
||||
Display => To_Display_Type (Port),
|
||||
Mode => Mode,
|
||||
Is_FDI => GMA.Config.Is_FDI_Port (Port),
|
||||
FDI => Default_DP,
|
||||
DP => Link);
|
||||
end;
|
||||
|
||||
if Port_Cfg.Is_FDI then
|
||||
Configure_FDI_Link (Port_Cfg, Success);
|
||||
end if;
|
||||
|
||||
if Success then
|
||||
if Port_Cfg.Mode.BPC = Auto_BPC then
|
||||
Port_Cfg.Mode.BPC := Connector_Info.Default_BPC (Port_Cfg);
|
||||
end if;
|
||||
|
||||
if Port_Cfg.Display = HDMI then
|
||||
declare
|
||||
pragma Assert (Config.HDMI_Max_Clock_24bpp * 8
|
||||
/ Port_Cfg.Mode.BPC >= Frequency_Type'First);
|
||||
Max_Dotclock : constant Frequency_Type :=
|
||||
Config.HDMI_Max_Clock_24bpp * 8 / Port_Cfg.Mode.BPC;
|
||||
begin
|
||||
if Port_Cfg.Mode.Dotclock > Max_Dotclock then
|
||||
pragma Debug (Debug.Put ("Dotclock "));
|
||||
pragma Debug (Debug.Put_Int64 (Port_Cfg.Mode.Dotclock));
|
||||
pragma Debug (Debug.Put (" too high, limiting to "));
|
||||
pragma Debug (Debug.Put_Int64 (Max_Dotclock));
|
||||
pragma Debug (Debug.Put_Line ("."));
|
||||
Port_Cfg.Mode.Dotclock := Max_Dotclock;
|
||||
end if;
|
||||
end;
|
||||
end if;
|
||||
end if;
|
||||
else
|
||||
Port_Cfg := Port_Config'
|
||||
(Port => GPU_Port'First,
|
||||
PCH_Port => PCH_Port'First,
|
||||
Display => Display_Type'First,
|
||||
Mode => Invalid_Mode,
|
||||
Is_FDI => False,
|
||||
FDI => Default_DP,
|
||||
DP => Default_DP);
|
||||
end if;
|
||||
end Fill_Port_Config;
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
function To_Controller
|
||||
(Dsp_Config : Pipe_Index) return Display_Controller.Controller_Type
|
||||
is
|
||||
@@ -345,185 +144,6 @@ is
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
function Port_Configured
|
||||
(Configs : Pipe_Configs;
|
||||
Port : Port_Type)
|
||||
return Boolean
|
||||
with
|
||||
Global => null
|
||||
is
|
||||
begin
|
||||
return Configs (Primary).Port = Port or
|
||||
Configs (Secondary).Port = Port or
|
||||
Configs (Tertiary).Port = Port;
|
||||
end Port_Configured;
|
||||
|
||||
-- DP and HDMI share physical pins.
|
||||
function Sibling_Port (Port : Port_Type) return Port_Type
|
||||
is
|
||||
begin
|
||||
return
|
||||
(case Port is
|
||||
when HDMI1 => DP1,
|
||||
when HDMI2 => DP2,
|
||||
when HDMI3 => DP3,
|
||||
when DP1 => HDMI1,
|
||||
when DP2 => HDMI2,
|
||||
when DP3 => HDMI3,
|
||||
when others => Disabled);
|
||||
end Sibling_Port;
|
||||
|
||||
function Has_Sibling_Port (Port : Port_Type) return Boolean
|
||||
is
|
||||
begin
|
||||
return Sibling_Port (Port) /= Disabled;
|
||||
end Has_Sibling_Port;
|
||||
|
||||
procedure Read_EDID
|
||||
(Raw_EDID : out EDID.Raw_EDID_Data;
|
||||
Port : in Active_Port_Type;
|
||||
Success : out Boolean)
|
||||
with
|
||||
Post => (if Success then EDID.Valid (Raw_EDID))
|
||||
is
|
||||
Raw_EDID_Length : GFX.I2C.Transfer_Length := Raw_EDID'Length;
|
||||
begin
|
||||
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
|
||||
|
||||
for I in 1 .. 2 loop
|
||||
if To_Display_Type (Port) = DP then
|
||||
-- May need power to read edid
|
||||
declare
|
||||
Temp_Configs : Pipe_Configs := Cur_Configs;
|
||||
begin
|
||||
Temp_Configs (Primary).Port := Port;
|
||||
Power_And_Clocks.Power_Up (Cur_Configs, Temp_Configs);
|
||||
end;
|
||||
|
||||
declare
|
||||
DP_Port : constant GMA.DP_Port :=
|
||||
(case Port is
|
||||
when Internal => DP_A,
|
||||
when DP1 => DP_B,
|
||||
when DP2 => DP_C,
|
||||
when DP3 => DP_D,
|
||||
when others => GMA.DP_Port'First);
|
||||
begin
|
||||
DP_Aux_Ch.I2C_Read
|
||||
(Port => DP_Port,
|
||||
Address => 16#50#,
|
||||
Length => Raw_EDID_Length,
|
||||
Data => Raw_EDID,
|
||||
Success => Success);
|
||||
end;
|
||||
else
|
||||
I2C.I2C_Read
|
||||
(Port => (if Port = Analog
|
||||
then Config.Analog_I2C_Port
|
||||
else To_PCH_Port (Port)),
|
||||
Address => 16#50#,
|
||||
Length => Raw_EDID_Length,
|
||||
Data => Raw_EDID,
|
||||
Success => Success);
|
||||
end if;
|
||||
exit when not Success; -- don't retry if reading itself failed
|
||||
|
||||
pragma Debug (Debug.Put_Buffer ("EDID", Raw_EDID, Raw_EDID_Length));
|
||||
EDID.Sanitize (Raw_EDID, Success);
|
||||
exit when Success;
|
||||
end loop;
|
||||
end Read_EDID;
|
||||
|
||||
procedure Probe_Port
|
||||
(Pipe_Cfg : in out Pipe_Config;
|
||||
Port : in Active_Port_Type;
|
||||
Success : out Boolean)
|
||||
with Pre => True
|
||||
is
|
||||
Raw_EDID : EDID.Raw_EDID_Data := (others => 16#00#);
|
||||
begin
|
||||
Success := Config.Valid_Port (Port);
|
||||
|
||||
if Success then
|
||||
if Port = Internal then
|
||||
Panel.On;
|
||||
end if;
|
||||
Read_EDID (Raw_EDID, Port, Success);
|
||||
end if;
|
||||
|
||||
if Success and then
|
||||
(EDID.Compatible_Display (Raw_EDID, To_Display_Type (Port)) and
|
||||
EDID.Has_Preferred_Mode (Raw_EDID))
|
||||
then
|
||||
Pipe_Cfg.Port := Port;
|
||||
Pipe_Cfg.Mode := EDID.Preferred_Mode (Raw_EDID);
|
||||
|
||||
pragma Warnings (GNATprove, Off, "unused assignment to ""Raw_EDID""",
|
||||
Reason => "We just want to check if it's readable.");
|
||||
if Has_Sibling_Port (Port) then
|
||||
-- Probe sibling port too and bail out if something is detected.
|
||||
-- This is a precaution for adapters that expose the pins of a
|
||||
-- port for both HDMI/DVI and DP (like some ThinkPad docks). A
|
||||
-- user might have attached both by accident and there are ru-
|
||||
-- mors of displays that got fried by applying the wrong signal.
|
||||
declare
|
||||
Have_Sibling_EDID : Boolean;
|
||||
begin
|
||||
Read_EDID (Raw_EDID, Sibling_Port (Port), Have_Sibling_EDID);
|
||||
if Have_Sibling_EDID then
|
||||
Pipe_Cfg.Port := Disabled;
|
||||
Success := False;
|
||||
end if;
|
||||
end;
|
||||
end if;
|
||||
pragma Warnings (GNATprove, On, "unused assignment to ""Raw_EDID""");
|
||||
else
|
||||
Success := False;
|
||||
if Port = Internal then
|
||||
Panel.Off;
|
||||
end if;
|
||||
end if;
|
||||
end Probe_Port;
|
||||
|
||||
procedure Scan_Ports
|
||||
(Configs : out Pipe_Configs;
|
||||
Ports : in Port_List;
|
||||
Max_Pipe : in Pipe_Index := Pipe_Index'Last)
|
||||
is
|
||||
Port_Idx : Port_List_Range := Port_List_Range'First;
|
||||
Success : Boolean;
|
||||
begin
|
||||
Configs := (Pipe_Index =>
|
||||
(Port => Disabled,
|
||||
Mode => Invalid_Mode,
|
||||
Framebuffer => Default_FB));
|
||||
|
||||
for Pipe in Pipe_Index range
|
||||
Pipe_Index'First .. Pipe_Index'Min (Max_Pipe, Config.Max_Pipe)
|
||||
loop
|
||||
while Ports (Port_Idx) /= Disabled loop
|
||||
if not Port_Configured (Configs, Ports (Port_Idx)) and
|
||||
(not Has_Sibling_Port (Ports (Port_Idx)) or
|
||||
not Port_Configured (Configs, Sibling_Port (Ports (Port_Idx))))
|
||||
then
|
||||
Probe_Port (Configs (Pipe), Ports (Port_Idx), Success);
|
||||
else
|
||||
Success := False;
|
||||
end if;
|
||||
|
||||
exit when Port_Idx = Port_List_Range'Last;
|
||||
Port_Idx := Port_List_Range'Succ (Port_Idx);
|
||||
|
||||
exit when Success;
|
||||
end loop;
|
||||
end loop;
|
||||
|
||||
-- Restore power settings
|
||||
Power_And_Clocks.Power_Set_To (Cur_Configs);
|
||||
end Scan_Ports;
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
procedure Update_Outputs (Configs : Pipe_Configs)
|
||||
is
|
||||
Did_Power_Up : Boolean := False;
|
||||
@@ -556,8 +176,9 @@ is
|
||||
Old_Config := Cur_Configs (I);
|
||||
New_Config := Configs (I);
|
||||
|
||||
Fill_Port_Config
|
||||
Config_Helpers.Fill_Port_Config
|
||||
(Port_Cfg, I, Old_Configs (I).Port, Old_Configs (I).Mode, Success);
|
||||
Port_Cfg.DP := DP_Links (I);
|
||||
if Success then
|
||||
Check_HPD (Port_Cfg, Old_Config.Port, HPD);
|
||||
end if;
|
||||
@@ -588,11 +209,13 @@ is
|
||||
end if;
|
||||
|
||||
if New_Config.Port /= Disabled then
|
||||
Fill_Port_Config
|
||||
Config_Helpers.Fill_Port_Config
|
||||
(Port_Cfg, I, Configs (I).Port, Configs (I).Mode, Success);
|
||||
|
||||
Success := Success and then
|
||||
Validate_Config (New_Config.Framebuffer, Port_Cfg, I);
|
||||
if Success then
|
||||
Success := Config_Helpers.Validate_Config
|
||||
(New_Config.Framebuffer, Port_Cfg, I);
|
||||
end if;
|
||||
|
||||
if Success and then Wait_For_HPD (New_Config.Port) then
|
||||
Check_HPD (Port_Cfg, New_Config.Port, Success);
|
||||
|
||||
@@ -47,8 +47,6 @@ is
|
||||
HDMI2, -- or DVI
|
||||
HDMI3, -- or DVI
|
||||
Analog);
|
||||
type Port_List_Range is range 0 .. 7;
|
||||
type Port_List is array (Port_List_Range) of Port_Type;
|
||||
|
||||
type Pipe_Config is record
|
||||
Port : Port_Type;
|
||||
@@ -78,10 +76,6 @@ is
|
||||
|
||||
procedure Legacy_VGA_Off;
|
||||
|
||||
procedure Scan_Ports
|
||||
(Configs : out Pipe_Configs;
|
||||
Ports : in Port_List;
|
||||
Max_Pipe : in Pipe_Index := Pipe_Index'Last);
|
||||
procedure Update_Outputs (Configs : Pipe_Configs);
|
||||
|
||||
pragma Warnings (GNATprove, Off, "subprogram ""Dump_Configs"" has no effect",
|
||||
@@ -99,6 +93,17 @@ is
|
||||
|
||||
private
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- State tracking for the currently configured pipes
|
||||
|
||||
Cur_Configs : Pipe_Configs with Part_Of => State;
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Internal representation of a single pipe's configuration
|
||||
|
||||
subtype Active_Port_Type is Port_Type
|
||||
range Port_Type'Succ (Disabled) .. Port_Type'Last;
|
||||
|
||||
type GPU_Port is (DIGI_A, DIGI_B, DIGI_C, DIGI_D, DIGI_E);
|
||||
|
||||
subtype Digital_Port is GPU_Port range DIGI_A .. DIGI_E;
|
||||
|
||||
Reference in New Issue
Block a user