gfx_test: Set our own framebuffers up, update README
Use GMA.Setup_Default_FB() to allocate framebuffers in the stolen
memory. To help with setups where we can't unload the i915 driver,
back up and restore the current GTT setup and framebuffer contents.
Also add a wrapper script and update the README.
Change-Id: I10790d35d38b7b211f41b2452f6d2baf17372e31
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/20604
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/gfxtest/gfx_test.sh b/gfxtest/gfx_test.sh
new file mode 100755
index 0000000..9df0005
--- /dev/null
+++ b/gfxtest/gfx_test.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+set -e
+
+usage="Usage: $0 [seconds]\n"
+
+err_msgs=
+command -v chvt >/dev/null || err_msgs="${err_msgs}"'Need `chvt`\n'
+command -v openvt >/dev/null || err_msgs="${err_msgs}"'Need `openvt`\n'
+command -v fgconsole >/dev/null || err_msgs="${err_msgs}"'Need `fgconsole`\n'
+[ -n "$err_msgs" ] && err_msgs="${err_msgs}"'e.g. install the `kbd` package\n'
+
+[ -x build/gfx_test ] || \
+ err_msgs="${err_msgs}"'Please run from *libgfxinit* source dir and build `gfx_test` first.\n'
+
+[ "$#" -gt 1 ] && err_msgs="${err_msgs}${usage}"
+
+if [ -n "$err_msgs" ]; then
+ printf "$err_msgs"
+ exit 1
+fi
+
+if [ "$#" -lt 1 ]; then
+ # default duration of 5s
+ set 5
+fi
+
+reload_i915=0
+prepare_vt() {
+ # switch VT, we might be in X
+ orig_vt=`fgconsole`
+ openvt -s -- true
+
+ # poll until the VT switch is done
+ while [ `fgconsole` -eq $orig_vt ]; do :; done
+
+ # take i915 out of charge
+ echo 0 >/sys/devices/virtual/vtconsole/vtcon1/bind
+
+ # try unloading it
+ if lsmod | grep -q i915 && modprobe -r i915 >/dev/null 2>&1; then
+ reload_i915=1
+ fi
+}
+
+restore_vt() {
+ # reload i915
+ if [ $reload_i915 -eq 1 ]; then
+ modprobe i915
+ fi
+
+ # put i915 back in charge
+ echo 1 >/sys/devices/virtual/vtconsole/vtcon1/bind
+
+ # return to original VT
+ chvt $orig_vt
+}
+
+prepare_vt
+
+build/gfx_test "$@" || true
+
+restore_vt
diff --git a/gfxtest/hw-gfx-gma-gfx_test.adb b/gfxtest/hw-gfx-gma-gfx_test.adb
index ad396fd..d870401 100644
--- a/gfxtest/hw-gfx-gma-gfx_test.adb
+++ b/gfxtest/hw-gfx-gma-gfx_test.adb
@@ -2,10 +2,12 @@
with Ada.Command_Line;
with Interfaces.C;
+with HW.Time;
with HW.Debug;
with HW.PCI.Dev;
with HW.MMIO_Range;
with HW.GFX.GMA;
+with HW.GFX.GMA.Config;
with HW.GFX.GMA.Display_Probing;
package body HW.GFX.GMA.GFX_Test
@@ -14,6 +16,32 @@
package Dev is new PCI.Dev (PCI.Address'(0, 2, 0));
+ type GTT_PTE_Type is mod 2 ** (Config.GTT_PTE_Size * 8);
+ type GTT_Registers_Type is array (GTT_Range) of GTT_PTE_Type;
+ package GTT is new MMIO_Range
+ (Base_Addr => 0,
+ Element_T => GTT_PTE_Type,
+ Index_T => GTT_Range,
+ Array_T => GTT_Registers_Type);
+
+ GTT_Backup : GTT_Registers_Type;
+
+ procedure Backup_GTT
+ is
+ begin
+ for Idx in GTT_Range loop
+ GTT.Read (GTT_Backup (Idx), Idx);
+ end loop;
+ end Backup_GTT;
+
+ procedure Restore_GTT
+ is
+ begin
+ for Idx in GTT_Range loop
+ GTT.Write (Idx, GTT_Backup (Idx));
+ end loop;
+ end Restore_GTT;
+
type Pixel_Type is record
Red : Byte;
Green : Byte;
@@ -46,7 +74,27 @@
package Screen is new MMIO_Range (0, Word32, Screen_Index, Screen_Type);
- Pipes : GMA.Pipe_Configs;
+ Screen_Backup : Screen_Type;
+
+ procedure Backup_Screen (FB : Framebuffer_Type)
+ is
+ First : constant Screen_Index := Natural (FB.Offset) / 4;
+ Last : constant Screen_Index := First + Natural (FB_Size (FB)) / 4 - 1;
+ begin
+ for Idx in Screen_Index range First .. Last loop
+ Screen.Read (Screen_Backup (Idx), Idx);
+ end loop;
+ end Backup_Screen;
+
+ procedure Restore_Screen (FB : Framebuffer_Type)
+ is
+ First : constant Screen_Index := Natural (FB.Offset) / 4;
+ Last : constant Screen_Index := First + Natural (FB_Size (FB)) / 4 - 1;
+ begin
+ for Idx in Screen_Index range First .. Last loop
+ Screen.Write (Idx, Screen_Backup (Idx));
+ end loop;
+ end Restore_Screen;
function Fill
(X, Y : Natural;
@@ -113,11 +161,14 @@
Offset := Offset + Word32 (FB.Stride * FB.Height * 4);
end Calc_Framebuffer;
+ Pipes : GMA.Pipe_Configs;
+
procedure Prepare_Configs
is
use type HW.GFX.GMA.Port_Type;
Offset : Word32 := 0;
+ Success : Boolean;
begin
GMA.Display_Probing.Scan_Ports (Pipes);
@@ -127,12 +178,27 @@
(FB => Pipes (Pipe).Framebuffer,
Mode => Pipes (Pipe).Mode,
Offset => Offset);
+ GMA.Setup_Default_FB
+ (FB => Pipes (Pipe).Framebuffer,
+ Clear => False,
+ Success => Success);
+ if not Success then
+ Pipes (Pipe).Port := GMA.Disabled;
+ end if;
end if;
end loop;
GMA.Dump_Configs (Pipes);
end Prepare_Configs;
+ procedure Print_Usage
+ is
+ begin
+ Debug.Put_Line
+ ("Usage: " & Ada.Command_Line.Command_Name & " <delay seconds>");
+ Debug.New_Line;
+ end Print_Usage;
+
procedure Main
is
use type HW.GFX.GMA.Port_Type;
@@ -141,12 +207,21 @@
Res_Addr : Word64;
+ Delay_S : Natural;
+
Dev_Init,
Initialized : Boolean;
function iopl (level : Interfaces.C.int) return Interfaces.C.int;
pragma Import (C, iopl, "iopl");
begin
+ if Ada.Command_Line.Argument_Count /= 1 then
+ Print_Usage;
+ return;
+ end if;
+
+ Delay_S := Natural'Value (Ada.Command_Line.Argument (1));
+
if iopl (3) /= 0 then
Debug.Put_Line ("Failed to change i/o privilege level.");
return;
@@ -158,6 +233,13 @@
return;
end if;
+ Dev.Map (Res_Addr, PCI.Res0, Offset => Config.GTT_Offset);
+ if Res_Addr = 0 then
+ Debug.Put_Line ("Failed to map PCI resource0.");
+ return;
+ end if;
+ GTT.Set_Base_Address (Res_Addr);
+
Dev.Map (Res_Addr, PCI.Res2, WC => True);
if Res_Addr = 0 then
Debug.Put_Line ("Failed to map PCI resource2.");
@@ -170,17 +252,29 @@
Success => Initialized);
if Initialized then
+ Backup_GTT;
+
Prepare_Configs;
GMA.Update_Outputs (Pipes);
for Pipe in GMA.Pipe_Index loop
if Pipes (Pipe).Port /= GMA.Disabled then
+ Backup_Screen (Pipes (Pipe).Framebuffer);
Test_Screen
(Framebuffer => Pipes (Pipe).Framebuffer,
Pipe => Pipe);
end if;
end loop;
+
+ Time.M_Delay (Delay_S * 1_000);
+
+ for Pipe in GMA.Pipe_Index loop
+ if Pipes (Pipe).Port /= GMA.Disabled then
+ Restore_Screen (Pipes (Pipe).Framebuffer);
+ end if;
+ end loop;
+ Restore_GTT;
end if;
end Main;