Initial upstream commit
The history contained unlicensed code so everything got squashed, sorry.
Change-Id: I9f5775208f9df6fb29074bf3bc498f68cb17b3a0
Signed-off-by: Nico Huber <nico.huber@secunet.com>
diff --git a/common/hw-gfx-gma-pch-transcoder.adb b/common/hw-gfx-gma-pch-transcoder.adb
new file mode 100644
index 0000000..bab3f31
--- /dev/null
+++ b/common/hw-gfx-gma-pch-transcoder.adb
@@ -0,0 +1,280 @@
+--
+-- Copyright (C) 2015-2016 secunet Security Networks AG
+-- Copyright (C) 2016 Nico Huber <nico.h@gmx.de>
+--
+-- 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; version 2 of the License.
+--
+-- 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.DP_Info;
+with HW.GFX.GMA.Registers;
+
+with HW.Debug;
+with GNAT.Source_Info;
+
+package body HW.GFX.GMA.PCH.Transcoder is
+
+ type DPLL_SEL_Array is array (FDI_Port_Type) of Word32;
+ DPLL_SEL_TRANSCODER_x_DPLL_ENABLE : constant DPLL_SEL_Array :=
+ (FDI_A => 1 * 2 ** 3,
+ FDI_B => 1 * 2 ** 7,
+ FDI_C => 1 * 2 ** 11);
+ DPLL_SEL_TRANSCODER_x_DPLL_SEL_MASK : constant DPLL_SEL_Array :=
+ (FDI_A => 1 * 2 ** 0,
+ FDI_B => 1 * 2 ** 4,
+ FDI_C => 1 * 2 ** 8);
+ function DPLL_SEL_TRANSCODER_x_DPLL_SEL
+ (Port : FDI_Port_Type;
+ PLL : Word32)
+ return Word32
+ is
+ begin
+ return Shift_Left (PLL,
+ (case Port is
+ when FDI_A => 0,
+ when FDI_B => 4,
+ when FDI_C => 8));
+ end DPLL_SEL_TRANSCODER_x_DPLL_SEL;
+
+ TRANS_CONF_TRANSCODER_ENABLE : constant := 1 * 2 ** 31;
+ TRANS_CONF_TRANSCODER_STATE : constant := 1 * 2 ** 30;
+
+ TRANS_CHICKEN2_TIMING_OVERRIDE : constant := 1 * 2 ** 31;
+
+ TRANS_DP_CTL_OUTPUT_ENABLE : constant := 1 * 2 ** 31;
+ TRANS_DP_CTL_PORT_SELECT_MASK : constant := 3 * 2 ** 29;
+ TRANS_DP_CTL_PORT_SELECT_NONE : constant := 3 * 2 ** 29;
+ TRANS_DP_CTL_ENHANCED_FRAMING : constant := 1 * 2 ** 18;
+ TRANS_DP_CTL_VSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 4;
+ TRANS_DP_CTL_HSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 3;
+
+ type TRANS_DP_CTL_PORT_SELECT_Array is array (PCH_Port) of Word32;
+ TRANS_DP_CTL_PORT_SELECT : constant TRANS_DP_CTL_PORT_SELECT_Array :=
+ (PCH_DP_B => 0 * 2 ** 29,
+ PCH_DP_C => 1 * 2 ** 29,
+ PCH_DP_D => 2 * 2 ** 29,
+ others => 0);
+
+ function TRANS_DP_CTL_BPC (BPC : BPC_Type) return Word32
+ is
+ begin
+ return
+ (case BPC is
+ when 6 => 2 * 2 ** 9,
+ when 10 => 1 * 2 ** 9,
+ when 12 => 3 * 2 ** 9,
+ when others => 0 * 2 ** 9);
+ end TRANS_DP_CTL_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;
+
+ ----------------------------------------------------------------------------
+
+ type Transcoder_Registers is record
+ HTOTAL : Registers.Registers_Index;
+ HBLANK : Registers.Registers_Index;
+ HSYNC : Registers.Registers_Index;
+ VTOTAL : Registers.Registers_Index;
+ VBLANK : Registers.Registers_Index;
+ VSYNC : Registers.Registers_Index;
+ CONF : Registers.Registers_Index;
+ DP_CTL : Registers.Registers_Index;
+ DATA_M : Registers.Registers_Index;
+ DATA_N : Registers.Registers_Index;
+ LINK_M : Registers.Registers_Index;
+ LINK_N : Registers.Registers_Index;
+ CHICKEN2 : Registers.Registers_Index;
+ end record;
+
+ type Transcoder_Registers_Array is
+ array (FDI_Port_Type) of Transcoder_Registers;
+
+ TRANS : constant Transcoder_Registers_Array := Transcoder_Registers_Array'
+ (FDI_A =>
+ (HTOTAL => Registers.TRANS_HTOTAL_A,
+ HBLANK => Registers.TRANS_HBLANK_A,
+ HSYNC => Registers.TRANS_HSYNC_A,
+ VTOTAL => Registers.TRANS_VTOTAL_A,
+ VBLANK => Registers.TRANS_VBLANK_A,
+ VSYNC => Registers.TRANS_VSYNC_A,
+ CONF => Registers.TRANSACONF,
+ DP_CTL => Registers.TRANS_DP_CTL_A,
+ DATA_M => Registers.TRANSA_DATA_M1,
+ DATA_N => Registers.TRANSA_DATA_N1,
+ LINK_M => Registers.TRANSA_DP_LINK_M1,
+ LINK_N => Registers.TRANSA_DP_LINK_N1,
+ CHICKEN2 => Registers.TRANSA_CHICKEN2),
+ FDI_B =>
+ (HTOTAL => Registers.TRANS_HTOTAL_B,
+ HBLANK => Registers.TRANS_HBLANK_B,
+ HSYNC => Registers.TRANS_HSYNC_B,
+ VTOTAL => Registers.TRANS_VTOTAL_B,
+ VBLANK => Registers.TRANS_VBLANK_B,
+ VSYNC => Registers.TRANS_VSYNC_B,
+ CONF => Registers.TRANSBCONF,
+ DP_CTL => Registers.TRANS_DP_CTL_B,
+ DATA_M => Registers.TRANSB_DATA_M1,
+ DATA_N => Registers.TRANSB_DATA_N1,
+ LINK_M => Registers.TRANSB_DP_LINK_M1,
+ LINK_N => Registers.TRANSB_DP_LINK_N1,
+ CHICKEN2 => Registers.TRANSB_CHICKEN2),
+ FDI_C =>
+ (HTOTAL => Registers.TRANS_HTOTAL_C,
+ HBLANK => Registers.TRANS_HBLANK_C,
+ HSYNC => Registers.TRANS_HSYNC_C,
+ VTOTAL => Registers.TRANS_VTOTAL_C,
+ VBLANK => Registers.TRANS_VBLANK_C,
+ VSYNC => Registers.TRANS_VSYNC_C,
+ CONF => Registers.TRANSCCONF,
+ DP_CTL => Registers.TRANS_DP_CTL_C,
+ DATA_M => Registers.TRANSC_DATA_M1,
+ DATA_N => Registers.TRANSC_DATA_N1,
+ LINK_M => Registers.TRANSC_DP_LINK_M1,
+ LINK_N => Registers.TRANSC_DP_LINK_N1,
+ CHICKEN2 => Registers.TRANSC_CHICKEN2));
+
+ ----------------------------------------------------------------------------
+
+ procedure On
+ (Port_Cfg : Port_Config;
+ Port : FDI_Port_Type;
+ PLL : Word32)
+ is
+ Mode : constant Mode_Type := Port_Cfg.Mode;
+
+ function Encode (LSW, MSW : Pos16) return Word32 is
+ begin
+ return (Word32 (LSW) - 1) or ((Word32 (MSW) - 1) * 2 ** 16);
+ end Encode;
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ if Config.Has_DPLL_SEL then
+ Registers.Unset_And_Set_Mask
+ (Register => Registers.PCH_DPLL_SEL,
+ Mask_Unset => DPLL_SEL_TRANSCODER_x_DPLL_SEL_MASK (Port),
+ Mask_Set => DPLL_SEL_TRANSCODER_x_DPLL_ENABLE (Port) or
+ DPLL_SEL_TRANSCODER_x_DPLL_SEL (Port, PLL));
+ end if;
+
+ Registers.Write
+ (Register => TRANS (Port).HTOTAL,
+ Value => Encode (Mode.H_Visible, Mode.H_Total));
+ Registers.Write
+ (Register => TRANS (Port).HBLANK,
+ Value => Encode (Mode.H_Visible, Mode.H_Total));
+ Registers.Write
+ (Register => TRANS (Port).HSYNC,
+ Value => Encode (Mode.H_Sync_Begin, Mode.H_Sync_End));
+ Registers.Write
+ (Register => TRANS (Port).VTOTAL,
+ Value => Encode (Mode.V_Visible, Mode.V_Total));
+ Registers.Write
+ (Register => TRANS (Port).VBLANK,
+ Value => Encode (Mode.V_Visible, Mode.V_Total));
+ Registers.Write
+ (Register => TRANS (Port).VSYNC,
+ Value => Encode (Mode.V_Sync_Begin, Mode.V_Sync_End));
+
+ if Port_Cfg.Display = DP then
+ declare
+ Data_M, Link_M : DP_Info.M_Type;
+ Data_N, Link_N : DP_Info.N_Type;
+ begin
+ DP_Info.Calculate_M_N
+ (Link => Port_Cfg.DP,
+ Mode => Port_Cfg.Mode,
+ Data_M => Data_M,
+ Data_N => Data_N,
+ Link_M => Link_M,
+ Link_N => Link_N);
+ Registers.Write
+ (Register => TRANS (Port).DATA_M,
+ Value => TRANS_DATA_M_TU (64) or
+ Word32 (Data_M));
+ Registers.Write
+ (Register => TRANS (Port).DATA_N,
+ Value => Word32 (Data_N));
+ Registers.Write
+ (Register => TRANS (Port).LINK_M,
+ Value => Word32 (Link_M));
+ Registers.Write
+ (Register => TRANS (Port).LINK_N,
+ Value => Word32 (Link_N));
+ end;
+
+ if Config.Has_Trans_DP_Ctl then
+ declare
+ Polarity : constant Word32 :=
+ (if Port_Cfg.Mode.H_Sync_Active_High then
+ TRANS_DP_CTL_HSYNC_ACTIVE_HIGH else 0) or
+ (if Port_Cfg.Mode.V_Sync_Active_High then
+ TRANS_DP_CTL_VSYNC_ACTIVE_HIGH else 0);
+ Enhanced_Framing : constant Word32 :=
+ (if Port_Cfg.DP.Enhanced_Framing then
+ TRANS_DP_CTL_ENHANCED_FRAMING else 0);
+ begin
+ Registers.Write
+ (Register => TRANS (Port).DP_CTL,
+ Value => TRANS_DP_CTL_OUTPUT_ENABLE or
+ TRANS_DP_CTL_PORT_SELECT (Port_Cfg.PCH_Port) or
+ Enhanced_Framing or
+ TRANS_DP_CTL_BPC (Port_Cfg.Mode.BPC) or
+ Polarity);
+ end;
+ end if;
+ end if;
+
+ if Config.Has_Trans_Timing_Ovrrde then
+ Registers.Set_Mask
+ (Register => TRANS (Port).CHICKEN2,
+ Mask => TRANS_CHICKEN2_TIMING_OVERRIDE);
+ end if;
+
+ Registers.Write
+ (Register => TRANS (Port).CONF,
+ Value => TRANS_CONF_TRANSCODER_ENABLE);
+ end On;
+
+ procedure Off (Port : FDI_Port_Type) is
+ begin
+ pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+ Registers.Unset_Mask
+ (Register => TRANS (Port).CONF,
+ Mask => TRANS_CONF_TRANSCODER_ENABLE);
+ Registers.Wait_Unset_Mask
+ (Register => TRANS (Port).CONF,
+ Mask => TRANS_CONF_TRANSCODER_STATE,
+ TOut_MS => 50);
+
+ if Config.Has_Trans_Timing_Ovrrde then
+ Registers.Unset_Mask
+ (Register => TRANS (Port).CHICKEN2,
+ Mask => TRANS_CHICKEN2_TIMING_OVERRIDE);
+ end if;
+
+ if Config.Has_Trans_DP_Ctl then
+ Registers.Write
+ (Register => TRANS (Port).DP_CTL,
+ Value => TRANS_DP_CTL_PORT_SELECT_NONE);
+ end if;
+
+ if Config.Has_DPLL_SEL then
+ Registers.Unset_Mask
+ (Register => Registers.PCH_DPLL_SEL,
+ Mask => DPLL_SEL_TRANSCODER_x_DPLL_ENABLE (Port));
+ end if;
+ end Off;
+
+end HW.GFX.GMA.PCH.Transcoder;