| -- |
| -- Copyright (C) 2022 Google, LLC |
| -- |
| -- 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.DP_Info; |
| with HW.GFX.GMA.PCode; |
| |
| with HW.Debug; |
| with GNAT.Source_Info; |
| |
| use type HW.Word64; |
| |
| package body HW.GFX.GMA.Connectors.TC is |
| |
| function HIP_INDEX_REG (P : USBC_Port) return Registers.Registers_Index |
| is |
| (if P <= DDI_TC4 |
| then Registers.HIP_INDEX_REG0 |
| else Registers.HIP_INDEX_REG1); |
| |
| function HIP_INDEX_VAL (P : USBC_Port; Val : Word32) return Word32 is |
| (Val * 2 ** (8 * ((GPU_Port'Pos (P) - GPU_Port'Pos (DDI_TC1)) mod 4))); |
| |
| type Port_Regs_Array is array (USBC_Port) of Registers.Registers_Index; |
| DKL_DP_MODE : constant Port_Regs_Array := |
| (DDI_TC1 => Registers.DKL_DP_MODE_1, |
| DDI_TC2 => Registers.DKL_DP_MODE_2, |
| DDI_TC3 => Registers.DKL_DP_MODE_3, |
| DDI_TC4 => Registers.DKL_DP_MODE_4, |
| DDI_TC5 => Registers.DKL_DP_MODE_5, |
| DDI_TC6 => Registers.DKL_DP_MODE_6); |
| |
| function DP_PIN_ASSIGNMENT_SHIFT (P : USBC_Port) return natural is |
| (case P is |
| when DDI_TC1 => 0, |
| when DDI_TC2 => 4, |
| when DDI_TC3 => 8, |
| when DDI_TC4 => 12, |
| when DDI_TC5 => 16, |
| when DDI_TC6 => 20); |
| |
| DP_PIN_ASSIGNMENT_MASK : constant := 16#f#; |
| |
| TGL_PCODE_TCCOLD : constant := 16#26#; |
| TCCOLD_BLOCK_REQ : constant := 16#00#; |
| TCCOLD_UNBLOCK_REQ : constant := 16#01#; |
| TCCOLD_BLOCK_RESULT_FAIL : constant := 16#01#; |
| |
| type Fia_Regs_Record is record |
| PORT_TX_DFLEXDPMLE1 : Registers.Registers_Index; |
| PORT_TX_DFLEXDPSP : Registers.Registers_Index; |
| PORT_TX_DFLEXDPPMS : Registers.Registers_Index; |
| PORT_TX_DFLEXDPCSSS : Registers.Registers_Index; |
| PORT_TX_DFLEXPA1 : Registers.Registers_Index; |
| end record; |
| |
| Fia_Regs : constant array (USBC_Port) of Fia_Regs_Record := |
| (DDI_TC1 => |
| (Registers.PORT_TX_DFLEXDPMLE1_FIA1, |
| Registers.PORT_TX_DFLEXDPSP_FIA1, |
| Registers.PORT_TX_DFLEXDPPMS_FIA1, |
| Registers.PORT_TX_DFLEXDPCSSS_FIA1, |
| Registers.PORT_TX_DFLEXPA1_FIA1), |
| DDI_TC2 => |
| (Registers.PORT_TX_DFLEXDPMLE1_FIA1, |
| Registers.PORT_TX_DFLEXDPSP_FIA1, |
| Registers.PORT_TX_DFLEXDPPMS_FIA1, |
| Registers.PORT_TX_DFLEXDPCSSS_FIA1, |
| Registers.PORT_TX_DFLEXPA1_FIA1), |
| DDI_TC3 => |
| (Registers.PORT_TX_DFLEXDPMLE1_FIA2, |
| Registers.PORT_TX_DFLEXDPSP_FIA2, |
| Registers.PORT_TX_DFLEXDPPMS_FIA2, |
| Registers.PORT_TX_DFLEXDPCSSS_FIA2, |
| Registers.PORT_TX_DFLEXPA1_FIA2), |
| DDI_TC4 => |
| (Registers.PORT_TX_DFLEXDPMLE1_FIA2, |
| Registers.PORT_TX_DFLEXDPSP_FIA2, |
| Registers.PORT_TX_DFLEXDPPMS_FIA2, |
| Registers.PORT_TX_DFLEXDPCSSS_FIA2, |
| Registers.PORT_TX_DFLEXPA1_FIA2), |
| DDI_TC5 => |
| (Registers.PORT_TX_DFLEXDPMLE1_FIA3, |
| Registers.PORT_TX_DFLEXDPSP_FIA3, |
| Registers.PORT_TX_DFLEXDPPMS_FIA3, |
| Registers.PORT_TX_DFLEXDPCSSS_FIA3, |
| Registers.PORT_TX_DFLEXPA1_FIA3), |
| DDI_TC6 => |
| (Registers.PORT_TX_DFLEXDPMLE1_FIA3, |
| Registers.PORT_TX_DFLEXDPSP_FIA3, |
| Registers.PORT_TX_DFLEXDPPMS_FIA3, |
| Registers.PORT_TX_DFLEXDPCSSS_FIA3, |
| Registers.PORT_TX_DFLEXPA1_FIA3)); |
| |
| function Fia_Index (Port : USBC_Port) return natural |
| is (case Port is |
| when DDI_TC1 | DDI_TC3 | DDI_TC5 => 0, |
| when DDI_TC2 | DDI_TC4 | DDI_TC6 => 1); |
| |
| function DFLEXDPMLE1_DPMLETC_MASK (Port : USBC_Port) return Word32 is |
| (Shift_Left (15, 4 * Fia_Index (Port))); |
| function DFLEXDPMLE1_DPMLETC_ML0 (Port : USBC_Port) return Word32 is |
| (Shift_Left (1, 4 * Fia_Index (Port))); |
| function DFLEXDPMLE1_DPMLETC_ML1_0 (Port : USBC_Port) return Word32 is |
| (Shift_Left (3, 4 * Fia_Index (Port))); |
| function DFLEXDPMLE1_DPMLETC_ML3 (Port : USBC_Port) return Word32 is |
| (Shift_Left (8, 4 * Fia_Index (Port))); |
| function DFLEXDPMLE1_DPMLETC_ML3_2 (Port : USBC_Port) return Word32 is |
| (Shift_Left (12, 4 * Fia_Index (Port))); |
| function DFLEXDPMLE1_DPMLETC_ML3_0 (Port : USBC_Port) return Word32 is |
| (Shift_Left (15, 4 * Fia_Index (Port))); |
| function DP_PHY_MODE_STATUS_COMPLETE (Port : USBC_Port) return Word32 is |
| (Shift_Left (1, Fia_Index (Port))); |
| function DP_PHY_MODE_STATUS_NOT_SAFE (Port : USBC_Port) return Word32 is |
| (Shift_Left (1, Fia_Index (Port))); |
| function TC_LIVE_STATE_TC (Port : USBC_Port) return Word32 is |
| (Shift_Left (1, Fia_Index (Port) * 8 + 5)); |
| function DP_LANE_ASSIGNMENT_MASK (Port : USBC_Port) return Word32 is |
| (Shift_Left (16#f#, Fia_Index (Port) * 8)); |
| function DP_LANE_ASSIGNMENT_SHIFT (Port : USBC_Port) return natural is |
| (Fia_Index (Port) * 8); |
| |
| DDI_BUF_CTL_BUFFER_ENABLE : constant := 1 * 2 ** 31; |
| DDI_BUF_CTL_TRANS_SELECT_MASK : constant := 16#f# * 2 ** 24; |
| DDI_BUF_CTL_PORT_REVERSAL : constant := 1 * 2 ** 16; |
| DDI_BUF_CTL_PORT_WIDTH_MASK : constant := 7 * 2 ** 1; |
| DDI_BUF_CTL_PORT_WIDTH_1_LANE : constant := 0 * 2 ** 1; |
| DDI_BUF_CTL_PORT_WIDTH_2_LANES : constant := 1 * 2 ** 1; |
| DDI_BUF_CTL_PORT_WIDTH_4_LANES : constant := 3 * 2 ** 1; |
| DDI_BUF_CTL_IDLE_STATUS : constant := 1 * 2 ** 7; |
| |
| DDI_BUF_CTL_PORT_WIDTH : constant array (DP_Lane_Count) of Word32 := |
| (HW.GFX.DP_Lane_Count_1 => DDI_BUF_CTL_PORT_WIDTH_1_LANE, |
| HW.GFX.DP_Lane_Count_2 => DDI_BUF_CTL_PORT_WIDTH_2_LANES, |
| HW.GFX.DP_Lane_Count_4 => DDI_BUF_CTL_PORT_WIDTH_4_LANES); |
| DDI_BUF_CTL : constant Port_Regs_Array := |
| (DDI_TC1 => Registers.DDI_BUF_CTL_USBC1, |
| DDI_TC2 => Registers.DDI_BUF_CTL_USBC2, |
| DDI_TC3 => Registers.DDI_BUF_CTL_USBC3, |
| DDI_TC4 => Registers.DDI_BUF_CTL_USBC4, |
| DDI_TC5 => Registers.DDI_BUF_CTL_USBC5, |
| DDI_TC6 => Registers.DDI_BUF_CTL_USBC6); |
| |
| type Buffer_Trans is record |
| Vswing_Control : Word32; |
| Preshoot_Control : Word32; |
| Deemphasis_Control : Word32; |
| end record; |
| |
| type Buffer_Trans_Range is new natural range 0 .. 9; |
| type Buffer_Trans_Array is array (Buffer_Trans_Range) of Buffer_Trans; |
| TGL_Buffer_Trans_DP_HBR2 : constant Buffer_Trans_Array := |
| ((16#7#, 16#0#, 16#00#), |
| (16#5#, 16#0#, 16#05#), |
| (16#2#, 16#0#, 16#0B#), |
| (16#0#, 16#0#, 16#19#), |
| (16#5#, 16#0#, 16#00#), |
| (16#2#, 16#0#, 16#08#), |
| (16#0#, 16#0#, 16#14#), |
| (16#2#, 16#0#, 16#00#), |
| (16#0#, 16#0#, 16#0B#), |
| (16#0#, 16#0#, 16#00#)); |
| TGL_Buffer_Trans_DP_HBR : constant Buffer_Trans_Array := |
| ((16#7#, 16#0#, 16#00#), |
| (16#5#, 16#0#, 16#05#), |
| (16#2#, 16#0#, 16#0B#), |
| (16#0#, 16#0#, 16#18#), |
| (16#5#, 16#0#, 16#00#), |
| (16#2#, 16#0#, 16#08#), |
| (16#0#, 16#0#, 16#14#), |
| (16#2#, 16#0#, 16#00#), |
| (16#0#, 16#0#, 16#0B#), |
| (16#0#, 16#0#, 16#00#)); |
| Buffer_Trans_HDMI : constant Buffer_Trans_Array := |
| ((16#7#, 16#0#, 16#0#), |
| (16#6#, 16#0#, 16#0#), |
| (16#4#, 16#0#, 16#0#), |
| (16#2#, 16#0#, 16#0#), |
| (16#0#, 16#0#, 16#0#), |
| (16#0#, 16#0#, 16#5#), |
| (16#0#, 16#0#, 16#6#), |
| (16#0#, 16#0#, 16#7#), |
| (16#0#, 16#0#, 16#8#), |
| (16#0#, 16#0#, 16#A#)); |
| ADL_Buffer_Trans_DP_HBR2 : constant Buffer_Trans_Array := |
| ((16#7#, 16#0#, 16#00#), |
| (16#5#, 16#0#, 16#04#), |
| (16#2#, 16#0#, 16#0a#), |
| (16#0#, 16#0#, 16#18#), |
| (16#5#, 16#0#, 16#00#), |
| (16#2#, 16#0#, 16#06#), |
| (16#0#, 16#0#, 16#14#), |
| (16#2#, 16#0#, 16#00#), |
| (16#0#, 16#0#, 16#09#), |
| (16#0#, 16#0#, 16#00#)); |
| ADL_Buffer_Trans_DP_HBR : constant Buffer_Trans_Array := |
| ((16#7#, 16#0#, 16#01#), |
| (16#5#, 16#0#, 16#06#), |
| (16#2#, 16#0#, 16#0b#), |
| (16#0#, 16#0#, 16#17#), |
| (16#5#, 16#0#, 16#00#), |
| (16#2#, 16#0#, 16#08#), |
| (16#0#, 16#0#, 16#14#), |
| (16#2#, 16#0#, 16#00#), |
| (16#0#, 16#0#, 16#0b#), |
| (16#0#, 16#0#, 16#00#)); |
| |
| type Vswing_Regs_Record is record |
| DKL_TX_PMD_LANE_SUS : Registers.Registers_Index; |
| DKL_TX_DPCNTL0 : Registers.Registers_Index; |
| DKL_TX_DPCNTL1 : Registers.Registers_Index; |
| DKL_TX_DPCNTL2 : Registers.Registers_Index; |
| end record; |
| |
| Vswing_Regs : constant array (USBC_Port) of Vswing_Regs_Record := |
| (DDI_TC1 => |
| (Registers.DKL_TX_PMD_LANE_SUS_1, |
| Registers.DKL_TX_DPCNTL0_1, |
| Registers.DKL_TX_DPCNTL1_1, |
| Registers.DKL_TX_DPCNTL2_1), |
| DDI_TC2 => |
| (Registers.DKL_TX_PMD_LANE_SUS_2, |
| Registers.DKL_TX_DPCNTL0_2, |
| Registers.DKL_TX_DPCNTL1_2, |
| Registers.DKL_TX_DPCNTL2_2), |
| DDI_TC3 => |
| (Registers.DKL_TX_PMD_LANE_SUS_3, |
| Registers.DKL_TX_DPCNTL0_3, |
| Registers.DKL_TX_DPCNTL1_3, |
| Registers.DKL_TX_DPCNTL2_3), |
| DDI_TC4 => |
| (Registers.DKL_TX_PMD_LANE_SUS_4, |
| Registers.DKL_TX_DPCNTL0_4, |
| Registers.DKL_TX_DPCNTL1_4, |
| Registers.DKL_TX_DPCNTL2_4), |
| DDI_TC5 => |
| (Registers.DKL_TX_PMD_LANE_SUS_5, |
| Registers.DKL_TX_DPCNTL0_5, |
| Registers.DKL_TX_DPCNTL1_5, |
| Registers.DKL_TX_DPCNTL2_5), |
| DDI_TC6 => |
| (Registers.DKL_TX_PMD_LANE_SUS_6, |
| Registers.DKL_TX_DPCNTL0_6, |
| Registers.DKL_TX_DPCNTL1_6, |
| Registers.DKL_TX_DPCNTL2_6)); |
| |
| procedure Set_HIP_For_Port (P : USBC_Port; N : Natural) is |
| begin |
| Registers.Write (HIP_INDEX_REG (P), HIP_INDEX_VAL (P, Word32 (N))); |
| end Set_HIP_For_Port; |
| |
| subtype Pin_Assignment_Type is natural range 0 .. 6; |
| procedure Get_Pin_Assignment |
| (P : in USBC_Port; |
| Assignment : out Pin_Assignment_Type) |
| is |
| Tmp : Word32; |
| A : Word32; |
| begin |
| Registers.Read (Fia_Regs (P).PORT_TX_DFLEXPA1, Tmp); |
| A := Shift_Right (Tmp, DP_PIN_ASSIGNMENT_SHIFT (P)); |
| A := A and DP_PIN_ASSIGNMENT_MASK; |
| |
| if natural (A) in Pin_Assignment_Type then |
| Assignment := Pin_Assignment_Type (A); |
| else |
| Assignment := Pin_Assignment_Type'First; |
| end if; |
| end Get_Pin_Assignment; |
| |
| --------------------------------------------------------------------- |
| |
| procedure Program_DP_Mode (P : USBC_Port; Lane_Count : Natural) |
| is |
| MG_DP_MODE_CFG_DP_X1_MODE : constant := 1 * 2 ** 6; |
| MG_DP_MODE_CFG_DP_X2_MODE : constant := 1 * 2 ** 7; |
| DP_X_MODE_MASK : constant Word32 := |
| MG_DP_MODE_CFG_DP_X1_MODE or MG_DP_MODE_CFG_DP_X2_MODE; |
| Assignment : Pin_Assignment_Type; |
| Ln0, Ln1 : Word32; |
| begin |
| Set_HIP_For_Port (P, 0); |
| Registers.Read (DKL_DP_MODE (P), Ln0); |
| Set_HIP_For_Port (P, 1); |
| Registers.Read (DKL_DP_MODE (P), Ln1); |
| |
| Ln0 := Ln0 and not DP_X_MODE_MASK; |
| Ln1 := Ln1 and not DP_X_MODE_MASK; |
| |
| Get_Pin_Assignment (P, Assignment); |
| case Assignment is |
| when 0 => |
| if Lane_Count = 1 then |
| Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X1_MODE; |
| else |
| Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X2_MODE; |
| Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X2_MODE; |
| end if; |
| when 1 => |
| if Lane_Count = 4 then |
| Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X2_MODE; |
| Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X2_MODE; |
| end if; |
| when 2 => |
| if Lane_Count = 2 then |
| Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X2_MODE; |
| Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X2_MODE; |
| end if; |
| when 3 | 4 | 5 | 6 => |
| if Lane_Count = 1 then |
| Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X1_MODE; |
| Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X1_MODE; |
| else |
| Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X2_MODE; |
| Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X2_MODE; |
| end if; |
| end case; |
| |
| Set_HIP_For_Port (P, 0); |
| Registers.Unset_And_Set_Mask (DKL_DP_MODE (P), DP_X_MODE_MASK, Ln0); |
| Set_HIP_For_Port (P, 1); |
| Registers.Unset_And_Set_Mask (DKL_DP_MODE (P), DP_X_MODE_MASK, Ln1); |
| end Program_DP_Mode; |
| |
| --------------------------------------------------------------------- |
| |
| procedure TC_Cold_Request |
| (Request : in TC_Cold_Request_Type; |
| Success : out Boolean) |
| is |
| Result : Word64; |
| begin |
| for Try in 1 .. 3 loop |
| PCode.Mailbox_Read |
| (MBox => TGL_PCODE_TCCOLD, |
| Command => (if Request = Block |
| then TCCOLD_BLOCK_REQ |
| else TCCOLD_UNBLOCK_REQ), |
| Wait_Ready => True, |
| Reply => Result, |
| Success => Success); |
| |
| if Success then |
| Success := (Result and TCCOLD_BLOCK_RESULT_FAIL) = 0; |
| end if; |
| |
| exit when Success; |
| |
| -- Wait 1 millisecond and try again |
| Time.U_Delay (1_000); |
| end loop; |
| end TC_Cold_Request; |
| |
| --------------------------------------------------------------------- |
| |
| procedure Claim |
| (Port : in USBC_Port; |
| DP_Alt : in Boolean; |
| Success : out Boolean) |
| is |
| begin |
| -- For legacy ports, this is supposed to be |
| -- initialized once during boot, hence wait. |
| Registers.Wait_Set_Mask |
| (Register => Fia_Regs (Port).PORT_TX_DFLEXDPPMS, |
| Mask => DP_PHY_MODE_STATUS_COMPLETE (Port), |
| TOut_MS => (if DP_Alt then 0 else 100), |
| Success => Success); |
| if not Success then |
| pragma Debug (Debug.Put_Line ("DP PHY mode status not complete")); |
| return; |
| end if; |
| |
| Registers.Set_Mask |
| (Register => Fia_Regs (Port).PORT_TX_DFLEXDPCSSS, |
| Mask => DP_PHY_MODE_STATUS_NOT_SAFE (Port)); |
| end Claim; |
| |
| procedure Claimed (Port : USBC_Port; Is_Claimed : out Boolean) is |
| begin |
| if Port not in DDI_TC1 .. Config.Last_TC_Port then |
| Is_Claimed := False; |
| return; |
| end if; |
| |
| Registers.Is_Set_Mask |
| (Register => Fia_Regs (Port).PORT_TX_DFLEXDPCSSS, |
| Mask => DP_PHY_MODE_STATUS_NOT_SAFE (Port), |
| Result => Is_Claimed); |
| end Claimed; |
| |
| --------------------------------------------------------------------- |
| |
| procedure Connect |
| (Port : in USBC_Port; |
| DP_Alt : in Boolean; |
| Lanes : in DP_Lane_Count; |
| Success : out Boolean) |
| is |
| procedure Get_Lane_Assignment_Count (Lanes : out DP_Lane_Count) |
| is |
| Lane_Mask : Word32; |
| Tmp : Word32; |
| begin |
| Registers.Read (Fia_Regs (Port).PORT_TX_DFLEXDPSP, Tmp); |
| Lane_Mask := Shift_Right (Tmp and DP_LANE_ASSIGNMENT_MASK (Port), |
| DP_LANE_ASSIGNMENT_SHIFT (Port)); |
| Lanes := |
| (case Lane_Mask is |
| when 16#1# | 16#2# | 16#4# | 16#8# => DP_Lane_Count_1, |
| when 16#3# | 16#c# => DP_Lane_Count_2, |
| when 16#f# => DP_Lane_Count_4, |
| when others => DP_Lane_Count_1); |
| end Get_Lane_Assignment_Count; |
| |
| procedure Set_Lane_Count (Lanes : DP_Lane_Count) is |
| begin |
| Registers.Unset_And_Set_Mask |
| (Register => Fia_Regs (Port).PORT_TX_DFLEXDPMLE1, |
| Mask_Unset => DFLEXDPMLE1_DPMLETC_MASK (Port), |
| Mask_Set => |
| (case Lanes is |
| -- ML0 is not lane-reversed, ML3 is reverse |
| when DP_Lane_Count_1 => DFLEXDPMLE1_DPMLETC_ML0 (Port), |
| -- ML1_0 is not reversed, ML3_2 is reverse |
| when DP_Lane_Count_2 => DFLEXDPMLE1_DPMLETC_ML1_0 (Port), |
| -- symmetric |
| when DP_Lane_Count_4 => DFLEXDPMLE1_DPMLETC_ML3_0 (Port))); |
| end Set_Lane_Count; |
| |
| Assigned_Lanes : DP_Lane_Count; |
| begin |
| Claimed (Port, Success); |
| if not Success then |
| pragma Debug (Debug.Put_Line ("Tried to connect to unclaimed port.")); |
| return; |
| end if; |
| |
| if DP_Alt then |
| Registers.Is_Set_Mask |
| (Register => Fia_Regs (Port).PORT_TX_DFLEXDPSP, |
| Mask => TC_LIVE_STATE_TC (Port), |
| Result => Success); |
| if not Success then |
| pragma Debug (Debug.Put_Line ("DP-Alt is not connected.")); |
| return; |
| end if; |
| |
| Get_Lane_Assignment_Count (Assigned_Lanes); |
| Set_Lane_Count (Assigned_Lanes); |
| else |
| Set_Lane_Count (Lanes); |
| end if; |
| end Connect; |
| |
| --------------------------------------------------------------------- |
| |
| procedure Disconnect (Port : USBC_Port) is |
| begin |
| if Port in DDI_TC1 .. Config.Last_TC_Port then |
| Registers.Unset_Mask |
| (Register => Fia_Regs (Port).PORT_TX_DFLEXDPCSSS, |
| Mask => DP_PHY_MODE_STATUS_NOT_SAFE (Port)); |
| end if; |
| end Disconnect; |
| |
| --------------------------------------------------------------------- |
| |
| procedure Set_Vswing_And_Deemphasis |
| (Port : USBC_Port; |
| Buf_Trans : Buffer_Trans) |
| is |
| -- Preshoot Coeff, Deemphasis Coeff, VSwing Control, |
| DPcnt_Mask : constant Word32 := 16#3_ff07#; |
| DPcnt_Val : constant Word32 := |
| Buf_Trans.Vswing_Control or |
| Shift_Left (Buf_Trans.Deemphasis_Control, 8) or |
| Shift_Left (Buf_Trans.Preshoot_Control, 13); |
| DKL_TX_DP20BITMODE : constant := 1 * 2 ** 2; |
| begin |
| for Lane in 0 .. 1 loop |
| Set_HIP_For_Port (Port, Lane); |
| Registers.Write (Vswing_Regs (Port).DKL_TX_PMD_LANE_SUS, 0); |
| Registers.Unset_And_Set_Mask |
| (Vswing_Regs (Port).DKL_TX_DPCNTL0, DPcnt_Mask, DPcnt_Val); |
| Registers.Unset_And_Set_Mask |
| (Vswing_Regs (Port).DKL_TX_DPCNTL1, DPcnt_Mask, DPcnt_Val); |
| Registers.Unset_Mask |
| (Vswing_Regs (Port).DKL_TX_DPCNTL2, DKL_TX_DP20BITMODE); |
| end loop; |
| |
| end Set_Vswing_And_Deemphasis; |
| |
| --------------------------------------------------------------------- |
| |
| procedure Set_Signal_Levels |
| (Port : USBC_Port; |
| Link : DP_Link; |
| Train_Set : DP_Info.Train_Set) |
| is |
| function To_Buf_Trans_Index |
| (Set : DP_Info.Train_Set) return Buffer_Trans_Range |
| is |
| begin |
| case Set.Voltage_Swing is |
| when DP_Info.VS_Level_0 => |
| case Set.Pre_Emph is |
| when DP_Info.Emph_Level_0 => return 0; |
| when DP_Info.Emph_Level_1 => return 1; |
| when DP_Info.Emph_Level_2 => return 2; |
| when DP_Info.Emph_Level_3 => return 3; |
| end case; |
| when DP_Info.VS_Level_1 => |
| case Set.Pre_Emph is |
| when DP_Info.Emph_Level_0 => return 4; |
| when DP_Info.Emph_Level_1 => return 5; |
| when DP_Info.Emph_Level_2 => return 6; |
| when others => return 0; |
| end case; |
| when DP_Info.VS_Level_2 => |
| case Set.Pre_Emph is |
| when DP_Info.Emph_Level_0 => return 7; |
| when DP_Info.Emph_Level_1 => return 8; |
| when others => return 0; |
| end case; |
| when DP_Info.VS_Level_3 => |
| case Set.Pre_Emph is |
| when DP_Info.Emph_Level_0 => return 9; |
| when others => return 0; |
| end case; |
| end case; |
| end To_Buf_Trans_Index; |
| |
| Was_Enabled : Boolean; |
| Buf_Trans : Buffer_Trans; |
| Entry_Index : constant Buffer_Trans_Range := |
| To_Buf_Trans_Index (Train_Set); |
| begin |
| pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); |
| |
| Registers.Is_Set_Mask |
| (Register => DDI_BUF_CTL (Port), |
| Mask => DDI_BUF_CTL_BUFFER_ENABLE, |
| Result => Was_Enabled); |
| |
| if Config.Has_TGL_Buffer_Translations then |
| if Link.Bandwidth > DP_Bandwidth_2_7 then |
| Buf_Trans := TGL_Buffer_Trans_DP_HBR2 (Entry_Index); |
| else |
| Buf_Trans := TGL_Buffer_Trans_DP_HBR (Entry_Index); |
| end if; |
| else |
| if Link.Bandwidth > DP_Bandwidth_2_7 then |
| Buf_Trans := ADL_Buffer_Trans_DP_HBR2 (Entry_Index); |
| else |
| Buf_Trans := ADL_Buffer_Trans_DP_HBR (Entry_Index); |
| end if; |
| end if; |
| |
| Set_Vswing_And_Deemphasis (Port, Buf_Trans); |
| |
| Registers.Unset_And_Set_Mask |
| (Register => DDI_BUF_CTL (Port), |
| Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or |
| DDI_BUF_CTL_PORT_REVERSAL or |
| DDI_BUF_CTL_PORT_WIDTH_MASK, |
| Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE or |
| DDI_BUF_CTL_PORT_WIDTH (Link.Lane_Count)); |
| Registers.Posting_Read (DDI_BUF_CTL (Port)); |
| |
| if not Was_Enabled then |
| Registers.Wait_Unset_Mask (DDI_BUF_CTL (Port), DDI_BUF_CTL_IDLE_STATUS); |
| end if; |
| end Set_Signal_Levels; |
| |
| procedure Enable_HDMI (Port : USBC_Port) |
| is |
| HDMI_Lane_Count : constant := 4; |
| Buf_Trans : constant Buffer_Trans := |
| Buffer_Trans_HDMI (Buffer_Trans_HDMI'Last); |
| begin |
| Program_DP_Mode (Port, HDMI_Lane_Count); |
| Set_Vswing_And_Deemphasis (Port, Buf_Trans); |
| |
| Registers.Unset_And_Set_Mask |
| (Register => DDI_BUF_CTL (Port), |
| Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or |
| DDI_BUF_CTL_PORT_REVERSAL or |
| DDI_BUF_CTL_PORT_WIDTH_MASK, |
| Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE); |
| |
| Registers.Wait_Unset_Mask |
| (Register => DDI_BUF_CTL (Port), |
| Mask => DDI_BUF_CTL_IDLE_STATUS, |
| TOut_MS => 1); |
| end Enable_HDMI; |
| |
| end HW.GFX.GMA.Connectors.TC; |