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-config_helpers.adb b/common/hw-gfx-gma-config_helpers.adb
new file mode 100644
index 0000000..31406cf
--- /dev/null
+++ b/common/hw-gfx-gma-config_helpers.adb
@@ -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;