blob: 9c8c27b747b870abb0a080d97807f8083a565d03 [file] [log] [blame]
--
-- 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
-- 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.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
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;
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
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;
procedure Clear_Hotplug_Detect (Port : Active_Port_Type)
is
Ignored_HPD : Boolean;
begin
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;