gma broxton: Add final glue

Add new configuration flags for Broxton and hook up its DDI_Phy
implementation in the shared Haswell DDI code. Haswell and Skylake
get DDI_Phy stubs.

Tested (in Linux userspace) on ASRock J3455-ITX which exposes the
following ports:
  o VGA through an active eDP to VGA converter chip
  o HDMI 2.0 through an active DP to HDMI converter chip
  o DVI-D connected to the SoC

Change-Id: If72b228c6a4c45487261e6e7435d281ec2d97f38
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.coreboot.org/18426
Tested-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/common/haswell/Makefile.inc b/common/haswell/Makefile.inc
index 682af33..7ba430e 100644
--- a/common/haswell/Makefile.inc
+++ b/common/haswell/Makefile.inc
@@ -1,3 +1,4 @@
+gfxinit-y += hw-gfx-gma-ddi_phy.ads
 gfxinit-y += hw-gfx-gma-plls-lcpll.ads
 gfxinit-y += hw-gfx-gma-plls-wrpll.adb
 gfxinit-y += hw-gfx-gma-plls-wrpll.ads
diff --git a/common/haswell/hw-gfx-gma-ddi_phy.ads b/common/haswell/hw-gfx-gma-ddi_phy.ads
new file mode 100644
index 0000000..cd0226e
--- /dev/null
+++ b/common/haswell/hw-gfx-gma-ddi_phy.ads
@@ -0,0 +1,17 @@
+--
+-- Copyright (C) 2017 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.DDI_Phy_Stub;
+
+private package HW.GFX.GMA.DDI_Phy renames HW.GFX.GMA.DDI_Phy_Stub;
diff --git a/common/haswell_shared/Makefile.inc b/common/haswell_shared/Makefile.inc
index 45b505b..c9b7daa 100644
--- a/common/haswell_shared/Makefile.inc
+++ b/common/haswell_shared/Makefile.inc
@@ -1,6 +1,7 @@
 gfxinit-y += hw-gfx-gma-connectors-ddi.adb
 gfxinit-y += hw-gfx-gma-connectors-ddi.ads
 gfxinit-y += hw-gfx-gma-connectors.adb
+gfxinit-y += hw-gfx-gma-ddi_phy_stub.ads
 gfxinit-y += hw-gfx-gma-port_detect.adb
 gfxinit-y += hw-gfx-gma-power_and_clocks_haswell.adb
 gfxinit-y += hw-gfx-gma-power_and_clocks_haswell.ads
diff --git a/common/haswell_shared/hw-gfx-gma-connectors-ddi.adb b/common/haswell_shared/hw-gfx-gma-connectors-ddi.adb
index 31f0b4c..4440376 100644
--- a/common/haswell_shared/hw-gfx-gma-connectors-ddi.adb
+++ b/common/haswell_shared/hw-gfx-gma-connectors-ddi.adb
@@ -21,6 +21,7 @@
 with HW.GFX.GMA.DP_Info;
 with HW.GFX.GMA.DP_Aux_Ch;
 with HW.GFX.GMA.SPLL;
+with HW.GFX.GMA.DDI_Phy;
 
 with HW.Debug;
 with GNAT.Source_Info;
@@ -179,7 +180,9 @@
    is
    begin
       return
-        (if (Config.Has_Low_Voltage_Swing and Config.EDP_Low_Voltage_Swing)
+        (if Config.Has_DDI_PHYs then
+            DDI_Phy.Max_V_Swing
+         elsif (Config.Has_Low_Voltage_Swing and Config.EDP_Low_Voltage_Swing)
             and then Port = DIGI_A
          then
             DP_Info.VS_Level_3
@@ -196,11 +199,14 @@
    is
    begin
       return
-        (case Train_Set.Voltage_Swing is
-            when DP_Info.VS_Level_0 => DP_Info.Emph_Level_3,
-            when DP_Info.VS_Level_1 => DP_Info.Emph_Level_2,
-            when DP_Info.VS_Level_2 => DP_Info.Emph_Level_1,
-            when others             => DP_Info.Emph_Level_0);
+        (if Config.Has_DDI_PHYs then
+            DDI_Phy.Max_Pre_Emph (Train_Set.Voltage_Swing)
+         else
+           (case Train_Set.Voltage_Swing is
+               when DP_Info.VS_Level_0 => DP_Info.Emph_Level_3,
+               when DP_Info.VS_Level_1 => DP_Info.Emph_Level_2,
+               when DP_Info.VS_Level_2 => DP_Info.Emph_Level_1,
+               when others             => DP_Info.Emph_Level_0));
    end Max_Pre_Emph;
    pragma Warnings (GNATprove, On, "unused variable ""Port""");
 
@@ -262,39 +268,43 @@
       Was_Enabled : Boolean;
       Trans_Select : DDI_BUF_CTL_TRANS_SELECT_T;
    begin
-      case Train_Set.Voltage_Swing is
-         when DP_Info.VS_Level_0 =>
-            case Train_Set.Pre_Emph is
-               when DP_Info.Emph_Level_0  => Trans_Select := 0;
-               when DP_Info.Emph_Level_1  => Trans_Select := 1;
-               when DP_Info.Emph_Level_2  => Trans_Select := 2;
-               when DP_Info.Emph_Level_3  => Trans_Select := 3;
-            end case;
-         when DP_Info.VS_Level_1 =>
-            case Train_Set.Pre_Emph is
-               when DP_Info.Emph_Level_0  => Trans_Select := 4;
-               when DP_Info.Emph_Level_1  => Trans_Select := 5;
-               when DP_Info.Emph_Level_2  => Trans_Select := 6;
-               when others                => Trans_Select := 0;
-            end case;
-         when DP_Info.VS_Level_2 =>
-            case Train_Set.Pre_Emph is
-               when DP_Info.Emph_Level_0  => Trans_Select := 7;
-               when DP_Info.Emph_Level_1  => Trans_Select := 8;
-               when others                => Trans_Select := 0;
-            end case;
-         when DP_Info.VS_Level_3 =>
-            case Train_Set.Pre_Emph is
-               when DP_Info.Emph_Level_0  => Trans_Select := 9;
-               when others                => Trans_Select := 0;
-            end case;
-      end case;
-
       Registers.Is_Set_Mask
         (Register => DDI_Regs (Port).BUF_CTL,
          Mask     => DDI_BUF_CTL_BUFFER_ENABLE,
          Result   => Was_Enabled);
 
+      if Config.Has_DDI_PHYs then
+         Trans_Select := 0;
+      else
+         case Train_Set.Voltage_Swing is
+            when DP_Info.VS_Level_0 =>
+               case Train_Set.Pre_Emph is
+                  when DP_Info.Emph_Level_0  => Trans_Select := 0;
+                  when DP_Info.Emph_Level_1  => Trans_Select := 1;
+                  when DP_Info.Emph_Level_2  => Trans_Select := 2;
+                  when DP_Info.Emph_Level_3  => Trans_Select := 3;
+               end case;
+            when DP_Info.VS_Level_1 =>
+               case Train_Set.Pre_Emph is
+                  when DP_Info.Emph_Level_0  => Trans_Select := 4;
+                  when DP_Info.Emph_Level_1  => Trans_Select := 5;
+                  when DP_Info.Emph_Level_2  => Trans_Select := 6;
+                  when others                => Trans_Select := 0;
+               end case;
+            when DP_Info.VS_Level_2 =>
+               case Train_Set.Pre_Emph is
+                  when DP_Info.Emph_Level_0  => Trans_Select := 7;
+                  when DP_Info.Emph_Level_1  => Trans_Select := 8;
+                  when others                => Trans_Select := 0;
+               end case;
+            when DP_Info.VS_Level_3 =>
+               case Train_Set.Pre_Emph is
+                  when DP_Info.Emph_Level_0  => Trans_Select := 9;
+                  when others                => Trans_Select := 0;
+               end case;
+         end case;
+      end if;
+
       -- enable DDI buffer
       Registers.Unset_And_Set_Mask
         (Register    => DDI_Regs (Port).BUF_CTL,
@@ -309,6 +319,10 @@
       if not Was_Enabled then
          Time.U_Delay (600);  -- wait >= 518us (intel spec)
       end if;
+
+      if Config.Has_DDI_PHYs then
+         DDI_Phy.Set_DP_Signal_Levels (Port, Train_Set);
+      end if;
    end Set_Signal_Levels;
 
    ----------------------------------------------------------------------------
@@ -344,7 +358,7 @@
          Registers.Write
            (Register => DDI_Regs (Port).PORT_CLK_SEL,
             Value    => PORT_CLK_SEL_NONE);
-      else
+      elsif not Config.Has_DDI_PHYs then
          Registers.Set_Mask
            (Register => Registers.DPLL_CTRL2,
             Mask     => DPLL_CTRL2_DDIx_CLOCK_OFF (Port));
@@ -472,7 +486,7 @@
             Registers.Write
               (Register    => DDI_Regs (Port_Cfg.Port).PORT_CLK_SEL,
                Value       => PLL_Hint);
-         else
+         elsif not Config.Has_DDI_PHYs then
             Registers.Unset_And_Set_Mask
               (Register    => Registers.DPLL_CTRL2,
                Mask_Unset  => DPLL_CTRL2_DDIx_CLOCK_OFF (Port_Cfg.Port) or
@@ -489,6 +503,14 @@
               (Port        => Port_Cfg.Port,
                Link        => Port_Cfg.DP,
                Success     => Success);
+         elsif Config.Has_DDI_PHYs and then
+            Port_Cfg.Display = HDMI and then
+            Port_Cfg.Port in DDI_Phy.DDI_Phy_Port
+         then
+            DDI_Phy.Set_HDMI_Signal_Levels
+              (Port  => Port_Cfg.Port,
+               Level => DDI_Phy.HDMI_Buf_Trans_Range'Last);
+            Success := True;
          else
             Success := True;
          end if;
diff --git a/common/haswell_shared/hw-gfx-gma-ddi_phy_stub.ads b/common/haswell_shared/hw-gfx-gma-ddi_phy_stub.ads
new file mode 100644
index 0000000..b37e955
--- /dev/null
+++ b/common/haswell_shared/hw-gfx-gma-ddi_phy_stub.ads
@@ -0,0 +1,35 @@
+--
+-- Copyright (C) 2017 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.DP_Info;
+
+private package HW.GFX.GMA.DDI_Phy_Stub is
+
+   subtype DDI_Phy_Port is GPU_Port;
+
+   Max_V_Swing : constant DP_Info.DP_Voltage_Swing := DP_Info.VS_Level_0;
+
+   type Emph_Array is array (DP_Info.DP_Voltage_Swing) of DP_Info.DP_Pre_Emph;
+   Max_Pre_Emph : constant Emph_Array := (others => DP_Info.Emph_Level_0);
+
+   procedure Set_DP_Signal_Levels
+     (Port        : Digital_Port;
+      Train_Set   : DP_Info.Train_Set) is null;
+
+   type HDMI_Buf_Trans_Range is range 0 .. 9;
+   procedure Set_HDMI_Signal_Levels
+     (Port  : DDI_Phy_Port;
+      Level : HDMI_Buf_Trans_Range) is null;
+
+end HW.GFX.GMA.DDI_Phy_Stub;
diff --git a/common/haswell_shared/hw-gfx-gma-port_detect.adb b/common/haswell_shared/hw-gfx-gma-port_detect.adb
index b8ba37d..d8a1d07 100644
--- a/common/haswell_shared/hw-gfx-gma-port_detect.adb
+++ b/common/haswell_shared/hw-gfx-gma-port_detect.adb
@@ -82,10 +82,14 @@
 
       if Config.Internal_Is_EDP then
          -- DDI_A
-         Registers.Is_Set_Mask
-           (Register => Registers.DDI_BUF_CTL_A,
-            Mask     => DDI_PORT_DETECTED (DIGI_A),
-            Result   => Internal_Detected);
+         if Config.Has_Presence_Straps then
+            Registers.Is_Set_Mask
+              (Register => Registers.DDI_BUF_CTL_A,
+               Mask     => DDI_PORT_DETECTED (DIGI_A),
+               Result   => Internal_Detected);
+         else
+            Internal_Detected := True; -- XXX: Linux' i915 contains a fixme.
+         end if;
          if Internal_Detected then
             if Config.Has_HOTPLUG_CTL then
                Registers.Set_Mask
@@ -114,10 +118,14 @@
 
       -- DDI_[BCD]
       for Port in Ext_Digital_Port range DIGI_B .. Config.Last_Digital_Port loop
-         Registers.Is_Set_Mask
-           (Register => Registers.SFUSE_STRAP,
-            Mask     => DDI_PORT_DETECTED (Port),
-            Result   => DDI_Detected);
+         if Config.Has_Presence_Straps then
+            Registers.Is_Set_Mask
+              (Register => Registers.SFUSE_STRAP,
+               Mask     => DDI_PORT_DETECTED (Port),
+               Result   => DDI_Detected);
+         else
+            DDI_Detected := True;
+         end if;
          Config.Valid_Port (To_HDMI_Port (Port)) :=
             Config.Valid_Port (To_HDMI_Port (Port)) and DDI_Detected;
          Config.Valid_Port (To_DP_Port (Port)) :=
diff --git a/common/hw-gfx-gma-config.ads.template b/common/hw-gfx-gma-config.ads.template
index 5aac59a..2bb916a 100644
--- a/common/hw-gfx-gma-config.ads.template
+++ b/common/hw-gfx-gma-config.ads.template
@@ -35,6 +35,7 @@
 
    Has_Internal_Display    : constant Boolean := Internal_Display /= None;
    Internal_Is_EDP         : constant Boolean := Internal_Display = DP;
+   Has_Presence_Straps     : constant Boolean := CPU /= Broxton;
 
    ----- CPU pipe: --------
    Disable_Trickle_Feed    : constant Boolean := not
@@ -57,6 +58,7 @@
    Use_PP_VDD_Override     : constant Boolean := CPU <= Ivybridge;
 
    ----- PCH/FDI: ---------
+   Has_PCH                 : constant Boolean := CPU /= Broxton;
    Has_PCH_DAC             : constant Boolean := CPU in Ironlake .. Ivybridge or
                                                  (CPU in Broadwell .. Haswell
                                                   and CPU_Var = Normal);
@@ -92,7 +94,11 @@
 
    Need_DP_Aux_Mutex       : constant Boolean := False; -- Skylake & (PSR | GTC)
 
+   Has_DDI_PHYs            : constant Boolean := CPU = Broxton;
+
+   ----- GMBUS: -----------
    Ungate_GMBUS_Unit_Level : constant Boolean := CPU >= Skylake;
+   GMBUS_Alternative_Pins  : constant Boolean := CPU = Broxton;
 
    ----- Power: -----------
    Has_IPS                 : constant Boolean := (CPU = Haswell and
diff --git a/common/hw-gfx-gma-i2c.adb b/common/hw-gfx-gma-i2c.adb
index 5b66f07..4b58dde 100644
--- a/common/hw-gfx-gma-i2c.adb
+++ b/common/hw-gfx-gma-i2c.adb
@@ -37,6 +37,9 @@
    GMBUS0_PIN_PAIR_SELECT_DIGI_C    : constant :=   4 * 2 **  0;
    GMBUS0_PIN_PAIR_SELECT_DIGI_B    : constant :=   5 * 2 **  0;
    GMBUS0_PIN_PAIR_SELECT_DIGI_D    : constant :=   6 * 2 **  0;
+   -- Broxton uses different pins
+   GMBUS0_PIN_PAIR_SELECT_BXT_B     : constant :=   1 * 2 **  0;
+   GMBUS0_PIN_PAIR_SELECT_BXT_C     : constant :=   2 * 2 **  0;
 
    GMBUS1_SOFTWARE_CLEAR_INTERRUPT  : constant :=   1 * 2 ** 31;
    GMBUS1_SOFTWARE_READY            : constant :=   1 * 2 ** 30;
@@ -85,13 +88,19 @@
    function GMBUS0_PIN_PAIR_SELECT (Port : PCH_Port) return Word32 is
    begin
       return
-        (case Port is
-            when PCH_DAC      => GMBUS0_PIN_PAIR_SELECT_DAC,
-            when PCH_LVDS     => GMBUS0_PIN_PAIR_SELECT_LVDS,
-            when PCH_HDMI_B   => GMBUS0_PIN_PAIR_SELECT_DIGI_B,
-            when PCH_HDMI_C   => GMBUS0_PIN_PAIR_SELECT_DIGI_C,
-            when PCH_HDMI_D   => GMBUS0_PIN_PAIR_SELECT_DIGI_D,
-            when others       => GMBUS0_PIN_PAIR_SELECT_NONE);
+        (if Config.GMBUS_Alternative_Pins then
+           (case Port is
+               when PCH_HDMI_B   => GMBUS0_PIN_PAIR_SELECT_BXT_B,
+               when PCH_HDMI_C   => GMBUS0_PIN_PAIR_SELECT_BXT_C,
+               when others       => GMBUS0_PIN_PAIR_SELECT_NONE)
+         else
+           (case Port is
+               when PCH_DAC      => GMBUS0_PIN_PAIR_SELECT_DAC,
+               when PCH_LVDS     => GMBUS0_PIN_PAIR_SELECT_LVDS,
+               when PCH_HDMI_B   => GMBUS0_PIN_PAIR_SELECT_DIGI_B,
+               when PCH_HDMI_C   => GMBUS0_PIN_PAIR_SELECT_DIGI_C,
+               when PCH_HDMI_D   => GMBUS0_PIN_PAIR_SELECT_DIGI_D,
+               when others       => GMBUS0_PIN_PAIR_SELECT_NONE));
    end GMBUS0_PIN_PAIR_SELECT;
 
    ----------------------------------------------------------------------------
diff --git a/common/hw-gfx-gma.adb b/common/hw-gfx-gma.adb
index 77ce2aa..21b123d 100644
--- a/common/hw-gfx-gma.adb
+++ b/common/hw-gfx-gma.adb
@@ -381,10 +381,12 @@
       -------------------- Now restart from a clean state ---------------------
       Power_And_Clocks.Initialize;
 
-      Registers.Unset_And_Set_Mask
-        (Register    => Registers.PCH_RAWCLK_FREQ,
-         Mask_Unset  => PCH_RAWCLK_FREQ_MASK,
-         Mask_Set    => PCH_RAWCLK_FREQ (Config.Default_RawClk_Freq));
+      if Config.Has_PCH then
+         Registers.Unset_And_Set_Mask
+           (Register    => Registers.PCH_RAWCLK_FREQ,
+            Mask_Unset  => PCH_RAWCLK_FREQ_MASK,
+            Mask_Set    => PCH_RAWCLK_FREQ (Config.Default_RawClk_Freq));
+      end if;
 
       Initialized := True;
 
diff --git a/common/skylake/Makefile.inc b/common/skylake/Makefile.inc
index 2dec2ef..36e4e0d 100644
--- a/common/skylake/Makefile.inc
+++ b/common/skylake/Makefile.inc
@@ -1,3 +1,4 @@
+gfxinit-y += hw-gfx-gma-ddi_phy.ads
 gfxinit-y += hw-gfx-gma-plls-dpll.adb
 gfxinit-y += hw-gfx-gma-plls-dpll.ads
 gfxinit-y += hw-gfx-gma-plls-dpll_0.adb
diff --git a/common/skylake/hw-gfx-gma-ddi_phy.ads b/common/skylake/hw-gfx-gma-ddi_phy.ads
new file mode 100644
index 0000000..cd0226e
--- /dev/null
+++ b/common/skylake/hw-gfx-gma-ddi_phy.ads
@@ -0,0 +1,17 @@
+--
+-- Copyright (C) 2017 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.DDI_Phy_Stub;
+
+private package HW.GFX.GMA.DDI_Phy renames HW.GFX.GMA.DDI_Phy_Stub;