Nico Huber has uploaded this change for review. ( https://review.coreboot.org/22711
Change subject: gma: Add support for rotated framebuffers ......................................................................
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 --- M common/hw-gfx-gma-config.ads.template M common/hw-gfx-gma-config_helpers.adb M common/hw-gfx-gma-config_helpers.ads M common/hw-gfx-gma-pipe_setup.adb M common/hw-gfx-gma-pipe_setup.ads M common/hw-gfx-gma.adb M common/hw-gfx-gma.ads M common/hw-gfx.ads 8 files changed, 132 insertions(+), 57 deletions(-)
git pull ssh://review.coreboot.org:29418/libgfxinit refs/changes/11/22711/1
diff --git a/common/hw-gfx-gma-config.ads.template b/common/hw-gfx-gma-config.ads.template index 252b023..31fa7ba 100644 --- a/common/hw-gfx-gma-config.ads.template +++ b/common/hw-gfx-gma-config.ads.template @@ -252,7 +252,7 @@ -- Maximum source width with enabled scaler. This only accounts -- for simple 1:1 pipe:scaler mappings.
- type Width_Per_Pipe is array (Pipe_Index) of Width_Type; + type Width_Per_Pipe is array (Pipe_Index) of Pos16;
Maximum_Scalable_Width : constant Width_Per_Pipe := (case CPU is diff --git a/common/hw-gfx-gma-config_helpers.adb b/common/hw-gfx-gma-config_helpers.adb index 6eff5d2..f2b4ef6 100644 --- a/common/hw-gfx-gma-config_helpers.adb +++ b/common/hw-gfx-gma-config_helpers.adb @@ -181,9 +181,9 @@ -- Validates that a given configuration should work with -- a given framebuffer. function Validate_Config - (Framebuffer : Framebuffer_Type; - Port_Cfg : Port_Config; - Pipe : Pipe_Index) + (FB : Framebuffer_Type; + Port_Cfg : Port_Config; + Pipe : Pipe_Index) return Boolean is begin @@ -193,18 +193,21 @@ -- Only 32bpp RGB (ignored for VGA plane) -- Stride must be big enough and a multiple of 64 bytes or the tile size -- (ignored for VGA plane) - -- Tiling is only supported on newer generations (with Plane_Control) + -- Tiling and rotation is only supported on newer generations (with + -- Plane_Control) + -- 90 degree rotations are only supported with Y-tiling return - ((Framebuffer.Width = Pos32 (Port_Cfg.Mode.H_Visible) and - Framebuffer.Height = Pos32 (Port_Cfg.Mode.V_Visible)) or - (Framebuffer.Width <= Config.Maximum_Scalable_Width (Pipe) and - Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and - Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible))) and - (Framebuffer.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or Pipe = Primary) - and - (Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or - (Framebuffer.BPC = 8 and Valid_Stride (Framebuffer) and - (Config.Has_Plane_Control or Framebuffer.Tiling = Linear))); + ((Rotated_Width (FB) = Port_Cfg.Mode.H_Visible and + Rotated_Height (FB) = Port_Cfg.Mode.V_Visible) or + (Rotated_Width (FB) <= Config.Maximum_Scalable_Width (Pipe) and + Rotated_Width (FB) <= Port_Cfg.Mode.H_Visible and + Rotated_Height (FB) <= Port_Cfg.Mode.V_Visible)) and + (FB.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or Pipe = Primary) and + (FB.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or + (FB.BPC = 8 and Valid_Stride (FB) and + (Config.Has_Plane_Control or + (FB.Tiling = Linear and FB.Rotation = No_Rotation)) and + (FB.Tiling = Y_Tiled or not Rotation_90 (FB)))); end Validate_Config;
end HW.GFX.GMA.Config_Helpers; diff --git a/common/hw-gfx-gma-config_helpers.ads b/common/hw-gfx-gma-config_helpers.ads index a9cde2b..e684f22 100644 --- a/common/hw-gfx-gma-config_helpers.ads +++ b/common/hw-gfx-gma-config_helpers.ads @@ -40,14 +40,16 @@ use type HW.Pos32; pragma Warnings (GNAT, On, """Integer_32"" is already use-visible *"); function Validate_Config - (Framebuffer : Framebuffer_Type; - Port_Cfg : Port_Config; - Pipe : Pipe_Index) + (FB : Framebuffer_Type; + Port_Cfg : Port_Config; + Pipe : Pipe_Index) return Boolean with Post => (if Validate_Config'Result then - Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and - Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible)); + Rotated_Width (FB) <= Port_Cfg.Mode.H_Visible and + Rotated_Height (FB) <= Port_Cfg.Mode.V_Visible and + (FB.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or + FB.Height <= FB.V_Stride));
end HW.GFX.GMA.Config_Helpers; 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); diff --git a/common/hw-gfx-gma-pipe_setup.ads b/common/hw-gfx-gma-pipe_setup.ads index 725bc08..35d9e87 100644 --- a/common/hw-gfx-gma-pipe_setup.ads +++ b/common/hw-gfx-gma-pipe_setup.ads @@ -25,8 +25,10 @@ Framebuffer : Framebuffer_Type) with Pre => - Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and - Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible); + Rotated_Width (Framebuffer) <= Port_Cfg.Mode.H_Visible and + Rotated_Height (Framebuffer) <= Port_Cfg.Mode.V_Visible and + (Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or + Framebuffer.Height <= Framebuffer.V_Stride);
procedure Off (Pipe : Pipe_Index);
diff --git a/common/hw-gfx-gma.adb b/common/hw-gfx-gma.adb index 76b271d..d6cd2c0 100644 --- a/common/hw-gfx-gma.adb +++ b/common/hw-gfx-gma.adb @@ -464,7 +464,7 @@
-- Check basics and that it fits in GTT function Valid_FB (FB : Framebuffer_Type) return Boolean is - (Valid_Stride (FB) and FB_Last_Page (FB) <= GTT_Range'Last); + (Valid_Stride (FB) and FB_Last_Page (FB) < GTT_Rotation_Offset);
-- Also check that we don't overflow the GTT's 39-bit space -- (always true with a 32-bit base) @@ -499,6 +499,30 @@ Valid => True); Phys_Addr := Phys_Addr + GTT_Page_Size; end loop; + + if Rotation_90 (FB) and FB.Tiling = Y_Tiled and FB.V_Stride >= 32 then + declare + V_Pages : constant Natural := Natural (FB.V_Stride) / 32; + Bytes_Per_Row : constant GTT_Address_Type := + GTT_Address_Type (Pixel_To_Bytes (32 * FB.Stride, FB)); + begin + Phys_Addr := GTT_Address_Type (Phys_Base) + + GTT_Address_Type (FB.Offset) + + GTT_Address_Type (FB_Size (FB)); + for Page in FB_First_Page (FB) .. FB_Last_Page (FB) loop + Phys_Addr := Phys_Addr - Bytes_Per_Row; + Registers.Write_GTT + (GTT_Page => GTT_Rotation_Offset + Page, + Device_Address => Phys_Addr, + Valid => True); + + if (Page - FB_First_Page (FB) + 1) mod V_Pages = 0 then + Phys_Addr := Phys_Addr + GTT_Page_Size + + GTT_Address_Type (V_Pages) * Bytes_Per_Row; + end if; + end loop; + end; + end if; end Setup_Default_GTT;
---------------------------------------------------------------------------- diff --git a/common/hw-gfx-gma.ads b/common/hw-gfx-gma.ads index 9943e44..50a76a0 100644 --- a/common/hw-gfx-gma.ads +++ b/common/hw-gfx-gma.ads @@ -95,6 +95,8 @@ GTT_Page_Size : constant := 4096; type GTT_Address_Type is mod 2 ** 39; subtype GTT_Range is Natural range 0 .. 16#8_0000# - 1; + GTT_Rotation_Offset : constant GTT_Range := GTT_Range'Last / 2 + 1; + procedure Write_GTT (GTT_Page : GTT_Range; Device_Address : GTT_Address_Type; @@ -161,6 +163,8 @@
Tile_Width : constant array (Tiling_Type) of Pos32 := (Linear => 16, X_Tiled => 128, Y_Tiled => 32); + Tile_Rows : constant array (Tiling_Type) of Pos32 := + (Linear => 1, X_Tiled => 8, Y_Tiled => 32);
function FB_Pitch (Px : Pixel_Type; FB : Framebuffer_Type) return Natural is (Natural (Div_Round_Up @@ -168,6 +172,8 @@
function Valid_Stride (FB : Framebuffer_Type) return Boolean is (FB.Width <= FB.Stride and - Pixel_To_Bytes (FB.Stride, FB) mod (Tile_Width (FB.Tiling) * 4) = 0); + Pixel_To_Bytes (FB.Stride, FB) mod (Tile_Width (FB.Tiling) * 4) = 0 and + FB.Height <= FB.V_Stride and + FB.V_Stride mod Tile_Rows (FB.Tiling) = 0);
end HW.GFX.GMA; diff --git a/common/hw-gfx.ads b/common/hw-gfx.ads index 5594b18..5d8ae59 100644 --- a/common/hw-gfx.ads +++ b/common/hw-gfx.ads @@ -47,6 +47,14 @@ Offset : Word32; end record;
+ function Rotation_90 (FB : Framebuffer_Type) return Boolean is + (FB.Rotation = Rotated_90 or FB.Rotation = Rotated_270); + + function Rotated_Width (FB : Framebuffer_Type) return Pos16 is + (if Rotation_90 (FB) then Pos16 (FB.Height) else Pos16 (FB.Width)); + function Rotated_Height (FB : Framebuffer_Type) return Pos16 is + (if Rotation_90 (FB) then Pos16 (FB.Width) else Pos16 (FB.Height)); + function Pixel_To_Bytes (Pixel : Pixel_Type; FB : Framebuffer_Type) return Pos32 is (Pixel * Pos32 (FB.BPC) / (8 / 4)); function FB_Size (FB : Framebuffer_Type) return Pos32 is