| -- |
| -- Copyright (C) 2015-2018 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.Debug; |
| with GNAT.Source_Info; |
| |
| with HW.GFX.GMA.DP_Info; |
| |
| package body HW.GFX.GMA.Transcoder is |
| |
| type Default_Transcoder_Array is array (Pipe_Index) of Transcoder_Index; |
| Default_Transcoder : constant Default_Transcoder_Array := |
| (Primary => Trans_A, |
| Secondary => Trans_B, |
| Tertiary => Trans_C); |
| |
| function Get_Idx (Pipe : Pipe_Index; Port : GPU_Port) return Transcoder_Index |
| is |
| begin |
| return |
| (if Config.Has_EDP_Transcoder and then Port = DIGI_A then |
| Trans_EDP |
| else |
| Default_Transcoder (Pipe)); |
| end Get_Idx; |
| |
| ---------------------------------------------------------------------------- |
| |
| TRANS_CLK_SEL_PORT_NONE : constant := 0 * 2 ** 29; |
| |
| type TRANS_CLK_SEL_PORT_Array is |
| array (Digital_Port) of Word32; |
| TRANS_CLK_SEL_PORT : constant TRANS_CLK_SEL_PORT_Array := |
| (DIGI_A => 0 * 2 ** 29, -- DDI A is not selectable |
| DIGI_B => 2 * 2 ** 29, |
| DIGI_C => 3 * 2 ** 29, |
| DIGI_D => 4 * 2 ** 29, |
| DIGI_E => 5 * 2 ** 29); |
| |
| TRANS_CONF_ENABLE : constant := 1 * 2 ** 31; |
| TRANS_CONF_ENABLED_STATUS : constant := 1 * 2 ** 30; |
| TRANS_CONF_ENABLE_DITHER : constant := 1 * 2 ** 4; |
| |
| type BPC_Array is array (BPC_Type) of Word32; |
| TRANS_CONF_BPC : constant BPC_Array := |
| (6 => 2 * 2 ** 5, |
| 8 => 0 * 2 ** 5, |
| 10 => 1 * 2 ** 5, |
| 12 => 3 * 2 ** 5, |
| others => 0 * 2 ** 5); -- default to 8 BPC |
| |
| function BPC_Conf (BPC : BPC_Type; Dither : Boolean) return Word32 is |
| begin |
| return |
| (if Config.Has_Pipeconf_BPC then TRANS_CONF_BPC (BPC) else 0) or |
| (if Dither then TRANS_CONF_ENABLE_DITHER else 0); |
| end BPC_Conf; |
| |
| ---------------------------------------------------------------------------- |
| |
| DDI_FUNC_CTL_ENABLE : constant := 1 * 2 ** 31; |
| DDI_FUNC_CTL_MODE_SELECT_MASK : constant := 7 * 2 ** 24; |
| DDI_FUNC_CTL_MODE_SELECT_HDMI : constant := 0 * 2 ** 24; |
| DDI_FUNC_CTL_MODE_SELECT_DVI : constant := 1 * 2 ** 24; |
| DDI_FUNC_CTL_MODE_SELECT_DP_SST : constant := 2 * 2 ** 24; |
| DDI_FUNC_CTL_MODE_SELECT_DP_MST : constant := 3 * 2 ** 24; |
| DDI_FUNC_CTL_MODE_SELECT_FDI : constant := 4 * 2 ** 24; |
| |
| type DDI_Select_Array is array (Digital_Port) of Word32; |
| DDI_FUNC_CTL_DDI_SELECT : constant DDI_Select_Array := |
| (DIGI_A => 0 * 2 ** 28, |
| DIGI_B => 1 * 2 ** 28, |
| DIGI_C => 2 * 2 ** 28, |
| DIGI_D => 3 * 2 ** 28, |
| DIGI_E => 4 * 2 ** 28); |
| |
| type DDI_Mode_Array is array (Display_Type) of Word32; |
| DDI_FUNC_CTL_MODE_SELECT : constant DDI_Mode_Array := |
| (VGA => DDI_FUNC_CTL_MODE_SELECT_FDI, |
| HDMI => DDI_FUNC_CTL_MODE_SELECT_DVI, |
| DP => DDI_FUNC_CTL_MODE_SELECT_DP_SST, |
| others => 0); |
| |
| type HV_Sync_Array is array (Boolean) of Word32; |
| DDI_FUNC_CTL_VSYNC : constant HV_Sync_Array := |
| (False => 0 * 2 ** 17, |
| True => 1 * 2 ** 17); |
| DDI_FUNC_CTL_HSYNC : constant HV_Sync_Array := |
| (False => 0 * 2 ** 16, |
| True => 1 * 2 ** 16); |
| |
| DDI_FUNC_CTL_EDP_SELECT_MASK : constant := 7 * 2 ** 12; |
| DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON : constant := 0 * 2 ** 12; |
| DDI_FUNC_CTL_EDP_SELECT : constant array (Pipe_Index) of Word32 := |
| (Primary => 4 * 2 ** 12, |
| Secondary => 5 * 2 ** 12, |
| Tertiary => 6 * 2 ** 12); |
| |
| type Port_Width_Array is array (DP_Lane_Count) of Word32; |
| DDI_FUNC_CTL_PORT_WIDTH : constant Port_Width_Array := |
| (DP_Lane_Count_1 => 0 * 2 ** 1, |
| DP_Lane_Count_2 => 1 * 2 ** 1, |
| DP_Lane_Count_4 => 3 * 2 ** 1); |
| |
| DDI_FUNC_CTL_BPC : constant BPC_Array := |
| (6 => 2 * 2 ** 20, |
| 8 => 0 * 2 ** 20, |
| 10 => 1 * 2 ** 20, |
| 12 => 3 * 2 ** 20, |
| others => 0 * 2 ** 20); -- default to 8 BPC |
| |
| ---------------------------------------------------------------------------- |
| |
| TRANS_MSA_MISC_SYNC_CLK : constant := 1 * 2 ** 0; |
| TRANS_MSA_MISC_BPC : constant BPC_Array := |
| (6 => 0 * 2 ** 5, |
| 8 => 1 * 2 ** 5, |
| 10 => 2 * 2 ** 5, |
| 12 => 3 * 2 ** 5, |
| 16 => 4 * 2 ** 5, |
| others => 1 * 2 ** 5); -- default to 8 BPC |
| |
| function TRANS_DATA_M_TU (Transfer_Unit : Positive) return Word32 is |
| begin |
| return Shift_Left (Word32 (Transfer_Unit - 1), 25); |
| end TRANS_DATA_M_TU; |
| |
| ---------------------------------------------------------------------------- |
| |
| function Encode (LSW, MSW : Pos32) return Word32 is |
| begin |
| return Shift_Left (Word32 (MSW - 1), 16) or Word32 (LSW - 1); |
| end Encode; |
| |
| ---------------------------------------------------------------------------- |
| |
| procedure Setup_Link |
| (Trans : Transcoder_Regs; |
| Link : DP_Link; |
| Mode : Mode_Type) |
| with |
| Global => (In_Out => Registers.Register_State), |
| Depends => (Registers.Register_State =>+ (Trans, Link, Mode)) |
| is |
| Data_M, Link_M : DP_Info.M_Type; |
| Data_N, Link_N : DP_Info.N_Type; |
| begin |
| pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); |
| |
| DP_Info.Calculate_M_N |
| (Link => Link, |
| Mode => Mode, |
| Data_M => Data_M, |
| Data_N => Data_N, |
| Link_M => Link_M, |
| Link_N => Link_N); |
| |
| Registers.Write |
| (Register => Trans.DATA_M1, |
| Value => TRANS_DATA_M_TU (64) or |
| Word32 (Data_M)); |
| Registers.Write |
| (Register => Trans.DATA_N1, |
| Value => Word32 (Data_N)); |
| |
| Registers.Write |
| (Register => Trans.LINK_M1, |
| Value => Word32 (Link_M)); |
| Registers.Write |
| (Register => Trans.LINK_N1, |
| Value => Word32 (Link_N)); |
| |
| if Config.Has_Pipe_MSA_Misc then |
| Registers.Write |
| (Register => Trans.MSA_MISC, |
| Value => TRANS_MSA_MISC_SYNC_CLK or |
| TRANS_MSA_MISC_BPC (Mode.BPC)); |
| end if; |
| end Setup_Link; |
| |
| ---------------------------------------------------------------------------- |
| |
| procedure Setup |
| (Pipe : Pipe_Index; |
| Port_Cfg : Port_Config) |
| is |
| use type HW.GFX.GMA.Registers.Registers_Invalid_Index; |
| |
| Trans : Transcoder_Regs renames |
| Transcoders (Get_Idx (Pipe, Port_Cfg.Port)); |
| M : constant Mode_Type := Port_Cfg.Mode; |
| begin |
| pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); |
| |
| if Config.Has_Trans_Clk_Sel and then |
| Trans.CLK_SEL /= Registers.Invalid_Register and then |
| Port_Cfg.Port in Digital_Port |
| then |
| Registers.Write |
| (Register => Trans.CLK_SEL, |
| Value => TRANS_CLK_SEL_PORT (Port_Cfg.Port)); |
| end if; |
| |
| if Port_Cfg.Is_FDI then |
| Setup_Link (Trans, Port_Cfg.FDI, Port_Cfg.Mode); |
| elsif Port_Cfg.Display = DP then |
| Setup_Link (Trans, Port_Cfg.DP, Port_Cfg.Mode); |
| end if; |
| |
| Registers.Write (Trans.HTOTAL, Encode (M.H_Visible, M.H_Total)); |
| Registers.Write (Trans.HBLANK, Encode (M.H_Visible, M.H_Total)); |
| Registers.Write (Trans.HSYNC, Encode (M.H_Sync_Begin, M.H_Sync_End)); |
| Registers.Write (Trans.VTOTAL, Encode (M.V_Visible, M.V_Total)); |
| Registers.Write (Trans.VBLANK, Encode (M.V_Visible, M.V_Total)); |
| Registers.Write (Trans.VSYNC, Encode (M.V_Sync_Begin, M.V_Sync_End)); |
| end Setup; |
| |
| ---------------------------------------------------------------------------- |
| |
| procedure On |
| (Pipe : Pipe_Index; |
| Port_Cfg : Port_Config; |
| Dither : Boolean; |
| Scale : Boolean) |
| is |
| Trans : Transcoder_Regs renames |
| Transcoders (Get_Idx (Pipe, Port_Cfg.Port)); |
| Lane_Count : constant DP_Lane_Count := |
| (if Port_Cfg.Is_FDI then Port_Cfg.FDI.Lane_Count else Port_Cfg.DP.Lane_Count); |
| EDP_Select : constant Word32 := |
| (if Pipe = Primary and |
| (not Config.Use_PDW_For_EDP_Scaling or else not Scale) |
| then |
| DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON |
| else |
| DDI_FUNC_CTL_EDP_SELECT (Pipe)); |
| begin |
| if Config.Has_Pipe_DDI_Func and Port_Cfg.Port in Digital_Port then |
| Registers.Write |
| (Register => Trans.DDI_FUNC_CTL, |
| Value => DDI_FUNC_CTL_ENABLE or |
| DDI_FUNC_CTL_DDI_SELECT (Port_Cfg.Port) or |
| DDI_FUNC_CTL_MODE_SELECT (Port_Cfg.Display) or |
| DDI_FUNC_CTL_BPC (Port_Cfg.Mode.BPC) or |
| DDI_FUNC_CTL_VSYNC (Port_Cfg.Mode.V_Sync_Active_High) or |
| DDI_FUNC_CTL_HSYNC (Port_Cfg.Mode.H_Sync_Active_High) or |
| EDP_Select or |
| DDI_FUNC_CTL_PORT_WIDTH (Lane_Count)); |
| end if; |
| |
| Registers.Write |
| (Register => Trans.CONF, |
| Value => TRANS_CONF_ENABLE or |
| (if not Config.Has_Pipeconf_Misc then |
| BPC_Conf (Port_Cfg.Mode.BPC, Dither) else 0)); |
| Registers.Posting_Read (Trans.CONF); |
| end On; |
| |
| ---------------------------------------------------------------------------- |
| |
| procedure Trans_Off (Trans : Transcoder_Regs) |
| is |
| Enabled : Boolean; |
| begin |
| Registers.Is_Set_Mask (Trans.CONF, TRANS_CONF_ENABLE, Enabled); |
| |
| if Enabled then |
| Registers.Unset_Mask (Trans.CONF, TRANS_CONF_ENABLE); |
| end if; |
| |
| -- Workaround for Broadwell: |
| -- Status may be wrong if pipe hasn't been enabled since reset. |
| if not Config.Pipe_Enabled_Workaround or else Enabled then |
| -- synchronously wait until pipe is truly off |
| Registers.Wait_Unset_Mask |
| (Register => Trans.CONF, |
| Mask => TRANS_CONF_ENABLED_STATUS, |
| TOut_MS => 40); |
| end if; |
| |
| if Config.Has_Pipe_DDI_Func then |
| Registers.Write (Trans.DDI_FUNC_CTL, 0); |
| end if; |
| end Trans_Off; |
| |
| procedure Off (Pipe : Pipe_Index) |
| is |
| DDI_Func_Ctl : Word32; |
| begin |
| if Config.Has_EDP_Transcoder then |
| Registers.Read (Registers.PIPE_EDP_DDI_FUNC_CTL, DDI_Func_Ctl); |
| DDI_Func_Ctl := DDI_Func_Ctl and DDI_FUNC_CTL_EDP_SELECT_MASK; |
| |
| if (Pipe = Primary and |
| DDI_Func_Ctl = DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON) or |
| DDI_Func_Ctl = DDI_FUNC_CTL_EDP_SELECT (Pipe) |
| then |
| Trans_Off (Transcoders (Trans_EDP)); |
| end if; |
| end if; |
| |
| Trans_Off (Transcoders (Default_Transcoder (Pipe))); |
| end Off; |
| |
| procedure Clk_Off (Pipe : Pipe_Index) |
| is |
| use type Registers.Registers_Invalid_Index; |
| |
| Trans : Transcoder_Regs renames Transcoders (Default_Transcoder (Pipe)); |
| begin |
| if Config.Has_Trans_Clk_Sel and then |
| Trans.CLK_SEL /= Registers.Invalid_Register |
| then |
| Registers.Write (Trans.CLK_SEL, TRANS_CLK_SEL_PORT_NONE); |
| end if; |
| end Clk_Off; |
| |
| ---------------------------------------------------------------------------- |
| |
| SRD_CTL_ENABLE : constant := 1 * 2 ** 31; |
| SRD_STATUS_STATE_MASK : constant := 7 * 2 ** 29; |
| |
| type SRD_Regs is record |
| CTL : Registers.Registers_Index; |
| STATUS : Registers.Registers_Index; |
| end record; |
| type SRD_Per_Pipe_Regs is array (Transcoder_Index) of SRD_Regs; |
| |
| SRD : constant SRD_Per_Pipe_Regs := SRD_Per_Pipe_Regs' |
| (Trans_EDP => SRD_Regs' |
| (CTL => Registers.SRD_CTL_EDP, |
| STATUS => Registers.SRD_STATUS_EDP), |
| Trans_A => SRD_Regs' |
| (CTL => Registers.SRD_CTL_A, |
| STATUS => Registers.SRD_STATUS_A), |
| Trans_B => SRD_Regs' |
| (CTL => Registers.SRD_CTL_B, |
| STATUS => Registers.SRD_STATUS_B), |
| Trans_C => SRD_Regs' |
| (CTL => Registers.SRD_CTL_C, |
| STATUS => Registers.SRD_STATUS_C)); |
| |
| ---------------------------------------------------------------------------- |
| |
| procedure PSR_Off |
| is |
| Enabled : Boolean; |
| begin |
| pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); |
| |
| if Config.Has_Per_Pipe_SRD then |
| for P in Transcoder_Index loop |
| Registers.Is_Set_Mask (SRD (P).CTL, SRD_CTL_ENABLE, Enabled); |
| if Enabled then |
| Registers.Unset_Mask (SRD (P).CTL, SRD_CTL_ENABLE); |
| Registers.Wait_Unset_Mask (SRD (P).STATUS, SRD_STATUS_STATE_MASK); |
| |
| pragma Debug (Debug.Put_Line ("Disabled PSR.")); |
| end if; |
| end loop; |
| else |
| Registers.Is_Set_Mask (Registers.SRD_CTL, SRD_CTL_ENABLE, Enabled); |
| if Enabled then |
| Registers.Unset_Mask (Registers.SRD_CTL, SRD_CTL_ENABLE); |
| Registers.Wait_Unset_Mask (Registers.SRD_STATUS, SRD_STATUS_STATE_MASK); |
| |
| pragma Debug (Debug.Put_Line ("Disabled PSR.")); |
| end if; |
| end if; |
| end PSR_Off; |
| |
| ---------------------------------------------------------------------------- |
| |
| end HW.GFX.GMA.Transcoder; |