[coreboot-gerrit] Change in libgfxinit[master]: gma: Add support for rotated framebuffers

Nico Huber (Code Review) gerrit at coreboot.org
Tue Dec 5 13:05:29 CET 2017


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

-- 
To view, visit https://review.coreboot.org/22711
To unsubscribe, visit https://review.coreboot.org/settings

Gerrit-Project: libgfxinit
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I1c901b7abc0fe7764bee87f6fda58ba9fa3f340d
Gerrit-Change-Number: 22711
Gerrit-PatchSet: 1
Gerrit-Owner: Nico Huber <nico.h at gmx.de>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20171205/9f89b145/attachment-0001.html>


More information about the coreboot-gerrit mailing list