<p>Nico Huber has uploaded this change for <strong>review</strong>.</p><p><a href="https://review.coreboot.org/22711">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">gma: Add support for rotated framebuffers<br><br>As for the tiling, we enable support for rotated framebuffers on<br>platforms with Plane_Control. On every path where a rotated frame-<br>buffer may be expected, we have to exchange width and height in<br>case of 90 degree rotations. Beside the rotation setting itself,<br>the hardware needs to know the vertical stride instead of the hori-<br>zontal and a delicate page mapping in case of 90 degree rotations.<br>For that we divide the GTT space into two, the lower half contains<br>the linear mappings, the upper half mappings for a rotated scanout.<br><br>Change-Id: I1c901b7abc0fe7764bee87f6fda58ba9fa3f340d<br>Signed-off-by: Nico Huber <nico.h@gmx.de><br>---<br>M common/hw-gfx-gma-config.ads.template<br>M common/hw-gfx-gma-config_helpers.adb<br>M common/hw-gfx-gma-config_helpers.ads<br>M common/hw-gfx-gma-pipe_setup.adb<br>M common/hw-gfx-gma-pipe_setup.ads<br>M common/hw-gfx-gma.adb<br>M common/hw-gfx-gma.ads<br>M common/hw-gfx.ads<br>8 files changed, 132 insertions(+), 57 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://review.coreboot.org:29418/libgfxinit refs/changes/11/22711/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/common/hw-gfx-gma-config.ads.template b/common/hw-gfx-gma-config.ads.template<br>index 252b023..31fa7ba 100644<br>--- a/common/hw-gfx-gma-config.ads.template<br>+++ b/common/hw-gfx-gma-config.ads.template<br>@@ -252,7 +252,7 @@<br> -- Maximum source width with enabled scaler. This only accounts<br> -- for simple 1:1 pipe:scaler mappings.<br> <br>- type Width_Per_Pipe is array (Pipe_Index) of Width_Type;<br>+ type Width_Per_Pipe is array (Pipe_Index) of Pos16;<br> <br> Maximum_Scalable_Width : constant Width_Per_Pipe :=<br> (case CPU is<br>diff --git a/common/hw-gfx-gma-config_helpers.adb b/common/hw-gfx-gma-config_helpers.adb<br>index 6eff5d2..f2b4ef6 100644<br>--- a/common/hw-gfx-gma-config_helpers.adb<br>+++ b/common/hw-gfx-gma-config_helpers.adb<br>@@ -181,9 +181,9 @@<br> -- Validates that a given configuration should work with<br> -- a given framebuffer.<br> function Validate_Config<br>- (Framebuffer : Framebuffer_Type;<br>- Port_Cfg : Port_Config;<br>- Pipe : Pipe_Index)<br>+ (FB : Framebuffer_Type;<br>+ Port_Cfg : Port_Config;<br>+ Pipe : Pipe_Index)<br> return Boolean<br> is<br> begin<br>@@ -193,18 +193,21 @@<br> -- Only 32bpp RGB (ignored for VGA plane)<br> -- Stride must be big enough and a multiple of 64 bytes or the tile size<br> -- (ignored for VGA plane)<br>- -- Tiling is only supported on newer generations (with Plane_Control)<br>+ -- Tiling and rotation is only supported on newer generations (with<br>+ -- Plane_Control)<br>+ -- 90 degree rotations are only supported with Y-tiling<br> return<br>- ((Framebuffer.Width = Pos32 (Port_Cfg.Mode.H_Visible) and<br>- Framebuffer.Height = Pos32 (Port_Cfg.Mode.V_Visible)) or<br>- (Framebuffer.Width <= Config.Maximum_Scalable_Width (Pipe) and<br>- Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and<br>- Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible))) and<br>- (Framebuffer.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or Pipe = Primary)<br>- and<br>- (Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or<br>- (Framebuffer.BPC = 8 and Valid_Stride (Framebuffer) and<br>- (Config.Has_Plane_Control or Framebuffer.Tiling = Linear)));<br>+ ((Rotated_Width (FB) = Port_Cfg.Mode.H_Visible and<br>+ Rotated_Height (FB) = Port_Cfg.Mode.V_Visible) or<br>+ (Rotated_Width (FB) <= Config.Maximum_Scalable_Width (Pipe) and<br>+ Rotated_Width (FB) <= Port_Cfg.Mode.H_Visible and<br>+ Rotated_Height (FB) <= Port_Cfg.Mode.V_Visible)) and<br>+ (FB.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or Pipe = Primary) and<br>+ (FB.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or<br>+ (FB.BPC = 8 and Valid_Stride (FB) and<br>+ (Config.Has_Plane_Control or<br>+ (FB.Tiling = Linear and FB.Rotation = No_Rotation)) and<br>+ (FB.Tiling = Y_Tiled or not Rotation_90 (FB))));<br> end Validate_Config;<br> <br> end HW.GFX.GMA.Config_Helpers;<br>diff --git a/common/hw-gfx-gma-config_helpers.ads b/common/hw-gfx-gma-config_helpers.ads<br>index a9cde2b..e684f22 100644<br>--- a/common/hw-gfx-gma-config_helpers.ads<br>+++ b/common/hw-gfx-gma-config_helpers.ads<br>@@ -40,14 +40,16 @@<br> use type HW.Pos32;<br> pragma Warnings (GNAT, On, """Integer_32"" is already use-visible *");<br> function Validate_Config<br>- (Framebuffer : Framebuffer_Type;<br>- Port_Cfg : Port_Config;<br>- Pipe : Pipe_Index)<br>+ (FB : Framebuffer_Type;<br>+ Port_Cfg : Port_Config;<br>+ Pipe : Pipe_Index)<br> return Boolean<br> with<br> Post =><br> (if Validate_Config'Result then<br>- Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and<br>- Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible));<br>+ Rotated_Width (FB) <= Port_Cfg.Mode.H_Visible and<br>+ Rotated_Height (FB) <= Port_Cfg.Mode.V_Visible and<br>+ (FB.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or<br>+ FB.Height <= FB.V_Stride));<br> <br> end HW.GFX.GMA.Config_Helpers;<br>diff --git a/common/hw-gfx-gma-pipe_setup.adb b/common/hw-gfx-gma-pipe_setup.adb<br>index 215b4de..e1ff835 100644<br>--- a/common/hw-gfx-gma-pipe_setup.adb<br>+++ b/common/hw-gfx-gma-pipe_setup.adb<br>@@ -50,6 +50,13 @@<br> X_Tiled => PLANE_CTL_TILED_SURFACE_X_TILED,<br> Y_Tiled => PLANE_CTL_TILED_SURFACE_Y_TILED);<br> <br>+ PLANE_CTL_PLANE_ROTATION_MASK : constant := 3 * 2 ** 0;<br>+ PLANE_CTL_PLANE_ROTATION : constant array (Rotation_Type) of Word32 :=<br>+ (No_Rotation => 0 * 2 ** 0,<br>+ Rotated_90 => 1 * 2 ** 0,<br>+ Rotated_180 => 2 * 2 ** 0,<br>+ Rotated_270 => 3 * 2 ** 0);<br>+<br> PLANE_WM_ENABLE : constant := 1 * 2 ** 31;<br> PLANE_WM_LINES_SHIFT : constant := 14;<br> PLANE_WM_LINES_MASK : constant := 16#001f# * 2 ** 14;<br>@@ -149,7 +156,8 @@<br> =>+<br> (Registers.Register_State,<br> Controller,<br>- FB))<br>+ FB)),<br>+ Pre => FB.Height <= FB.V_Stride<br> is<br> -- FIXME: setup correct format, based on framebuffer RGB format<br> Format : constant Word32 := 6 * 2 ** 26;<br>@@ -158,20 +166,34 @@<br> pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));<br> <br> if Config.Has_Plane_Control then<br>- Registers.Write<br>- (Register => Controller.PLANE_CTL,<br>- Value => PLANE_CTL_PLANE_ENABLE or<br>- PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or<br>- PLANE_CTL_PLANE_GAMMA_DISABLE or<br>- PLANE_CTL_TILED_SURFACE (FB.Tiling));<br>- Registers.Write (Controller.PLANE_OFFSET, 16#0000_0000#);<br>- Registers.Write<br>- (Controller.PLANE_SIZE,<br>- Encode (Pos16 (FB.Width), Pos16 (FB.Height)));<br>- Registers.Write<br>- (Controller.PLANE_STRIDE, Word32 (FB_Pitch (FB.Stride, FB)));<br>- Registers.Write (Controller.PLANE_POS, 16#0000_0000#);<br>- Registers.Write (Controller.PLANE_SURF, FB.Offset and 16#ffff_f000#);<br>+ declare<br>+ Stride, Offset, GTT_Addr : Word32;<br>+ Width : constant Pos16 := Rotated_Width (FB);<br>+ Height : constant Pos16 := Rotated_Height (FB);<br>+ begin<br>+ if Rotation_90 (FB) then<br>+ Stride := Word32 (FB_Pitch (FB.V_Stride, FB));<br>+ Offset := Word32 (FB.V_Stride - FB.Height);<br>+ GTT_Addr :=<br>+ FB.Offset + Word32 (GTT_Rotation_Offset) * GTT_Page_Size;<br>+ else<br>+ Stride := Word32 (FB_Pitch (FB.Stride, FB));<br>+ Offset := 0;<br>+ GTT_Addr := FB.Offset;<br>+ end if;<br>+ Registers.Write<br>+ (Register => Controller.PLANE_CTL,<br>+ Value => PLANE_CTL_PLANE_ENABLE or<br>+ PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or<br>+ PLANE_CTL_PLANE_GAMMA_DISABLE or<br>+ PLANE_CTL_TILED_SURFACE (FB.Tiling) or<br>+ PLANE_CTL_PLANE_ROTATION (FB.Rotation));<br>+ Registers.Write (Controller.PLANE_OFFSET, Offset);<br>+ Registers.Write (Controller.PLANE_SIZE, Encode (Width, Height));<br>+ Registers.Write (Controller.PLANE_STRIDE, Stride);<br>+ Registers.Write (Controller.PLANE_POS, 16#0000_0000#);<br>+ Registers.Write (Controller.PLANE_SURF, GTT_Addr and 16#ffff_f000#);<br>+ end;<br> else<br> if Config.Disable_Trickle_Feed then<br> PRI := PRI or DSPCNTR_DISABLE_TRICKLE_FEED;<br>@@ -210,7 +232,10 @@<br> Dither),<br> Port_IO.State<br> =>+<br>- (Framebuffer))<br>+ (Framebuffer)),<br>+ Pre =><br>+ Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or<br>+ Framebuffer.Height <= Framebuffer.V_Stride<br> is<br> use type Word8;<br> <br>@@ -252,7 +277,7 @@<br> Registers.Write<br> (Register => Controller.PIPESRC,<br> Value => Encode<br>- (Pos16 (Framebuffer.Height), Pos16 (Framebuffer.Width)));<br>+ (Rotated_Height (Framebuffer), Rotated_Width (Framebuffer)));<br> <br> if Config.Has_Pipeconf_Misc then<br> Registers.Write<br>@@ -273,19 +298,21 @@<br> Pre =><br> Max_Width <= Pos32 (Pos16'Last) and<br> Max_Height <= Pos32 (Pos16'Last) and<br>- Framebuffer.Width <= Max_Width and<br>- Framebuffer.Height <= Max_Height,<br>+ Pos32 (Rotated_Width (Framebuffer)) <= Max_Width and<br>+ Pos32 (Rotated_Height (Framebuffer)) <= Max_Height,<br> Post =><br> Width <= Max_Width and Height <= Max_Height<br> is<br>+ Src_Width : constant Pos32 := Pos32 (Rotated_Width (Framebuffer));<br>+ Src_Height : constant Pos32 := Pos32 (Rotated_Height (Framebuffer));<br> begin<br>- if (Max_Width * Framebuffer.Height) / Framebuffer.Width <= Max_Height then<br>+ if (Max_Width * Src_Height) / Src_Width <= Max_Height then<br> Width := Max_Width;<br>- Height := (Max_Width * Framebuffer.Height) / Framebuffer.Width;<br>+ Height := (Max_Width * Src_Height) / Src_Width;<br> else<br> Height := Max_Height;<br> Width := Pos32'Min (Max_Width, -- could prove, it's <= Max_Width<br>- (Max_Height * Framebuffer.Width) / Framebuffer.Height);<br>+ (Max_Height * Src_Width) / Src_Height);<br> end if;<br> end Scale_Keep_Aspect;<br> <br>@@ -295,8 +322,8 @@<br> Framebuffer : in HW.GFX.Framebuffer_Type)<br> with<br> Pre =><br>- Framebuffer.Width <= Pos32 (Mode.H_Visible) and<br>- Framebuffer.Height <= Pos32 (Mode.V_Visible)<br>+ Rotated_Width (Framebuffer) <= Mode.H_Visible and<br>+ Rotated_Height (Framebuffer) <= Mode.V_Visible<br> is<br> use type Registers.Registers_Invalid_Index;<br> <br>@@ -305,14 +332,17 @@<br> (if Controller.PS_CTRL_2 /= Registers.Invalid_Register then<br> PS_CTRL_SCALER_MODE_7X5_EXTENDED else 0);<br> <br>+ Width_In : constant Pos32 := Pos32 (Rotated_Width (Framebuffer));<br>+ Height_In : constant Pos32 := Pos32 (Rotated_Height (Framebuffer));<br>+<br> -- We can scale up to 2.99x horizontally:<br>- Horizontal_Limit : constant Pos32 := ((Framebuffer.Width * 299) / 100);<br>+ Horizontal_Limit : constant Pos32 := (Width_In * 299) / 100;<br> -- The third scaler is limited to 1.99x<br> -- vertical scaling for source widths > 2048:<br> Vertical_Limit : constant Pos32 :=<br>- (Framebuffer.Height *<br>+ (Height_In *<br> (if Controller.PS_CTRL_2 = Registers.Invalid_Register and<br>- Framebuffer.Width > 2048<br>+ Width_In > 2048<br> then<br> 199<br> else<br>@@ -348,8 +378,8 @@<br> Framebuffer : in HW.GFX.Framebuffer_Type)<br> with<br> Pre =><br>- Framebuffer.Width <= Pos32 (Mode.H_Visible) and<br>- Framebuffer.Height <= Pos32 (Mode.V_Visible)<br>+ Rotated_Width (Framebuffer) <= Mode.H_Visible and<br>+ Rotated_Height (Framebuffer) <= Mode.V_Visible<br> is<br> -- Force 1:1 mapping of panel fitter:pipe<br> PF_Ctrl_Pipe_Sel : constant Word32 :=<br>@@ -390,12 +420,12 @@<br> Framebuffer : in HW.GFX.Framebuffer_Type)<br> with<br> Pre =><br>- Framebuffer.Width <= Pos32 (Mode.H_Visible) and<br>- Framebuffer.Height <= Pos32 (Mode.V_Visible)<br>+ Rotated_Width (Framebuffer) <= Mode.H_Visible and<br>+ Rotated_Height (Framebuffer) <= Mode.V_Visible<br> is<br> begin<br>- if Framebuffer.Width /= Pos32 (Mode.H_Visible) or<br>- Framebuffer.Height /= Pos32 (Mode.V_Visible)<br>+ if Rotated_Width (Framebuffer) /= Mode.H_Visible or<br>+ Rotated_Height (Framebuffer) /= Mode.V_Visible<br> then<br> if Config.Has_Plane_Control then<br> Setup_Skylake_Pipe_Scaler (Controller, Mode, Framebuffer);<br>diff --git a/common/hw-gfx-gma-pipe_setup.ads b/common/hw-gfx-gma-pipe_setup.ads<br>index 725bc08..35d9e87 100644<br>--- a/common/hw-gfx-gma-pipe_setup.ads<br>+++ b/common/hw-gfx-gma-pipe_setup.ads<br>@@ -25,8 +25,10 @@<br> Framebuffer : Framebuffer_Type)<br> with<br> Pre =><br>- Framebuffer.Width <= Pos32 (Port_Cfg.Mode.H_Visible) and<br>- Framebuffer.Height <= Pos32 (Port_Cfg.Mode.V_Visible);<br>+ Rotated_Width (Framebuffer) <= Port_Cfg.Mode.H_Visible and<br>+ Rotated_Height (Framebuffer) <= Port_Cfg.Mode.V_Visible and<br>+ (Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or<br>+ Framebuffer.Height <= Framebuffer.V_Stride);<br> <br> procedure Off (Pipe : Pipe_Index);<br> <br>diff --git a/common/hw-gfx-gma.adb b/common/hw-gfx-gma.adb<br>index 76b271d..d6cd2c0 100644<br>--- a/common/hw-gfx-gma.adb<br>+++ b/common/hw-gfx-gma.adb<br>@@ -464,7 +464,7 @@<br> <br> -- Check basics and that it fits in GTT<br> function Valid_FB (FB : Framebuffer_Type) return Boolean is<br>- (Valid_Stride (FB) and FB_Last_Page (FB) <= GTT_Range'Last);<br>+ (Valid_Stride (FB) and FB_Last_Page (FB) < GTT_Rotation_Offset);<br> <br> -- Also check that we don't overflow the GTT's 39-bit space<br> -- (always true with a 32-bit base)<br>@@ -499,6 +499,30 @@<br> Valid => True);<br> Phys_Addr := Phys_Addr + GTT_Page_Size;<br> end loop;<br>+<br>+ if Rotation_90 (FB) and FB.Tiling = Y_Tiled and FB.V_Stride >= 32 then<br>+ declare<br>+ V_Pages : constant Natural := Natural (FB.V_Stride) / 32;<br>+ Bytes_Per_Row : constant GTT_Address_Type :=<br>+ GTT_Address_Type (Pixel_To_Bytes (32 * FB.Stride, FB));<br>+ begin<br>+ Phys_Addr := GTT_Address_Type (Phys_Base) +<br>+ GTT_Address_Type (FB.Offset) +<br>+ GTT_Address_Type (FB_Size (FB));<br>+ for Page in FB_First_Page (FB) .. FB_Last_Page (FB) loop<br>+ Phys_Addr := Phys_Addr - Bytes_Per_Row;<br>+ Registers.Write_GTT<br>+ (GTT_Page => GTT_Rotation_Offset + Page,<br>+ Device_Address => Phys_Addr,<br>+ Valid => True);<br>+<br>+ if (Page - FB_First_Page (FB) + 1) mod V_Pages = 0 then<br>+ Phys_Addr := Phys_Addr + GTT_Page_Size +<br>+ GTT_Address_Type (V_Pages) * Bytes_Per_Row;<br>+ end if;<br>+ end loop;<br>+ end;<br>+ end if;<br> end Setup_Default_GTT;<br> <br> ----------------------------------------------------------------------------<br>diff --git a/common/hw-gfx-gma.ads b/common/hw-gfx-gma.ads<br>index 9943e44..50a76a0 100644<br>--- a/common/hw-gfx-gma.ads<br>+++ b/common/hw-gfx-gma.ads<br>@@ -95,6 +95,8 @@<br> GTT_Page_Size : constant := 4096;<br> type GTT_Address_Type is mod 2 ** 39;<br> subtype GTT_Range is Natural range 0 .. 16#8_0000# - 1;<br>+ GTT_Rotation_Offset : constant GTT_Range := GTT_Range'Last / 2 + 1;<br>+<br> procedure Write_GTT<br> (GTT_Page : GTT_Range;<br> Device_Address : GTT_Address_Type;<br>@@ -161,6 +163,8 @@<br> <br> Tile_Width : constant array (Tiling_Type) of Pos32 :=<br> (Linear => 16, X_Tiled => 128, Y_Tiled => 32);<br>+ Tile_Rows : constant array (Tiling_Type) of Pos32 :=<br>+ (Linear => 1, X_Tiled => 8, Y_Tiled => 32);<br> <br> function FB_Pitch (Px : Pixel_Type; FB : Framebuffer_Type) return Natural is<br> (Natural (Div_Round_Up<br>@@ -168,6 +172,8 @@<br> <br> function Valid_Stride (FB : Framebuffer_Type) return Boolean is<br> (FB.Width <= FB.Stride and<br>- Pixel_To_Bytes (FB.Stride, FB) mod (Tile_Width (FB.Tiling) * 4) = 0);<br>+ Pixel_To_Bytes (FB.Stride, FB) mod (Tile_Width (FB.Tiling) * 4) = 0 and<br>+ FB.Height <= FB.V_Stride and<br>+ FB.V_Stride mod Tile_Rows (FB.Tiling) = 0);<br> <br> end HW.GFX.GMA;<br>diff --git a/common/hw-gfx.ads b/common/hw-gfx.ads<br>index 5594b18..5d8ae59 100644<br>--- a/common/hw-gfx.ads<br>+++ b/common/hw-gfx.ads<br>@@ -47,6 +47,14 @@<br> Offset : Word32;<br> end record;<br> <br>+ function Rotation_90 (FB : Framebuffer_Type) return Boolean is<br>+ (FB.Rotation = Rotated_90 or FB.Rotation = Rotated_270);<br>+<br>+ function Rotated_Width (FB : Framebuffer_Type) return Pos16 is<br>+ (if Rotation_90 (FB) then Pos16 (FB.Height) else Pos16 (FB.Width));<br>+ function Rotated_Height (FB : Framebuffer_Type) return Pos16 is<br>+ (if Rotation_90 (FB) then Pos16 (FB.Width) else Pos16 (FB.Height));<br>+<br> function Pixel_To_Bytes (Pixel : Pixel_Type; FB : Framebuffer_Type)<br> return Pos32 is (Pixel * Pos32 (FB.BPC) / (8 / 4));<br> function FB_Size (FB : Framebuffer_Type) return Pos32 is<br></pre><p>To view, visit <a href="https://review.coreboot.org/22711">change 22711</a>. To unsubscribe, visit <a href="https://review.coreboot.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://review.coreboot.org/22711"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: libgfxinit </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I1c901b7abc0fe7764bee87f6fda58ba9fa3f340d </div>
<div style="display:none"> Gerrit-Change-Number: 22711 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Nico Huber <nico.h@gmx.de> </div>