gma: Configure panel fitter / pipe scaler
If the framebuffer size is smaller than the display mode's resolution,
enable the panel fitter or pipe scaler (on Skylake+).
Change-Id: I0a648a7e7bf495a80636a589a74b698ecba7e7d5
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.coreboot.org/17263
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Tested-by: Nico Huber <nico.h@gmx.de>
diff --git a/common/hw-gfx-gma-config.ads.template b/common/hw-gfx-gma-config.ads.template
index 7a83e77..7289dff 100644
--- a/common/hw-gfx-gma-config.ads.template
+++ b/common/hw-gfx-gma-config.ads.template
@@ -48,6 +48,7 @@
Has_Pipeconf_BPC : constant Boolean := CPU /= Haswell;
Has_Plane_Control : constant Boolean := CPU >= Skylake;
Has_DSP_Linoff : constant Boolean := CPU <= Ivybridge;
+ Has_PF_Pipe_Select : constant Boolean := CPU in Ivybridge .. Haswell;
----- Panel power: -----
Has_PP_Write_Protection : constant Boolean := CPU <= Ivybridge;
diff --git a/common/hw-gfx-gma-pipe_setup.adb b/common/hw-gfx-gma-pipe_setup.adb
index 2d13a01..b902b77 100644
--- a/common/hw-gfx-gma-pipe_setup.adb
+++ b/common/hw-gfx-gma-pipe_setup.adb
@@ -64,11 +64,13 @@
PIPECONF_ENABLE_DITHER : constant := 1 * 2 ** 4;
PIPECONF_DITHER_TEMPORAL : constant := 1 * 2 ** 2;
- PF_CTL_1_ENABLE : constant Word32 := 1 * 2 ** 31;
+ PF_CTRL_ENABLE : constant := 1 * 2 ** 31;
+ PF_CTRL_PIPE_SELECT_MASK : constant := 3 * 2 ** 29;
+ PF_CTRL_FILTER_MED : constant := 1 * 2 ** 23;
- PS_CTRL_ENABLE_SCALER : constant Word32 := 1 * 2 ** 31;
- PS_CTRL_SCALER_MODE_7X5_EXTENDED : constant Word32 := 1 * 2 ** 28;
- PS_CTRL_FILTER_SELECT_MEDIUM_2 : constant Word32 := 1 * 2 ** 23;
+ PS_CTRL_ENABLE_SCALER : constant := 1 * 2 ** 31;
+ PS_CTRL_SCALER_MODE_7X5_EXTENDED : constant := 1 * 2 ** 28;
+ PS_CTRL_FILTER_SELECT_MEDIUM_2 : constant := 1 * 2 ** 23;
PIPE_DDI_FUNC_CTL_ENABLE : constant := 1 * 2 ** 31;
PIPE_DDI_FUNC_CTL_DDI_SELECT_MASK : constant := 7 * 2 ** 28;
@@ -385,6 +387,148 @@
----------------------------------------------------------------------------
+ procedure Scale_Keep_Aspect
+ (Width : out Pos32;
+ Height : out Pos32;
+ Max_Width : in Pos32;
+ Max_Height : in Pos32;
+ Framebuffer : in Framebuffer_Type)
+ with
+ Pre =>
+ Max_Width <= Pos32 (Pos16'Last) and
+ Max_Height <= Pos32 (Pos16'Last) and
+ Framebuffer.Width <= Max_Width and
+ Framebuffer.Height <= Max_Height,
+ Post =>
+ Width <= Max_Width and Height <= Max_Height
+ is
+ begin
+ if (Max_Width * Framebuffer.Height) / Framebuffer.Width <= Max_Height then
+ Width := Max_Width;
+ Height := (Max_Width * Framebuffer.Height) / Framebuffer.Width;
+ else
+ Height := Max_Height;
+ Width := Pos32'Min (Max_Width, -- could prove, it's <= Max_Width
+ (Max_Height * Framebuffer.Width) / Framebuffer.Height);
+ end if;
+ end Scale_Keep_Aspect;
+
+ procedure Setup_Skylake_Pipe_Scaler
+ (Controller : in Controller_Type;
+ Mode : in HW.GFX.Mode_Type;
+ Framebuffer : in HW.GFX.Framebuffer_Type)
+ with
+ Pre =>
+ Framebuffer.Width <= Pos32 (Mode.H_Visible) and
+ Framebuffer.Height <= Pos32 (Mode.V_Visible)
+ is
+ -- Enable 7x5 extended mode where possible:
+ Scaler_Mode : constant Word32 :=
+ (if Controller.PS_CTRL_2 /= Registers.Invalid_Register then
+ PS_CTRL_SCALER_MODE_7X5_EXTENDED else 0);
+
+ -- We can scale up to 2.99x horizontally:
+ Horizontal_Limit : constant Pos32 := ((Framebuffer.Width * 299) / 100);
+ -- The third scaler is limited to 1.99x
+ -- vertical scaling for source widths > 2048:
+ Vertical_Limit : constant Pos32 :=
+ (Framebuffer.Height *
+ (if Controller.PS_CTRL_2 = Registers.Invalid_Register and
+ Framebuffer.Width > 2048
+ then
+ 199
+ else
+ 299)) / 100;
+
+ Width, Height : Pos32;
+ begin
+ -- Writes to WIN_SZ arm the PS registers.
+
+ Scale_Keep_Aspect
+ (Width => Width,
+ Height => Height,
+ Max_Width => Pos32'Min (Horizontal_Limit, Pos32 (Mode.H_Visible)),
+ Max_Height => Pos32'Min (Vertical_Limit, Pos32 (Mode.V_Visible)),
+ Framebuffer => Framebuffer);
+
+ Registers.Write
+ (Register => Controller.PS_CTRL_1,
+ Value => PS_CTRL_ENABLE_SCALER or Scaler_Mode);
+ Registers.Write
+ (Register => Controller.PS_WIN_POS_1,
+ Value =>
+ Shift_Left (Word32 (Pos32 (Mode.H_Visible) - Width) / 2, 16) or
+ Word32 (Pos32 (Mode.V_Visible) - Height) / 2);
+ Registers.Write
+ (Register => Controller.PS_WIN_SZ_1,
+ Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
+ end Setup_Skylake_Pipe_Scaler;
+
+ procedure Setup_Ironlake_Panel_Fitter
+ (Controller : in Controller_Type;
+ Mode : in HW.GFX.Mode_Type;
+ Framebuffer : in HW.GFX.Framebuffer_Type)
+ with
+ Pre =>
+ Framebuffer.Width <= Pos32 (Mode.H_Visible) and
+ Framebuffer.Height <= Pos32 (Mode.V_Visible)
+ is
+ -- Force 1:1 mapping of panel fitter:pipe
+ PF_Ctrl_Pipe_Sel : constant Word32 :=
+ (if Config.Has_PF_Pipe_Select then
+ (case Controller.PF_CTRL is
+ when Registers.PFA_CTL_1 => 0 * 2 ** 29,
+ when Registers.PFB_CTL_1 => 1 * 2 ** 29,
+ when Registers.PFC_CTL_1 => 2 * 2 ** 29,
+ when others => 0) else 0);
+
+ Width, Height : Pos32;
+ begin
+ -- Writes to WIN_SZ arm the PF registers.
+
+ Scale_Keep_Aspect
+ (Width => Width,
+ Height => Height,
+ Max_Width => Pos32 (Mode.H_Visible),
+ Max_Height => Pos32 (Mode.V_Visible),
+ Framebuffer => Framebuffer);
+
+ Registers.Write
+ (Register => Controller.PF_CTRL,
+ Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_CTRL_FILTER_MED);
+ Registers.Write
+ (Register => Controller.PF_WIN_POS,
+ Value =>
+ Shift_Left (Word32 (Pos32 (Mode.H_Visible) - Width) / 2, 16) or
+ Word32 (Pos32 (Mode.V_Visible) - Height) / 2);
+ Registers.Write
+ (Register => Controller.PF_WIN_SZ,
+ Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
+ end Setup_Ironlake_Panel_Fitter;
+
+ procedure Setup_Scaling
+ (Controller : in Controller_Type;
+ Mode : in HW.GFX.Mode_Type;
+ Framebuffer : in HW.GFX.Framebuffer_Type)
+ with
+ Pre =>
+ Framebuffer.Width <= Pos32 (Mode.H_Visible) and
+ Framebuffer.Height <= Pos32 (Mode.V_Visible)
+ is
+ begin
+ if Framebuffer.Width /= Pos32 (Mode.H_Visible) or
+ Framebuffer.Height /= Pos32 (Mode.V_Visible)
+ then
+ if Config.Has_Plane_Control then
+ Setup_Skylake_Pipe_Scaler (Controller, Mode, Framebuffer);
+ else
+ Setup_Ironlake_Panel_Fitter (Controller, Mode, Framebuffer);
+ end if;
+ end if;
+ end Setup_Scaling;
+
+ ----------------------------------------------------------------------------
+
procedure Setup_Head
(Controller : Controller_Type;
Head : Head_Type;
@@ -456,6 +600,8 @@
Setup_Display (Controller, Head, Port_Cfg.Mode, Framebuffer);
+ Setup_Scaling (Controller, Port_Cfg.Mode, Framebuffer);
+
Setup_Head (Controller, Head, Port_Cfg, Framebuffer);
end On;
@@ -511,7 +657,7 @@
Registers.Write (Controller.PS_WIN_SZ_2, 16#0000_0000#);
end if;
else
- Registers.Unset_Mask (Controller.PF_CTL_1, PF_CTL_1_ENABLE);
+ Registers.Unset_Mask (Controller.PF_CTRL, PF_CTRL_ENABLE);
Registers.Write (Controller.PF_WIN_SZ, 16#0000_0000#);
end if;
end Panel_Fitter_Off;
diff --git a/common/hw-gfx-gma-pipe_setup.ads b/common/hw-gfx-gma-pipe_setup.ads
index b696934..c485f1a 100644
--- a/common/hw-gfx-gma-pipe_setup.ads
+++ b/common/hw-gfx-gma-pipe_setup.ads
@@ -65,7 +65,7 @@
Kind : Controller_Kind;
PIPESRC : Registers.Registers_Index;
PIPEMISC : Registers.Registers_Index;
- PF_CTL_1 : Registers.Registers_Index;
+ PF_CTRL : Registers.Registers_Index;
PF_WIN_POS : Registers.Registers_Index;
PF_WIN_SZ : Registers.Registers_Index;
DSPCNTR : Registers.Registers_Index;
@@ -83,8 +83,9 @@
PLANE_STRIDE : Registers.Registers_Index;
PLANE_SURF : Registers.Registers_Index;
PS_CTRL_1 : Registers.Registers_Index;
- PS_CTRL_2 : Registers.Registers_Invalid_Index;
+ PS_WIN_POS_1 : Registers.Registers_Index;
PS_WIN_SZ_1 : Registers.Registers_Index;
+ PS_CTRL_2 : Registers.Registers_Invalid_Index;
PS_WIN_SZ_2 : Registers.Registers_Invalid_Index;
WM_LINETIME : Registers.Registers_Index;
PLANE_BUF_CFG : Registers.Registers_Index;
@@ -114,7 +115,7 @@
(Kind => A,
PIPESRC => Registers.PIPEASRC,
PIPEMISC => Registers.PIPEAMISC,
- PF_CTL_1 => Registers.PFA_CTL_1,
+ PF_CTRL => Registers.PFA_CTL_1,
PF_WIN_POS => Registers.PFA_WIN_POS,
PF_WIN_SZ => Registers.PFA_WIN_SZ,
DSPCNTR => Registers.DSPACNTR,
@@ -131,8 +132,9 @@
PLANE_STRIDE => Registers.DSPASTRIDE,
PLANE_SURF => Registers.DSPASURF,
PS_CTRL_1 => Registers.PS_CTRL_1_A,
- PS_CTRL_2 => Registers.PS_CTRL_2_A,
+ PS_WIN_POS_1 => Registers.PS_WIN_POS_1_A,
PS_WIN_SZ_1 => Registers.PS_WIN_SZ_1_A,
+ PS_CTRL_2 => Registers.PS_CTRL_2_A,
PS_WIN_SZ_2 => Registers.PS_WIN_SZ_2_A,
WM_LINETIME => Registers.WM_LINETIME_A,
PLANE_BUF_CFG => Registers.PLANE_BUF_CFG_1_A,
@@ -149,7 +151,7 @@
(Kind => B,
PIPESRC => Registers.PIPEBSRC,
PIPEMISC => Registers.PIPEBMISC,
- PF_CTL_1 => Registers.PFB_CTL_1,
+ PF_CTRL => Registers.PFB_CTL_1,
PF_WIN_POS => Registers.PFB_WIN_POS,
PF_WIN_SZ => Registers.PFB_WIN_SZ,
DSPCNTR => Registers.DSPBCNTR,
@@ -166,8 +168,9 @@
PLANE_STRIDE => Registers.DSPBSTRIDE,
PLANE_SURF => Registers.DSPBSURF,
PS_CTRL_1 => Registers.PS_CTRL_1_B,
- PS_CTRL_2 => Registers.PS_CTRL_2_B,
+ PS_WIN_POS_1 => Registers.PS_WIN_POS_1_B,
PS_WIN_SZ_1 => Registers.PS_WIN_SZ_1_B,
+ PS_CTRL_2 => Registers.PS_CTRL_2_B,
PS_WIN_SZ_2 => Registers.PS_WIN_SZ_2_B,
WM_LINETIME => Registers.WM_LINETIME_B,
PLANE_BUF_CFG => Registers.PLANE_BUF_CFG_1_B,
@@ -184,7 +187,7 @@
(Kind => C,
PIPESRC => Registers.PIPECSRC,
PIPEMISC => Registers.PIPECMISC,
- PF_CTL_1 => Registers.PFC_CTL_1,
+ PF_CTRL => Registers.PFC_CTL_1,
PF_WIN_POS => Registers.PFC_WIN_POS,
PF_WIN_SZ => Registers.PFC_WIN_SZ,
DSPCNTR => Registers.DSPCCNTR,
@@ -201,8 +204,9 @@
PLANE_STRIDE => Registers.DSPCSTRIDE,
PLANE_SURF => Registers.DSPCSURF,
PS_CTRL_1 => Registers.PS_CTRL_1_C,
- PS_CTRL_2 => Registers.Invalid_Register,
+ PS_WIN_POS_1 => Registers.PS_WIN_POS_1_C,
PS_WIN_SZ_1 => Registers.PS_WIN_SZ_1_C,
+ PS_CTRL_2 => Registers.Invalid_Register,
PS_WIN_SZ_2 => Registers.Invalid_Register,
WM_LINETIME => Registers.WM_LINETIME_C,
PLANE_BUF_CFG => Registers.PLANE_BUF_CFG_1_C,