From 1c3b9285ceb3ff7bbb6dab8d9805ca3bda9d0ff3 Mon Sep 17 00:00:00 2001 From: Nico Huber Date: Thu, 9 Feb 2017 13:57:04 +0100 Subject: [PATCH] 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 Reviewed-on: https://review.coreboot.org/18426 Tested-by: Nico Huber Reviewed-by: Arthur Heymans --- common/haswell/Makefile.inc | 1 + common/haswell/hw-gfx-gma-ddi_phy.ads | 17 ++++ common/haswell_shared/Makefile.inc | 1 + .../hw-gfx-gma-connectors-ddi.adb | 94 ++++++++++++------- .../hw-gfx-gma-ddi_phy_stub.ads | 35 +++++++ .../haswell_shared/hw-gfx-gma-port_detect.adb | 24 +++-- common/hw-gfx-gma-config.ads.template | 6 ++ common/hw-gfx-gma-i2c.adb | 23 +++-- common/hw-gfx-gma.adb | 10 +- common/skylake/Makefile.inc | 1 + common/skylake/hw-gfx-gma-ddi_phy.ads | 17 ++++ 11 files changed, 174 insertions(+), 55 deletions(-) create mode 100644 common/haswell/hw-gfx-gma-ddi_phy.ads create mode 100644 common/haswell_shared/hw-gfx-gma-ddi_phy_stub.ads create mode 100644 common/skylake/hw-gfx-gma-ddi_phy.ads diff --git a/common/haswell/Makefile.inc b/common/haswell/Makefile.inc index 682af3320f..7ba430e6d6 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 0000000000..cd0226e92e --- /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 45b505b05b..c9b7daafa0 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 31f0b4c408..444037677f 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.PCH.VGA; 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 @@ package body HW.GFX.GMA.Connectors.DDI is 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 @@ package body HW.GFX.GMA.Connectors.DDI is 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 @@ package body HW.GFX.GMA.Connectors.DDI is 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 @@ package body HW.GFX.GMA.Connectors.DDI is 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 @@ package body HW.GFX.GMA.Connectors.DDI is 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 @@ package body HW.GFX.GMA.Connectors.DDI is 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 @@ package body HW.GFX.GMA.Connectors.DDI is (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 0000000000..b37e955d74 --- /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 b8ba37dd33..d8a1d075bf 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 @@ is 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 @@ is -- 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 5aac59afed..2bb916aded 100644 --- a/common/hw-gfx-gma-config.ads.template +++ b/common/hw-gfx-gma-config.ads.template @@ -35,6 +35,7 @@ is 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 @@ is 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 @@ is 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 5b66f07bdc..4b58dde64c 100644 --- a/common/hw-gfx-gma-i2c.adb +++ b/common/hw-gfx-gma-i2c.adb @@ -37,6 +37,9 @@ package body HW.GFX.GMA.I2C is 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 @@ package body HW.GFX.GMA.I2C is 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 77ce2aae3c..21b123da0a 100644 --- a/common/hw-gfx-gma.adb +++ b/common/hw-gfx-gma.adb @@ -381,10 +381,12 @@ is -------------------- 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 2dec2ef801..36e4e0d50c 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 0000000000..cd0226e92e --- /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;