<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>