gma pipe_setup: Untangle pipe and transcoder config

Intel's manuals became much more clear with the years about what be-
longs to the transcoder and what to the pipe setup.

Although the transcoder is generally tied to a specific pipe, we
keep the naming of transcoder A, B, C which are mapped to the Primary,
Secondary, and Tertiary pipe respectively (with the exception of the
Haswell+ EDP transcoder which can be attached to any pipe).

Change-Id: I722786d318268c51ae2eaba9c108312f139165d8
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.coreboot.org/17763
Tested-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
diff --git a/common/hw-gfx-gma-pipe_setup.adb b/common/hw-gfx-gma-pipe_setup.adb
index 6293f20..40b31c8 100644
--- a/common/hw-gfx-gma-pipe_setup.adb
+++ b/common/hw-gfx-gma-pipe_setup.adb
@@ -106,6 +106,29 @@
    PIPECONF_ENABLE_DITHER   : constant := 1 * 2 **  4;
    PIPECONF_DITHER_TEMPORAL : constant := 1 * 2 **  2;
 
+   function PIPECONF_BPC (Bits_Per_Color : BPC_Type) return Word32
+   with
+      Pre => True
+   is
+   begin
+      return
+        (case Bits_Per_Color is
+            when      6 => 2 * 2 ** 5,
+            when     10 => 1 * 2 ** 5,
+            when     12 => 3 * 2 ** 5,
+            when others => 0 * 2 ** 5);
+   end PIPECONF_BPC;
+
+   function PIPECONF_Misc (BPC : BPC_Type; Dither : Boolean) return Word32
+   with
+      Pre => True
+   is
+   begin
+      return
+        (if Config.Has_Pipeconf_BPC then PIPECONF_BPC (BPC) else 0) or
+        (if Dither then PIPECONF_ENABLE_DITHER else 0);
+   end PIPECONF_Misc;
+
    PF_CTRL_ENABLE                         : constant := 1 * 2 ** 31;
    PF_CTRL_PIPE_SELECT_MASK               : constant := 3 * 2 ** 29;
    PF_CTRL_FILTER_MED                     : constant := 1 * 2 ** 23;
@@ -233,24 +256,6 @@
 
    ---------------------------------------------------------------------------
 
-   function PIPECONF_BPC_MAP (Bits_Per_Color : HW.GFX.BPC_Type) return Word32
-   is
-      Result : Word32;
-   begin
-      if    Bits_Per_Color = 6 then
-         Result := 2 * 2 ** 5;
-      elsif Bits_Per_Color = 10 then
-         Result := 1 * 2 ** 5;
-      elsif Bits_Per_Color = 12 then
-         Result := 3 * 2 ** 5;
-      else
-         Result := 0;
-      end if;
-      return Result;
-   end PIPECONF_BPC_MAP;
-
-   ---------------------------------------------------------------------------
-
    function PLANE_WM_LINES (Lines : Natural) return Word32 is
    begin
       return Shift_Left (Word32 (Lines), PLANE_WM_LINES_SHIFT)
@@ -412,10 +417,10 @@
    end Setup_Hires_Plane;
 
    procedure Setup_Display
-     (Controller  : in     Controller_Type;
-      Head        : in     Head_Type;
-      Mode        : in     HW.GFX.Mode_Type;
-      Framebuffer : in     HW.GFX.Framebuffer_Type)
+     (Controller  : Controller_Type;
+      Framebuffer : Framebuffer_Type;
+      Dither_BPC  : BPC_Type;
+      Dither      : Boolean)
    with
       Global => (In_Out => (Registers.Register_State, Port_IO.State)),
       Depends =>
@@ -423,9 +428,9 @@
             =>+
               (Registers.Register_State,
                Controller,
-               Head,
-               Mode,
-               Framebuffer),
+               Framebuffer,
+               Dither_BPC,
+               Dither),
          Port_IO.State
             =>+
                (Framebuffer))
@@ -472,14 +477,43 @@
          Value    => Encode
            (Pos16 (Framebuffer.Height), Pos16 (Framebuffer.Width)));
 
-      Registers.Write (Head.HTOTAL,  Encode (Mode.H_Visible,    Mode.H_Total));
-      Registers.Write (Head.HBLANK,  Encode (Mode.H_Visible,    Mode.H_Total));
-      Registers.Write (Head.HSYNC,   Encode (Mode.H_Sync_Begin, Mode.H_Sync_End));
-      Registers.Write (Head.VTOTAL,  Encode (Mode.V_Visible,    Mode.V_Total));
-      Registers.Write (Head.VBLANK,  Encode (Mode.V_Visible,    Mode.V_Total));
-      Registers.Write (Head.VSYNC,   Encode (Mode.V_Sync_Begin, Mode.V_Sync_End));
+      if Config.Has_Pipeconf_Misc then
+         Registers.Write
+           (Register => Controller.PIPEMISC,
+            Value    => PIPECONF_Misc (Dither_BPC, Dither));
+      end if;
    end Setup_Display;
 
+   procedure Setup_Transcoder
+     (Head     : Head_Type;
+      Port_Cfg : Port_Config)
+   is
+      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
+         Head.TRANS_CLK_SEL /= Registers.Invalid_Register
+      then
+         Registers.Write
+           (Register => Head.TRANS_CLK_SEL,
+            Value    => TRANS_CLK_SEL_PORT (Port_Cfg.Port));
+      end if;
+
+      if Port_Cfg.Is_FDI then
+         Setup_Link (Head, Port_Cfg.FDI, Port_Cfg.Mode);
+      elsif Port_Cfg.Display = DP then
+         Setup_Link (Head, Port_Cfg.DP, Port_Cfg.Mode);
+      end if;
+
+      Registers.Write (Head.HTOTAL,  Encode (M.H_Visible,    M.H_Total));
+      Registers.Write (Head.HBLANK,  Encode (M.H_Visible,    M.H_Total));
+      Registers.Write (Head.HSYNC,   Encode (M.H_Sync_Begin, M.H_Sync_End));
+      Registers.Write (Head.VTOTAL,  Encode (M.V_Visible,    M.V_Total));
+      Registers.Write (Head.VBLANK,  Encode (M.V_Visible,    M.V_Total));
+      Registers.Write (Head.VSYNC,   Encode (M.V_Sync_Begin, M.V_Sync_End));
+   end Setup_Transcoder;
+
    ----------------------------------------------------------------------------
 
    procedure Scale_Keep_Aspect
@@ -624,13 +658,12 @@
 
    ----------------------------------------------------------------------------
 
-   procedure Setup_Head
-     (Controller  : Controller_Type;
+   procedure Transcoder_On
+     (Pipe        : Pipe_Index;
       Head        : Head_Type;
       Port_Cfg    : Port_Config;
-      Framebuffer : Framebuffer_Type)
+      Dither      : Boolean)
    is
-      PIPECONF_Options : Word32 := 0;
    begin
       if Config.Has_Pipe_DDI_Func then
          Registers.Write
@@ -641,34 +674,17 @@
                         PIPE_DDI_FUNC_CTL_BPC (Port_Cfg.Mode.BPC) or
                         PIPE_DDI_FUNC_CTL_VSYNC (Port_Cfg.Mode.V_Sync_Active_High) or
                         PIPE_DDI_FUNC_CTL_HSYNC (Port_Cfg.Mode.H_Sync_Active_High) or
-                        PIPE_DDI_FUNC_CTL_EDP_SELECT (Controller.Pipe) or
+                        PIPE_DDI_FUNC_CTL_EDP_SELECT (Pipe) or
                         PIPE_DDI_FUNC_CTL_PORT_WIDTH (Port_Cfg.DP.Lane_Count));
       end if;
 
-      if Config.Has_Pipeconf_BPC then
-         PIPECONF_Options := PIPECONF_BPC_MAP (Port_Cfg.Mode.BPC);
-      end if;
-
-      -- Enable dithering if framebuffer BPC differs from connector BPC,
-      -- as smooth gradients look really bad without
-      if Framebuffer.BPC /= Port_Cfg.Mode.BPC then
-         PIPECONF_Options := PIPECONF_Options or PIPECONF_ENABLE_DITHER;
-      end if;
-
-      if not Config.Has_Pipeconf_Misc then
-         Registers.Write
-           (Register => Head.PIPECONF,
-            Value    => PIPECONF_ENABLE or PIPECONF_Options);
-      else
-         Registers.Write
-           (Register => Controller.PIPEMISC,
-            Value    => PIPECONF_Options);
-         Registers.Write
-           (Register => Head.PIPECONF,
-            Value    => PIPECONF_ENABLE);
-      end if;
+      Registers.Write
+        (Register => Head.PIPECONF,
+         Value    => PIPECONF_ENABLE or
+                     (if not Config.Has_Pipeconf_Misc then
+                        PIPECONF_Misc (Port_Cfg.Mode.BPC, Dither) else 0));
       Registers.Posting_Read (Head.PIPECONF);
-   end Setup_Head;
+   end Transcoder_On;
 
    ----------------------------------------------------------------------------
 
@@ -677,28 +693,21 @@
       Port_Cfg    : Port_Config;
       Framebuffer : Framebuffer_Type)
    is
+      -- Enable dithering if framebuffer BPC differs from port BPC,
+      -- as smooth gradients look really bad without.
+      Dither : constant Boolean := Framebuffer.BPC /= Port_Cfg.Mode.BPC;
       Head : constant Pipe_Head := Get_Pipe_Head (Pipe, Port_Cfg.Port);
    begin
       pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
 
-      if Config.Has_Trans_Clk_Sel then
-         Registers.Write
-           (Register => Controllers (Pipe).TRANS_CLK_SEL,
-            Value    => TRANS_CLK_SEL_PORT (Port_Cfg.Port));
-      end if;
-
-      if Port_Cfg.Is_FDI then
-         Setup_Link (Heads (Head), Port_Cfg.FDI, Port_Cfg.Mode);
-      elsif Port_Cfg.Display = DP then
-         Setup_Link (Heads (Head), Port_Cfg.DP, Port_Cfg.Mode);
-      end if;
+      Setup_Transcoder (Heads (Head), Port_Cfg);
 
       Setup_Display
-        (Controllers (Pipe), Heads (Head), Port_Cfg.Mode, Framebuffer);
+        (Controllers (Pipe), Framebuffer, Port_Cfg.Mode.BPC, Dither);
 
       Setup_Scaling (Controllers (Pipe), Port_Cfg.Mode, Framebuffer);
 
-      Setup_Head (Controllers (Pipe), Heads (Head), Port_Cfg, Framebuffer);
+      Transcoder_On (Pipe, Heads (Head), Port_Cfg, Dither);
    end On;
 
    ----------------------------------------------------------------------------
@@ -740,6 +749,25 @@
       end if;
    end Head_Off;
 
+   procedure Transcoder_Off (Pipe : Pipe_Index)
+   is
+      DDI_Func_Ctl : Word32;
+   begin
+      if Config.Has_EDP_Pipe then
+         Registers.Read (Registers.PIPE_EDP_DDI_FUNC_CTL, DDI_Func_Ctl);
+         DDI_Func_Ctl := DDI_Func_Ctl and PIPE_DDI_FUNC_CTL_EDP_SELECT_MASK;
+
+         if (Pipe = Primary and
+             DDI_Func_Ctl = PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON) or
+            DDI_Func_Ctl = PIPE_DDI_FUNC_CTL_EDP_SELECT_ONOFF (Pipe)
+         then
+            Head_Off (Heads (Head_EDP));
+         end if;
+      end if;
+
+      Head_Off (Heads (Default_Pipe_Head (Pipe)));
+   end Transcoder_Off;
+
    procedure Panel_Fitter_Off (Controller : Controller_Type) is
    begin
       -- Writes to WIN_SZ arm the PS/PF registers.
@@ -758,22 +786,25 @@
       end if;
    end Panel_Fitter_Off;
 
-   procedure Trans_Clk_Off (Controller : Controller_Type) is
+   procedure Trans_Clk_Off (Head : Head_Type) is
    begin
-      if Config.Has_Trans_Clk_Sel then
-         Registers.Write (Controller.TRANS_CLK_SEL, TRANS_CLK_SEL_PORT_NONE);
+      if Config.Has_Trans_Clk_Sel and then
+         Head.TRANS_CLK_SEL /= Registers.Invalid_Register
+      then
+         Registers.Write (Head.TRANS_CLK_SEL, TRANS_CLK_SEL_PORT_NONE);
       end if;
    end Trans_Clk_Off;
 
    procedure Off (Pipe : Pipe_Index; Port_Cfg : Port_Config)
    is
+      Head : constant Pipe_Head := Get_Pipe_Head (Pipe, Port_Cfg.Port);
    begin
       pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
 
       Planes_Off (Controllers (Pipe));
-      Head_Off (Heads (Get_Pipe_Head (Pipe, Port_Cfg.Port)));
+      Transcoder_Off (Pipe);
       Panel_Fitter_Off (Controllers (Pipe));
-      Trans_Clk_Off (Controllers (Pipe));
+      Trans_Clk_Off (Heads (Head));
    end Off;
 
    procedure Legacy_VGA_Off
@@ -790,50 +821,17 @@
 
    procedure All_Off
    is
-      EDP_Enabled, EDP_Piped : Boolean;
-
-      procedure EDP_Piped_To (Pipe : Pipe_Index; Piped_To : out Boolean)
-      is
-         Pipe_DDI_Func_Ctl : Word32;
-      begin
-         Registers.Read (Registers.PIPE_EDP_DDI_FUNC_CTL, Pipe_DDI_Func_Ctl);
-         Pipe_DDI_Func_Ctl :=
-            Pipe_DDI_Func_Ctl and PIPE_DDI_FUNC_CTL_EDP_SELECT_MASK;
-
-         Piped_To :=
-            (Pipe = Primary and
-             Pipe_DDI_Func_Ctl = PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON) or
-            Pipe_DDI_Func_Ctl = PIPE_DDI_FUNC_CTL_EDP_SELECT_ONOFF (Pipe);
-      end EDP_Piped_To;
    begin
       pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
 
       Legacy_VGA_Off;
 
-      if Config.Has_EDP_Pipe then
-         Registers.Is_Set_Mask
-           (Registers.PIPE_EDP_CONF, PIPECONF_ENABLE, EDP_Enabled);
-      else
-         EDP_Enabled := False;
-      end if;
-
       for Pipe in Pipe_Index loop
          Planes_Off (Controllers (Pipe));
-         if EDP_Enabled then
-            EDP_Piped_To (Pipe, EDP_Piped);
-            if EDP_Piped then
-               Head_Off (Heads (Head_EDP));
-               EDP_Enabled := False;
-            end if;
-         end if;
-         Head_Off (Heads (Default_Pipe_Head (Pipe)));
+         Transcoder_Off (Pipe);
          Panel_Fitter_Off (Controllers (Pipe));
-         Trans_Clk_Off (Controllers (Pipe));
+         Trans_Clk_Off (Heads (Default_Pipe_Head (Pipe)));
       end loop;
-
-      if EDP_Enabled then
-         Head_Off (Heads (Head_EDP));
-      end if;
    end All_Off;
 
    ----------------------------------------------------------------------------
diff --git a/common/hw-gfx-gma-pipe_setup.ads b/common/hw-gfx-gma-pipe_setup.ads
index a57ca18..250ab5a 100644
--- a/common/hw-gfx-gma-pipe_setup.ads
+++ b/common/hw-gfx-gma-pipe_setup.ads
@@ -59,7 +59,6 @@
          DSPSURF           : Registers.Registers_Index;
          DSPTILEOFF        : Registers.Registers_Index;
          SPCNTR            : Registers.Registers_Index;
-         TRANS_CLK_SEL     : Registers.Registers_Index;
          -- Skylake registers (partially aliased)
          PLANE_CTL         : Registers.Registers_Index;
          PLANE_OFFSET      : Registers.Registers_Index;
@@ -99,6 +98,7 @@
          PIPE_LINK_N1      : Registers.Registers_Index;
          PIPE_DDI_FUNC_CTL : Registers.Registers_Index;
          PIPE_MSA_MISC     : Registers.Registers_Index;
+         TRANS_CLK_SEL     : Registers.Registers_Invalid_Index;
       end record;
 
    type Head_Array is array (Pipe_Head) of Head_Type;
@@ -119,7 +119,6 @@
          DSPSURF           => Registers.DSPASURF,
          DSPTILEOFF        => Registers.DSPATILEOFF,
          SPCNTR            => Registers.SPACNTR,
-         TRANS_CLK_SEL     => Registers.TRANSA_CLK_SEL,
          PLANE_CTL         => Registers.DSPACNTR,
          PLANE_OFFSET      => Registers.DSPATILEOFF,
          PLANE_POS         => Registers.PLANE_POS_1_A,
@@ -155,7 +154,6 @@
          DSPSURF           => Registers.DSPBSURF,
          DSPTILEOFF        => Registers.DSPBTILEOFF,
          SPCNTR            => Registers.SPBCNTR,
-         TRANS_CLK_SEL     => Registers.TRANSB_CLK_SEL,
          PLANE_CTL         => Registers.DSPBCNTR,
          PLANE_OFFSET      => Registers.DSPBTILEOFF,
          PLANE_POS         => Registers.PLANE_POS_1_B,
@@ -191,7 +189,6 @@
          DSPSURF           => Registers.DSPCSURF,
          DSPTILEOFF        => Registers.DSPCTILEOFF,
          SPCNTR            => Registers.SPCCNTR,
-         TRANS_CLK_SEL     => Registers.TRANSC_CLK_SEL,
          PLANE_CTL         => Registers.DSPCCNTR,
          PLANE_OFFSET      => Registers.DSPCTILEOFF,
          PLANE_POS         => Registers.PLANE_POS_1_C,
@@ -230,7 +227,8 @@
          PIPE_LINK_M1      => Registers.PIPE_EDP_LINK_M1,
          PIPE_LINK_N1      => Registers.PIPE_EDP_LINK_N1,
          PIPE_DDI_FUNC_CTL => Registers.PIPE_EDP_DDI_FUNC_CTL,
-         PIPE_MSA_MISC     => Registers.PIPE_EDP_MSA_MISC),
+         PIPE_MSA_MISC     => Registers.PIPE_EDP_MSA_MISC,
+         TRANS_CLK_SEL     => Registers.Invalid_Register),
       Head_A => Head_Type'
         (Head              => Head_A,
          HTOTAL            => Registers.HTOTAL_A,
@@ -245,7 +243,8 @@
          PIPE_LINK_M1      => Registers.PIPEA_LINK_M1,
          PIPE_LINK_N1      => Registers.PIPEA_LINK_N1,
          PIPE_DDI_FUNC_CTL => Registers.PIPEA_DDI_FUNC_CTL,
-         PIPE_MSA_MISC     => Registers.PIPEA_MSA_MISC),
+         PIPE_MSA_MISC     => Registers.PIPEA_MSA_MISC,
+         TRANS_CLK_SEL     => Registers.TRANSA_CLK_SEL),
       Head_B => Head_Type'
         (Head              => Head_B,
          HTOTAL            => Registers.HTOTAL_B,
@@ -260,7 +259,8 @@
          PIPE_LINK_M1      => Registers.PIPEB_LINK_M1,
          PIPE_LINK_N1      => Registers.PIPEB_LINK_N1,
          PIPE_DDI_FUNC_CTL => Registers.PIPEB_DDI_FUNC_CTL,
-         PIPE_MSA_MISC     => Registers.PIPEB_MSA_MISC),
+         PIPE_MSA_MISC     => Registers.PIPEB_MSA_MISC,
+         TRANS_CLK_SEL     => Registers.TRANSB_CLK_SEL),
       Head_C => Head_Type'
         (Head              => Head_C,
          HTOTAL            => Registers.HTOTAL_C,
@@ -275,6 +275,7 @@
          PIPE_LINK_M1      => Registers.PIPEC_LINK_M1,
          PIPE_LINK_N1      => Registers.PIPEC_LINK_N1,
          PIPE_DDI_FUNC_CTL => Registers.PIPEC_DDI_FUNC_CTL,
-         PIPE_MSA_MISC     => Registers.PIPEC_MSA_MISC));
+         PIPE_MSA_MISC     => Registers.PIPEC_MSA_MISC,
+         TRANS_CLK_SEL     => Registers.TRANSC_CLK_SEL));
 
 end HW.GFX.GMA.Pipe_Setup;