gma tgl: Add port detection
Block TCCOLD during initialization so that Modular FIA registers can be
accessed. Instead of keeping track of the state of TCCOLD all of the
time (and enabling and re-enabling), this patch just blocks TCCOLD
once during initializaton and leaves it that way.
We don't have any knowledge yet if a TC port is used in legacy DP/HDMI
mode or not, so we always handle hotplug events in both hardware blocks.
Signed-off-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Change-Id: I674e7c2dcd7738e3d76266ff36675dbd52fa5ae2
Reviewed-on: https://review.sourcearcade.org/c/libgfxinit/+/470
Tested-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: Ada SPARK <gnatbot@sourcearcade.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
diff --git a/common/tigerlake/hw-gfx-gma-port_detect.adb b/common/tigerlake/hw-gfx-gma-port_detect.adb
index a0bad14..9c8c27b 100644
--- a/common/tigerlake/hw-gfx-gma-port_detect.adb
+++ b/common/tigerlake/hw-gfx-gma-port_detect.adb
@@ -1,5 +1,6 @@
--
-- Copyright (C) Google, LLC
+-- Copyright (C) 2024 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
@@ -15,33 +16,165 @@
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Registers;
with HW.GFX.GMA.Config_Helpers;
+with HW.GFX.GMA.Connectors.TC;
with HW.Debug;
with GNAT.Source_Info;
package body HW.GFX.GMA.Port_Detect
is
- procedure Initialize is
+ SHOTPLUG_CTL_DDI_HPD_STATUS_MASK : constant := 16#0333#;
+
+ function SHOTPLUG_CTL_DDI_HPD_ENABLE (P : Combo_Port) return Word32 is
+ (Shift_Left (8, 4 * (GPU_Port'Pos (P) - GPU_Port'Pos (Combo_Port'First))));
+
+ function SHOTPLUG_CTL_DDI_HPD_STATUS (P : Combo_Port) return Word32 is
+ (Shift_Left (3, 4 * (GPU_Port'Pos (P) - GPU_Port'Pos (Combo_Port'First))));
+
+ function SHOTPLUG_CTL_DDI_HPD_LONG_DETECT (P : Combo_Port) return Word32 is
+ (Shift_Left (2, 4 * (GPU_Port'Pos (P) - GPU_Port'Pos (Combo_Port'First))));
+
+ SHOTPLUG_CTL_TC_DDI_HPD_STATUS_MASK : constant := 16#0033_3333#;
+
+ function SHOTPLUG_CTL_TC_DDI_HPD_ENABLE (P : USBC_Port) return Word32 is
+ (Shift_Left (8, 4 * (GPU_Port'Pos (P) - GPU_Port'Pos (USBC_Port'First))));
+
+ function SHOTPLUG_CTL_TC_DDI_HPD_STATUS (P : USBC_Port) return Word32 is
+ (Shift_Left (3, 4 * (GPU_Port'Pos (P) - GPU_Port'Pos (USBC_Port'First))));
+
+ function SHOTPLUG_CTL_TC_DDI_HPD_LONG_DETECT (P : USBC_Port) return Word32 is
+ (Shift_Left (2, 4 * (GPU_Port'Pos (P) - GPU_Port'Pos (USBC_Port'First))));
+
+ TC_HOTPLUG_CTL_HPD_STATUS_MASK : constant := 16#0033_3333#;
+
+ function TC_HOTPLUG_CTL_HPD_ENABLE (P : USBC_Port) return Word32 renames
+ SHOTPLUG_CTL_TC_DDI_HPD_ENABLE;
+
+ function TC_HOTPLUG_CTL_HPD_STATUS (P : USBC_Port) return Word32 renames
+ SHOTPLUG_CTL_TC_DDI_HPD_STATUS;
+
+ procedure Initialize
+ is
+ Success : Boolean;
begin
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ Registers.Unset_And_Set_Mask
+ (Register => Registers.SHPD_FILTER_CNT,
+ Mask_Unset => 16#1_ffff#,
+ Mask_Set => 16#1d9#); -- constant from i915 (SHPD_FILTER_CNT_500_ADJ)
+
+ -- Hotplug for combo ports
+ Registers.Set_Mask
+ (Register => Registers.SHOTPLUG_CTL,
+ Mask =>
+ SHOTPLUG_CTL_DDI_HPD_ENABLE (DIGI_A) or
+ SHOTPLUG_CTL_DDI_HPD_ENABLE (DIGI_B) or
+ SHOTPLUG_CTL_DDI_HPD_ENABLE (DIGI_C) or
+ SHOTPLUG_CTL_DDI_HPD_STATUS_MASK); -- clear status
+
+ -- Validity can only be detected via hotplug.
+ -- DP3/HDMI3 doesn't exist in any TGL SKU.
+ for Port in DP1 .. DP2 loop
+ Config.Valid_Port (Port) := True;
+ end loop;
+ for Port in DP_TC1 .. DP_TC4 loop
+ Config.Valid_Port (Port) := True;
+ end loop;
+ for Port in HDMI1 .. HDMI2 loop
+ Config.Valid_Port (Port) := True;
+ end loop;
+ for Port in HDMI_TC1 .. HDMI_TC4 loop
+ Config.Valid_Port (Port) := True;
+ end loop;
+ for Port in USBC1 .. USBC4 loop
+ Config.Valid_Port (Port) := True;
+ end loop;
+
+ for Port in DDI_TC1 .. Config.Last_TC_Port loop
+ -- Hotplug for Type-C ports in legacy mode
+ Registers.Set_Mask
+ (Register => Registers.SHOTPLUG_CTL_TC,
+ Mask => SHOTPLUG_CTL_TC_DDI_HPD_ENABLE (Port));
+ -- Hotplug for Type-C ports in DP-Alt mode
+ Registers.Set_Mask
+ (Register => Registers.TC_HOTPLUG_CTL,
+ Mask => TC_HOTPLUG_CTL_HPD_ENABLE (Port));
+ end loop;
+
+ -- Clear status:
+ Registers.Set_Mask
+ (Register => Registers.SHOTPLUG_CTL_TC,
+ Mask => SHOTPLUG_CTL_TC_DDI_HPD_STATUS_MASK);
+ Registers.Set_Mask
+ (Register => Registers.TC_HOTPLUG_CTL,
+ Mask => TC_HOTPLUG_CTL_HPD_STATUS_MASK);
+
+ -- TCCOLD should be blocked first before accessing FIA registers
+ -- during e.g. connect flows. It can be unblocked only after done
+ -- accessing FIA registers and there is no longer a connection
+ -- i.e., after all ports are disconnected.
+ -- In order to avoid keeping track of the state and constantly
+ -- blocking and unblocking, we just block it once at the beginning
+ -- and leave it that way.
+ Connectors.TC.TC_Cold_Request (Connectors.TC.Block, Success);
+ if not Success then
+ Debug.Put_Line ("Failed to block TCCOLD, Type-C will not work!");
+ return;
+ end if;
end Initialize;
- pragma Warnings (Off, "unused variable ""Port""",
- Reason => "Not yet implemented.");
procedure Hotplug_Detect
(Port : in Active_Port_Type;
Detected : out Boolean)
is
+ GPU_Port : constant GMA.GPU_Port := Config_Helpers.To_GPU_Port (Pipe_Index'First, Port);
+ North32, South32 : Word32;
begin
- pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Detected := False;
+
+ if GPU_Port in USBC_Port then
+ Registers.Read (Registers.TC_HOTPLUG_CTL, North32, Verbose => False);
+ Registers.Read (Registers.SHOTPLUG_CTL_TC, South32, Verbose => False);
+
+ Detected := ((North32 or South32) and
+ SHOTPLUG_CTL_TC_DDI_HPD_LONG_DETECT (GPU_Port)) /= 0;
+
+ if (North32 and TC_HOTPLUG_CTL_HPD_STATUS (GPU_Port)) /= 0 then
+ Registers.Unset_And_Set_Mask
+ (Register => Registers.TC_HOTPLUG_CTL,
+ Mask_Unset => TC_HOTPLUG_CTL_HPD_STATUS_MASK,
+ Mask_Set => TC_HOTPLUG_CTL_HPD_STATUS (GPU_Port));
+ end if;
+ if (South32 and TC_HOTPLUG_CTL_HPD_STATUS (GPU_Port)) /= 0 then
+ Registers.Unset_And_Set_Mask
+ (Register => Registers.SHOTPLUG_CTL_TC,
+ Mask_Unset => SHOTPLUG_CTL_TC_DDI_HPD_STATUS_MASK,
+ Mask_Set => SHOTPLUG_CTL_TC_DDI_HPD_STATUS (GPU_Port));
+ end if;
+ end if;
+
+ if GPU_Port in Combo_Port then
+ Registers.Read (Registers.SHOTPLUG_CTL, South32, Verbose => False);
+ Detected := (South32 and SHOTPLUG_CTL_DDI_HPD_LONG_DETECT (GPU_Port)) /= 0;
+
+ if (South32 and SHOTPLUG_CTL_DDI_HPD_STATUS (GPU_Port)) /= 0 then
+ Registers.Unset_And_Set_Mask
+ (Register => Registers.SHOTPLUG_CTL,
+ Mask_Unset => SHOTPLUG_CTL_DDI_HPD_STATUS_MASK,
+ Mask_Set => SHOTPLUG_CTL_DDI_HPD_STATUS (GPU_Port));
+ end if;
+ end if;
end Hotplug_Detect;
- pragma Warnings (On, "unused variable ""Port""");
procedure Clear_Hotplug_Detect (Port : Active_Port_Type)
is
+ Ignored_HPD : Boolean;
begin
- pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+ pragma Warnings (GNATprove, Off, "unused assignment to ""Ignored_HPD""",
+ Reason => "We want to clear pending events only");
+ Port_Detect.Hotplug_Detect (Port, Ignored_HPD);
+ pragma Warnings (GNATprove, On, "unused assignment to ""Ignored_HPD""");
end Clear_Hotplug_Detect;
end HW.GFX.GMA.Port_Detect;