Add linux user-space app `gfx_test`

This simple program scans all ports and configures pipes for the first
three available displays. It presumes that there is enough framebuffer
mapped for all pipes and fills it with test images.

The only command line parameter ist the path to a PCI-device node in
sysfs. On exit, the hardware is left in the configured state. So the
user has to make sure, that he either can work without the gfx hard-
ware or has another driver to restore a working state.

Change-Id: I2144300589e113e711db7959aa68fa96c3844568
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/18786
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Tested-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
Nico Huber 2017-03-05 14:14:09 +01:00 committed by Stefan Reinauer
parent 3586101e0b
commit 1d0abe468b
7 changed files with 244 additions and 0 deletions

View File

@ -1,6 +1,16 @@
name := gfxinit
ifeq ($(MAKECMDGOALS),gfx_test)
prefixed-name := gfx_test
link-type := program
GFXINIT_TEST := y
endif
gfxinit-deplibs := libhw
libhw-dir ?= ../libhwbase/dest
include $(libhw-dir)/Makefile
gfx_test: $(binary)
.PHONY: gfx_test

View File

@ -1 +1,3 @@
subdirs-y += common
subdirs-$(GFXINIT_TEST) += gfxtest

2
TODO
View File

@ -5,3 +5,5 @@ unknown DP honor SINK_STATUS after training
low LVDS 8bit colors, data format???
medium SKL check if DPLL_CTRL2 really defaults to `Clock Off` => 0
medium gfxtest take care of our own framebuffer mapping

4
gfxtest/Makefile.inc Normal file
View File

@ -0,0 +1,4 @@
gfxinit-y += gfx_test.adb
gfxinit-y += gfx_test.ads
gfxinit-main-y = gfx_test_main.adb

215
gfxtest/gfx_test.adb Normal file
View File

@ -0,0 +1,215 @@
with System.Storage_Elements;
with Ada.Command_Line;
with Interfaces.C;
with HW.File;
with HW.Debug;
with HW.GFX.GMA;
with HW.GFX.GMA.Display_Probing;
use HW;
use HW.GFX;
package body GFX_Test is
MMIO_Size : constant := 2 * 1024 * 1024;
subtype MMIO_Range is Natural range 0 .. MMIO_Size - 1;
subtype MMIO_Buffer is Buffer (MMIO_Range);
MMIO_Dummy : MMIO_Buffer
with
Alignment => 16#1000#,
Volatile;
type Pixel_Type is record
Red : Byte;
Green : Byte;
Blue : Byte;
Alpha : Byte;
end record;
for Pixel_Type use record
Blue at 0 range 0 .. 7;
Green at 1 range 0 .. 7;
Red at 2 range 0 .. 7;
Alpha at 3 range 0 .. 7;
end record;
Max_W : constant := 4096;
Max_H : constant := 2160;
FB_Align : constant := 16#0004_0000#;
type Screen_Type is
array (0 .. 3 * (Max_W * Max_H + FB_Align / 4) - 1) of Pixel_Type;
Screen : Screen_Type
with
Alignment => 16#1000#,
Volatile;
Pipes : GMA.Pipe_Configs;
function Fill
(X, Y : Natural;
Framebuffer : Framebuffer_Type;
Pipe : GMA.Pipe_Index)
return Pixel_Type
is
use type HW.Byte;
Xp : constant Natural := X * 256 / Natural (Framebuffer.Width);
Yp : constant Natural := Y * 256 / Natural (Framebuffer.Height);
Xn : constant Natural := 255 - Xp;
Yn : constant Natural := 255 - Yp;
function Map (X, Y : Natural) return Byte is
begin
return Byte (X * Y / 255);
end Map;
begin
return
(case Pipe is
when GMA.Primary => (Map (Xn, Yn), Map (Xp, Yn), Map (Xp, Yp), 255),
when GMA.Secondary => (Map (Xn, Yp), Map (Xn, Yn), Map (Xp, Yn), 255),
when GMA.Tertiary => (Map (Xp, Yp), Map (Xn, Yp), Map (Xn, Yn), 255));
end Fill;
procedure Test_Screen
(Framebuffer : Framebuffer_Type;
Pipe : GMA.Pipe_Index)
is
use type HW.Word32;
P : Pixel_Type;
-- We have pixel offset wheras the framebuffer has a byte offset
Offset_Y : Natural := Natural (Framebuffer.Offset / 4);
Offset : Natural;
begin
for Y in 0 .. Natural (Framebuffer.Height) - 1 loop
Offset := Offset_Y;
for X in 0 .. Natural (Framebuffer.Width) - 1 loop
if Y mod 16 = 0 or X mod 16 = 0 then
P := (0, 0, 0, 0);
else
P := Fill (X, Y, Framebuffer, Pipe);
end if;
Screen (Offset) := P;
Offset := Offset + 1;
end loop;
Offset_Y := Offset_Y + Natural (Framebuffer.Stride);
end loop;
end Test_Screen;
procedure Calc_Framebuffer
(FB : out Framebuffer_Type;
Mode : in Mode_Type;
Offset : in out Word32)
is
use type HW.Int32;
use type HW.Word32;
begin
Offset := (Offset + FB_Align - 1) and not (FB_Align - 1);
FB :=
(Width => Width_Type (Mode.H_Visible),
Height => Height_Type (Mode.V_Visible),
BPC => 8,
Stride => Width_Type ((Word32 (Mode.H_Visible) + 15) and not 15),
Offset => Offset);
Offset := Offset + Word32 (FB.Stride * FB.Height * 4);
end Calc_Framebuffer;
procedure Prepare_Configs
is
use type HW.GFX.GMA.Port_Type;
Offset : HW.Word32 := 0;
begin
GMA.Display_Probing.Scan_Ports (Pipes);
for Pipe in GMA.Pipe_Index loop
if Pipes (Pipe).Port /= GMA.Disabled then
Calc_Framebuffer
(FB => Pipes (Pipe).Framebuffer,
Mode => Pipes (Pipe).Mode,
Offset => Offset);
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 & " <sysfs-pci-path>");
Debug.New_Line;
end Print_Usage;
procedure Main
is
use System.Storage_Elements;
use type HW.GFX.GMA.Port_Type;
use type Interfaces.C.int;
MMIO_Mapped,
Screen_Mapped,
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;
if iopl (3) /= 0 then
Debug.Put_Line ("Failed to change i/o privilege level.");
return;
end if;
File.Map
(Path => Ada.Command_Line.Argument (1) & "/resource0",
Addr => Word64 (To_Integer (MMIO_Dummy'Address)),
Len => MMIO_Dummy'Size / 8,
Readable => True,
Writable => True,
Success => MMIO_Mapped);
if not MMIO_Mapped then
Debug.Put_Line
("Failed to map '" & Ada.Command_Line.Argument (1) & "/resource0'.");
return;
end if;
File.Map
(Path => Ada.Command_Line.Argument (1) & "/resource2",
Addr => Word64 (To_Integer (Screen'Address)),
Len => Screen'Size / 8,
Readable => True,
Writable => True,
Success => Screen_Mapped);
if not Screen_Mapped then
Debug.Put_Line
("Failed to map '" & Ada.Command_Line.Argument (1) & "/resource2'.");
return;
end if;
GMA.Initialize
(MMIO_Base => Word64 (To_Integer (MMIO_Dummy'Address)),
Clean_State => True,
Success => Initialized);
if Initialized then
Prepare_Configs;
GMA.Update_Outputs (Pipes);
for Pipe in GMA.Pipe_Index loop
if Pipes (Pipe).Port /= GMA.Disabled then
Test_Screen
(Framebuffer => Pipes (Pipe).Framebuffer,
Pipe => Pipe);
end if;
end loop;
end if;
end Main;
end GFX_Test;

5
gfxtest/gfx_test.ads Normal file
View File

@ -0,0 +1,5 @@
package GFX_Test is
procedure Main;
end GFX_Test;

View File

@ -0,0 +1,6 @@
with GFX_Test;
procedure GFX_Test_Main is
begin
GFX_Test.Main;
end GFX_Test_Main;