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>
diff --git a/common/hw-gfx-gma.adb b/common/hw-gfx-gma.adb
index 4b09d51..0a5b1b5 100644
--- a/common/hw-gfx-gma.adb
+++ b/common/hw-gfx-gma.adb
@@ -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 @@
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 @@
----------------------------------------------------------------------------
- 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 @@
----------------------------------------------------------------------------
- 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 @@
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 @@
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);