gma: Add support for rotated framebuffers
As for the tiling, we enable support for rotated framebuffers on
platforms with Plane_Control. On every path where a rotated frame-
buffer may be expected, we have to exchange width and height in
case of 90 degree rotations. Beside the rotation setting itself,
the hardware needs to know the vertical stride instead of the hori-
zontal and a delicate page mapping in case of 90 degree rotations.
For that we divide the GTT space into two, the lower half contains
the linear mappings, the upper half mappings for a rotated scanout.
Change-Id: I1c901b7abc0fe7764bee87f6fda58ba9fa3f340d
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/22711
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Tested-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
diff --git a/common/hw-gfx-gma-pipe_setup.adb b/common/hw-gfx-gma-pipe_setup.adb
index 215b4de..e1ff835 100644
--- a/common/hw-gfx-gma-pipe_setup.adb
+++ b/common/hw-gfx-gma-pipe_setup.adb
@@ -50,6 +50,13 @@
X_Tiled => PLANE_CTL_TILED_SURFACE_X_TILED,
Y_Tiled => PLANE_CTL_TILED_SURFACE_Y_TILED);
+ PLANE_CTL_PLANE_ROTATION_MASK : constant := 3 * 2 ** 0;
+ PLANE_CTL_PLANE_ROTATION : constant array (Rotation_Type) of Word32 :=
+ (No_Rotation => 0 * 2 ** 0,
+ Rotated_90 => 1 * 2 ** 0,
+ Rotated_180 => 2 * 2 ** 0,
+ Rotated_270 => 3 * 2 ** 0);
+
PLANE_WM_ENABLE : constant := 1 * 2 ** 31;
PLANE_WM_LINES_SHIFT : constant := 14;
PLANE_WM_LINES_MASK : constant := 16#001f# * 2 ** 14;
@@ -149,7 +156,8 @@
=>+
(Registers.Register_State,
Controller,
- FB))
+ FB)),
+ Pre => FB.Height <= FB.V_Stride
is
-- FIXME: setup correct format, based on framebuffer RGB format
Format : constant Word32 := 6 * 2 ** 26;
@@ -158,20 +166,34 @@
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
if Config.Has_Plane_Control then
- Registers.Write
- (Register => Controller.PLANE_CTL,
- Value => PLANE_CTL_PLANE_ENABLE or
- PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
- PLANE_CTL_PLANE_GAMMA_DISABLE or
- PLANE_CTL_TILED_SURFACE (FB.Tiling));
- Registers.Write (Controller.PLANE_OFFSET, 16#0000_0000#);
- Registers.Write
- (Controller.PLANE_SIZE,
- Encode (Pos16 (FB.Width), Pos16 (FB.Height)));
- Registers.Write
- (Controller.PLANE_STRIDE, Word32 (FB_Pitch (FB.Stride, FB)));
- Registers.Write (Controller.PLANE_POS, 16#0000_0000#);
- Registers.Write (Controller.PLANE_SURF, FB.Offset and 16#ffff_f000#);
+ declare
+ Stride, Offset, GTT_Addr : Word32;
+ Width : constant Pos16 := Rotated_Width (FB);
+ Height : constant Pos16 := Rotated_Height (FB);
+ begin
+ if Rotation_90 (FB) then
+ Stride := Word32 (FB_Pitch (FB.V_Stride, FB));
+ Offset := Word32 (FB.V_Stride - FB.Height);
+ GTT_Addr :=
+ FB.Offset + Word32 (GTT_Rotation_Offset) * GTT_Page_Size;
+ else
+ Stride := Word32 (FB_Pitch (FB.Stride, FB));
+ Offset := 0;
+ GTT_Addr := FB.Offset;
+ end if;
+ Registers.Write
+ (Register => Controller.PLANE_CTL,
+ Value => PLANE_CTL_PLANE_ENABLE or
+ PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
+ PLANE_CTL_PLANE_GAMMA_DISABLE or
+ PLANE_CTL_TILED_SURFACE (FB.Tiling) or
+ PLANE_CTL_PLANE_ROTATION (FB.Rotation));
+ Registers.Write (Controller.PLANE_OFFSET, Offset);
+ Registers.Write (Controller.PLANE_SIZE, Encode (Width, Height));
+ Registers.Write (Controller.PLANE_STRIDE, Stride);
+ Registers.Write (Controller.PLANE_POS, 16#0000_0000#);
+ Registers.Write (Controller.PLANE_SURF, GTT_Addr and 16#ffff_f000#);
+ end;
else
if Config.Disable_Trickle_Feed then
PRI := PRI or DSPCNTR_DISABLE_TRICKLE_FEED;
@@ -210,7 +232,10 @@
Dither),
Port_IO.State
=>+
- (Framebuffer))
+ (Framebuffer)),
+ Pre =>
+ Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
+ Framebuffer.Height <= Framebuffer.V_Stride
is
use type Word8;
@@ -252,7 +277,7 @@
Registers.Write
(Register => Controller.PIPESRC,
Value => Encode
- (Pos16 (Framebuffer.Height), Pos16 (Framebuffer.Width)));
+ (Rotated_Height (Framebuffer), Rotated_Width (Framebuffer)));
if Config.Has_Pipeconf_Misc then
Registers.Write
@@ -273,19 +298,21 @@
Pre =>
Max_Width <= Pos32 (Pos16'Last) and
Max_Height <= Pos32 (Pos16'Last) and
- Framebuffer.Width <= Max_Width and
- Framebuffer.Height <= Max_Height,
+ Pos32 (Rotated_Width (Framebuffer)) <= Max_Width and
+ Pos32 (Rotated_Height (Framebuffer)) <= Max_Height,
Post =>
Width <= Max_Width and Height <= Max_Height
is
+ Src_Width : constant Pos32 := Pos32 (Rotated_Width (Framebuffer));
+ Src_Height : constant Pos32 := Pos32 (Rotated_Height (Framebuffer));
begin
- if (Max_Width * Framebuffer.Height) / Framebuffer.Width <= Max_Height then
+ if (Max_Width * Src_Height) / Src_Width <= Max_Height then
Width := Max_Width;
- Height := (Max_Width * Framebuffer.Height) / Framebuffer.Width;
+ Height := (Max_Width * Src_Height) / Src_Width;
else
Height := Max_Height;
Width := Pos32'Min (Max_Width, -- could prove, it's <= Max_Width
- (Max_Height * Framebuffer.Width) / Framebuffer.Height);
+ (Max_Height * Src_Width) / Src_Height);
end if;
end Scale_Keep_Aspect;
@@ -295,8 +322,8 @@
Framebuffer : in HW.GFX.Framebuffer_Type)
with
Pre =>
- Framebuffer.Width <= Pos32 (Mode.H_Visible) and
- Framebuffer.Height <= Pos32 (Mode.V_Visible)
+ Rotated_Width (Framebuffer) <= Mode.H_Visible and
+ Rotated_Height (Framebuffer) <= Mode.V_Visible
is
use type Registers.Registers_Invalid_Index;
@@ -305,14 +332,17 @@
(if Controller.PS_CTRL_2 /= Registers.Invalid_Register then
PS_CTRL_SCALER_MODE_7X5_EXTENDED else 0);
+ Width_In : constant Pos32 := Pos32 (Rotated_Width (Framebuffer));
+ Height_In : constant Pos32 := Pos32 (Rotated_Height (Framebuffer));
+
-- We can scale up to 2.99x horizontally:
- Horizontal_Limit : constant Pos32 := ((Framebuffer.Width * 299) / 100);
+ Horizontal_Limit : constant Pos32 := (Width_In * 299) / 100;
-- The third scaler is limited to 1.99x
-- vertical scaling for source widths > 2048:
Vertical_Limit : constant Pos32 :=
- (Framebuffer.Height *
+ (Height_In *
(if Controller.PS_CTRL_2 = Registers.Invalid_Register and
- Framebuffer.Width > 2048
+ Width_In > 2048
then
199
else
@@ -348,8 +378,8 @@
Framebuffer : in HW.GFX.Framebuffer_Type)
with
Pre =>
- Framebuffer.Width <= Pos32 (Mode.H_Visible) and
- Framebuffer.Height <= Pos32 (Mode.V_Visible)
+ Rotated_Width (Framebuffer) <= Mode.H_Visible and
+ Rotated_Height (Framebuffer) <= Mode.V_Visible
is
-- Force 1:1 mapping of panel fitter:pipe
PF_Ctrl_Pipe_Sel : constant Word32 :=
@@ -390,12 +420,12 @@
Framebuffer : in HW.GFX.Framebuffer_Type)
with
Pre =>
- Framebuffer.Width <= Pos32 (Mode.H_Visible) and
- Framebuffer.Height <= Pos32 (Mode.V_Visible)
+ Rotated_Width (Framebuffer) <= Mode.H_Visible and
+ Rotated_Height (Framebuffer) <= Mode.V_Visible
is
begin
- if Framebuffer.Width /= Pos32 (Mode.H_Visible) or
- Framebuffer.Height /= Pos32 (Mode.V_Visible)
+ if Rotated_Width (Framebuffer) /= Mode.H_Visible or
+ Rotated_Height (Framebuffer) /= Mode.V_Visible
then
if Config.Has_Plane_Control then
Setup_Skylake_Pipe_Scaler (Controller, Mode, Framebuffer);