Nico Huber has submitted this change. ( https://review.coreboot.org/c/libgfxinit/+/41343 )
Change subject: haswell: Make VGA on FDI work ......................................................................
haswell: Make VGA on FDI work
Attempting to light up a 1920x1080 monitor through VGA with libgfxinit on Haswell would either hang the system or show garbage on the monitor. This was due to two different problems around FDI initialization code.
The system would only hang if libgfxinit was the first program to light up a monitor on VGA. This is because no one had performed the required FDI mPHY initialization that is described on the Haswell graphics PRMs. Add it to libgfxinit alongside some code to disable bending CLKOUT_DP.
Even with the FDI mPHY initialization in place, the garbage would still be present on the VGA monitor. Digital interfaces were not affected. By carefully dumping and comparing the display registers of a good and a bad case, it was determinted that the fault was due to a mismatched link width for FDI. The FDI link between the iGPU and the Lynxpoint PCH can operate in either x1 or x2 width, depending on the bandwidth needs of the monitor on the PCH's VGA port. To drive a 1920x1080 VGA monitor, it is necessary to use both FDI lanes. Moreover, both ends of the link need to be configured to use the same link width. However, the wrong link width was assumed when configuring the display pipe, because `DP.Lane_Count` was used unconditionally instead of `FDI.Lane_Count`.
After fixing both issues, gfx_test is able to light up a 1920x1080 VGA monitor on the Asrock B85M Pro4 successfully, even after a S3 resume.
Change-Id: Ieabe3b7f947be2ef488ddb57bfeae85fa055d360 Signed-off-by: Angel Pons th3fanbus@gmail.com Reviewed-on: https://review.coreboot.org/c/libgfxinit/+/41343 Tested-by: Nico Huber nico.h@gmx.de Reviewed-by: Nico Huber nico.h@gmx.de --- M common/haswell/Makefile.inc A common/haswell/hw-gfx-gma-pch-lynxpoint.adb A common/haswell/hw-gfx-gma-pch-lynxpoint.ads M common/haswell/hw-gfx-gma-power_and_clocks_haswell.adb M common/haswell/hw-gfx-gma-power_and_clocks_haswell.ads M common/hw-gfx-gma-pch-sideband.adb M common/hw-gfx-gma-pch-sideband.ads M common/hw-gfx-gma-transcoder.adb 8 files changed, 263 insertions(+), 6 deletions(-)
Approvals: Nico Huber: Verified; Looks good to me, approved
diff --git a/common/haswell/Makefile.inc b/common/haswell/Makefile.inc index ef75dc4..32657a8 100644 --- a/common/haswell/Makefile.inc +++ b/common/haswell/Makefile.inc @@ -1,6 +1,8 @@ gfxinit-y += hw-gfx-gma-connectors-ddi-buffers.adb gfxinit-y += hw-gfx-gma-connectors-ddi-buffers.ads gfxinit-y += hw-gfx-gma-ddi_phy.ads +gfxinit-y += hw-gfx-gma-pch-lynxpoint.adb +gfxinit-y += hw-gfx-gma-pch-lynxpoint.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-pch-lynxpoint.adb b/common/haswell/hw-gfx-gma-pch-lynxpoint.adb new file mode 100644 index 0000000..9a89a58 --- /dev/null +++ b/common/haswell/hw-gfx-gma-pch-lynxpoint.adb @@ -0,0 +1,177 @@ +-- +-- Copyright (C) 2020 Angel Pons th3fanbus@gmail.com +-- +-- 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.Config; +with HW.GFX.GMA.Registers; +with HW.GFX.GMA.PCH.Sideband; + +with HW.Debug; +with GNAT.Source_Info; + +package body HW.GFX.GMA.PCH.Lynxpoint is + + FDI_MPHY_IOSFSB_RESET_CTL : constant := 1 * 2 ** 12; + FDI_MPHY_IOSFSB_RESET_STATUS : constant := 1 * 2 ** 13; + + procedure Reset_FDI_mPHY is + begin + Registers.Set_Mask + (Register => Registers.QUIRK_C2004, + Mask => FDI_MPHY_IOSFSB_RESET_CTL); + + Registers.Wait_Set_Mask + (Register => Registers.QUIRK_C2004, + Mask => FDI_MPHY_IOSFSB_RESET_STATUS, + TOut_MS => 1); -- 100 us + + Registers.Unset_Mask + (Register => Registers.QUIRK_C2004, + Mask => FDI_MPHY_IOSFSB_RESET_CTL); + + Registers.Wait_Unset_Mask + (Register => Registers.QUIRK_C2004, + Mask => FDI_MPHY_IOSFSB_RESET_STATUS, + TOut_MS => 1); -- 100 us + end Reset_FDI_mPHY; + + -- WaMPhyProgramming:hsw + procedure Program_FDI_mPHY + is + use Sideband; + subtype Bit_Index is Natural range 0 .. Word32'Size - 1; + + procedure mPHY_Update_Field + (High_Bit : in Bit_Index; + Low_Bit : in Bit_Index; + Value : in Word32; + Register : in Register_Type) + with + Pre => High_Bit >= Low_Bit + is + begin + Unset_And_Set_Mask + (Dest => SBI_MPHY, + Register => Register, + Mask_Unset => 2 ** (High_Bit + 1) - 2 ** Low_Bit, + Mask_Set => Value * 2 ** Low_Bit); + end mPHY_Update_Field; + + procedure mPHY_Update_Lanes + (High_Bit : in Bit_Index; + Low_Bit : in Bit_Index; + Value : in Word32; + Reg_Lane_0 : in Register_Type; + Reg_Lane_1 : in Register_Type) + with + Pre => High_Bit >= Low_Bit + is + begin + mPHY_Update_Field (High_Bit, Low_Bit, Value, Reg_Lane_0); + mPHY_Update_Field (High_Bit, Low_Bit, Value, Reg_Lane_1); + end mPHY_Update_Lanes; + begin + mPHY_Update_Field (31, 24, 16#12#, SBI_MPHY_8008); + mPHY_Update_Lanes (11, 11, 1, SBI_MPHY_2008, SBI_MPHY_2108); + mPHY_Update_Lanes (24, 24, 1, SBI_MPHY_206C, SBI_MPHY_216C); + mPHY_Update_Lanes (21, 21, 1, SBI_MPHY_206C, SBI_MPHY_216C); + mPHY_Update_Lanes (18, 18, 1, SBI_MPHY_206C, SBI_MPHY_216C); + mPHY_Update_Lanes (15, 13, 16#05#, SBI_MPHY_2080, SBI_MPHY_2180); + mPHY_Update_Lanes ( 7, 0, 16#1c#, SBI_MPHY_208C, SBI_MPHY_218C); + mPHY_Update_Lanes (23, 16, 16#1c#, SBI_MPHY_2098, SBI_MPHY_2198); + mPHY_Update_Lanes (27, 27, 1, SBI_MPHY_20C4, SBI_MPHY_21C4); + mPHY_Update_Lanes (31, 28, 16#04#, SBI_MPHY_20EC, SBI_MPHY_21EC); + end Program_FDI_mPHY; + + ---------------------------------------------------------------------------- + + SBI_SSCCTL_DISABLE : constant := 1 * 2 ** 0; + SBI_SSCCTL_PATHALT : constant := 1 * 2 ** 3; + SBI_GEN0_CFG_BUFFENABLE_DISABLE : constant := 1 * 2 ** 0; + + procedure Enable_Clkout_DP_And_FDI_mPHY is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Sideband.Unset_And_Set_Mask + (Dest => Sideband.SBI_ICLK, + Register => Sideband.SBI_SSCCTL, + Mask_Unset => SBI_SSCCTL_DISABLE, + Mask_Set => SBI_SSCCTL_PATHALT); + + Time.U_Delay (24); + + Sideband.Unset_Mask + (Dest => Sideband.SBI_ICLK, + Register => Sideband.SBI_SSCCTL, + Mask => SBI_SSCCTL_PATHALT); + + Reset_FDI_mPHY; + Program_FDI_mPHY; + + Sideband.Set_Mask + (Dest => Sideband.SBI_ICLK, + Register => (if Config.Is_LP then Sideband.SBI_GEN0 else Sideband.SBI_DBUFF0), + Mask => SBI_GEN0_CFG_BUFFENABLE_DISABLE); + end Enable_Clkout_DP_And_FDI_mPHY; + + procedure Disable_Clkout_DP + is + function Is_Mask_Set (Value, Mask : Word32) return Boolean is + ((Value and Mask) = Mask); + SSC_Ctl : Word32; + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Sideband.Unset_Mask + (Dest => Sideband.SBI_ICLK, + Register => (if Config.Is_LP then Sideband.SBI_GEN0 else Sideband.SBI_DBUFF0), + Mask => SBI_GEN0_CFG_BUFFENABLE_DISABLE); + + Sideband.Read + (Dest => Sideband.SBI_ICLK, + Register => Sideband.SBI_SSCCTL, + Value => SSC_Ctl); + + if not Is_Mask_Set (SSC_Ctl, SBI_SSCCTL_DISABLE) then + if not Is_Mask_Set (SSC_Ctl, SBI_SSCCTL_PATHALT) then + Sideband.Set_Mask + (Dest => Sideband.SBI_ICLK, + Register => Sideband.SBI_SSCCTL, + Mask => SBI_SSCCTL_PATHALT); + Time.U_Delay (32); + end if; + Sideband.Set_Mask + (Dest => Sideband.SBI_ICLK, + Register => Sideband.SBI_SSCCTL, + Mask => SBI_SSCCTL_DISABLE); + end if; + end Disable_Clkout_DP; + + procedure Unbend_Clkout_DP is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Sideband.Write + (Dest => Sideband.SBI_ICLK, + Register => Sideband.SBI_SSCDITHPHASE, + Value => 0); + + Sideband.Unset_And_Set_Mask + (Dest => Sideband.SBI_ICLK, + Register => Sideband.SBI_SSCDIVINTPHASE, + Mask_Unset => 16#ffff#, + Mask_Set => 16#0025#); + end Unbend_Clkout_DP; + +end HW.GFX.GMA.PCH.Lynxpoint; diff --git a/common/haswell/hw-gfx-gma-pch-lynxpoint.ads b/common/haswell/hw-gfx-gma-pch-lynxpoint.ads new file mode 100644 index 0000000..5782683 --- /dev/null +++ b/common/haswell/hw-gfx-gma-pch-lynxpoint.ads @@ -0,0 +1,21 @@ +-- +-- Copyright (C) 2020 Angel Pons th3fanbus@gmail.com +-- +-- 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. +-- + +package HW.GFX.GMA.PCH.Lynxpoint is + + procedure Enable_Clkout_DP_And_FDI_mPHY; + procedure Disable_Clkout_DP; + procedure Unbend_Clkout_DP; + +end HW.GFX.GMA.PCH.Lynxpoint; diff --git a/common/haswell/hw-gfx-gma-power_and_clocks_haswell.adb b/common/haswell/hw-gfx-gma-power_and_clocks_haswell.adb index e261ace..fa52899 100644 --- a/common/haswell/hw-gfx-gma-power_and_clocks_haswell.adb +++ b/common/haswell/hw-gfx-gma-power_and_clocks_haswell.adb @@ -21,6 +21,7 @@ with HW.GFX.GMA.PCode; with HW.GFX.GMA.Registers; with HW.GFX.GMA.Transcoder; +with HW.GFX.GMA.PCH.Lynxpoint;
package body HW.GFX.GMA.Power_And_Clocks_Haswell is
@@ -275,6 +276,13 @@ Config.CDClk := CDClk; end Set_CDClk;
+ procedure Post_All_Off is + begin + -- Reset CLKOUT_DP to disabled state + PCH.Lynxpoint.Disable_Clkout_DP; + PCH.Lynxpoint.Unbend_Clkout_DP; + end Post_All_Off; + procedure Initialize is CDClk : Config.CDClk_Range; @@ -289,6 +297,11 @@ Set_CDClk (Config.Default_CDClk_Freq);
Config.Raw_Clock := Config.Default_RawClk_Freq; + + -- Configure CLKOUT_DP for FDI + if Config.Has_DDI_E then + PCH.Lynxpoint.Enable_Clkout_DP_And_FDI_mPHY; + end if; end Initialize;
procedure Limit_Dotclocks diff --git a/common/haswell/hw-gfx-gma-power_and_clocks_haswell.ads b/common/haswell/hw-gfx-gma-power_and_clocks_haswell.ads index 2665122..488b90c 100644 --- a/common/haswell/hw-gfx-gma-power_and_clocks_haswell.ads +++ b/common/haswell/hw-gfx-gma-power_and_clocks_haswell.ads @@ -17,7 +17,7 @@ private package HW.GFX.GMA.Power_And_Clocks_Haswell is
procedure Pre_All_Off; - procedure Post_All_Off is null; + procedure Post_All_Off;
procedure Initialize;
diff --git a/common/hw-gfx-gma-pch-sideband.adb b/common/hw-gfx-gma-pch-sideband.adb index e848d86..41126bf 100644 --- a/common/hw-gfx-gma-pch-sideband.adb +++ b/common/hw-gfx-gma-pch-sideband.adb @@ -28,9 +28,30 @@
type Register_Array is array (Register_Type) of Word32; Register_Addr : constant Register_Array := Register_Array' - (SBI_SSCDIVINTPHASE6 => 16#0600_0000#, + (SBI_SSCDIVINTPHASE => 16#0200_0000#, + SBI_SSCDITHPHASE => 16#0204_0000#, + SBI_SSCCTL => 16#020c_0000#, + SBI_SSCDIVINTPHASE6 => 16#0600_0000#, SBI_SSCCTL6 => 16#060c_0000#, - SBI_SSCAUXDIV => 16#0610_0000#); + SBI_SSCAUXDIV => 16#0610_0000#, + SBI_GEN0 => 16#1f00_0000#, + SBI_DBUFF0 => 16#2a00_0000#, + + SBI_MPHY_2008 => 16#2008_0000#, + SBI_MPHY_206C => 16#206c_0000#, + SBI_MPHY_2080 => 16#2080_0000#, + SBI_MPHY_208C => 16#208c_0000#, + SBI_MPHY_2098 => 16#2098_0000#, + SBI_MPHY_20C4 => 16#20c4_0000#, + SBI_MPHY_20EC => 16#20ec_0000#, + SBI_MPHY_2108 => 16#2108_0000#, + SBI_MPHY_216C => 16#216c_0000#, + SBI_MPHY_2180 => 16#2180_0000#, + SBI_MPHY_218C => 16#218c_0000#, + SBI_MPHY_2198 => 16#2198_0000#, + SBI_MPHY_21C4 => 16#21c4_0000#, + SBI_MPHY_21EC => 16#21ec_0000#, + SBI_MPHY_8008 => 16#8008_0000#);
----------------------------------------------------------------------------
diff --git a/common/hw-gfx-gma-pch-sideband.ads b/common/hw-gfx-gma-pch-sideband.ads index e3073ae..8fb1586 100644 --- a/common/hw-gfx-gma-pch-sideband.ads +++ b/common/hw-gfx-gma-pch-sideband.ads @@ -17,9 +17,30 @@ type Destination_Type is (SBI_ICLK, SBI_MPHY);
type Register_Type is - (SBI_SSCDIVINTPHASE6, + (SBI_SSCDIVINTPHASE, + SBI_SSCDITHPHASE, + SBI_SSCCTL, + SBI_SSCDIVINTPHASE6, SBI_SSCCTL6, - SBI_SSCAUXDIV); + SBI_SSCAUXDIV, + SBI_GEN0, + SBI_DBUFF0, + + SBI_MPHY_2008, + SBI_MPHY_206C, + SBI_MPHY_2080, + SBI_MPHY_208C, + SBI_MPHY_2098, + SBI_MPHY_20C4, + SBI_MPHY_20EC, + SBI_MPHY_2108, + SBI_MPHY_216C, + SBI_MPHY_2180, + SBI_MPHY_218C, + SBI_MPHY_2198, + SBI_MPHY_21C4, + SBI_MPHY_21EC, + SBI_MPHY_8008);
procedure Read (Dest : in Destination_Type; diff --git a/common/hw-gfx-gma-transcoder.adb b/common/hw-gfx-gma-transcoder.adb index 9de8230..e74d769 100644 --- a/common/hw-gfx-gma-transcoder.adb +++ b/common/hw-gfx-gma-transcoder.adb @@ -236,6 +236,8 @@ 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) @@ -254,7 +256,7 @@ 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 (Port_Cfg.DP.Lane_Count)); + DDI_FUNC_CTL_PORT_WIDTH (Lane_Count)); end if;
Registers.Write