blob: 9a5ce0a5bf3da04ce98074165d564414997c3b15 [file] [log] [blame]
Nico Huberfda2d6e2017-07-09 16:47:52 +02001with Ada.Unchecked_Conversion;
Nico Huber1d0abe42017-03-05 14:14:09 +01002with Ada.Command_Line;
3with Interfaces.C;
4
Nico Huber3b654a02017-07-15 22:27:14 +02005with HW.Time;
Nico Huber1d0abe42017-03-05 14:14:09 +01006with HW.Debug;
Nico Huberfda2d6e2017-07-09 16:47:52 +02007with HW.PCI.Dev;
8with HW.MMIO_Range;
Nico Huber1d0abe42017-03-05 14:14:09 +01009with HW.GFX.GMA;
Nico Huber3b654a02017-07-15 22:27:14 +020010with HW.GFX.GMA.Config;
Nico Huber1d0abe42017-03-05 14:14:09 +010011with HW.GFX.GMA.Display_Probing;
12
Nico Huberfda2d6e2017-07-09 16:47:52 +020013package body HW.GFX.GMA.GFX_Test
14is
15 pragma Disable_Atomic_Synchronization;
Nico Huber1d0abe42017-03-05 14:14:09 +010016
Nico Huberfda2d6e2017-07-09 16:47:52 +020017 package Dev is new PCI.Dev (PCI.Address'(0, 2, 0));
Nico Huber1d0abe42017-03-05 14:14:09 +010018
Nico Huber3b654a02017-07-15 22:27:14 +020019 type GTT_PTE_Type is mod 2 ** (Config.GTT_PTE_Size * 8);
20 type GTT_Registers_Type is array (GTT_Range) of GTT_PTE_Type;
21 package GTT is new MMIO_Range
22 (Base_Addr => 0,
23 Element_T => GTT_PTE_Type,
24 Index_T => GTT_Range,
25 Array_T => GTT_Registers_Type);
26
27 GTT_Backup : GTT_Registers_Type;
28
29 procedure Backup_GTT
30 is
31 begin
32 for Idx in GTT_Range loop
33 GTT.Read (GTT_Backup (Idx), Idx);
34 end loop;
35 end Backup_GTT;
36
37 procedure Restore_GTT
38 is
39 begin
40 for Idx in GTT_Range loop
41 GTT.Write (Idx, GTT_Backup (Idx));
42 end loop;
43 end Restore_GTT;
44
Nico Huber1d0abe42017-03-05 14:14:09 +010045 type Pixel_Type is record
46 Red : Byte;
47 Green : Byte;
48 Blue : Byte;
49 Alpha : Byte;
50 end record;
51
52 for Pixel_Type use record
53 Blue at 0 range 0 .. 7;
54 Green at 1 range 0 .. 7;
55 Red at 2 range 0 .. 7;
56 Alpha at 3 range 0 .. 7;
57 end record;
58
Nico Huberfda2d6e2017-07-09 16:47:52 +020059 function Pixel_To_Word (P : Pixel_Type) return Word32
60 with
61 SPARK_Mode => Off
62 is
63 function To_Word is new Ada.Unchecked_Conversion (Pixel_Type, Word32);
64 begin
65 return To_Word (P);
66 end Pixel_To_Word;
67
Nico Huber1d0abe42017-03-05 14:14:09 +010068 Max_W : constant := 4096;
69 Max_H : constant := 2160;
70 FB_Align : constant := 16#0004_0000#;
Nico Huberfda2d6e2017-07-09 16:47:52 +020071 subtype Screen_Index is Natural range
72 0 .. 3 * (Max_W * Max_H + FB_Align / 4) - 1;
73 type Screen_Type is array (Screen_Index) of Word32;
Nico Huber1d0abe42017-03-05 14:14:09 +010074
Nico Huberfda2d6e2017-07-09 16:47:52 +020075 package Screen is new MMIO_Range (0, Word32, Screen_Index, Screen_Type);
Nico Huber1d0abe42017-03-05 14:14:09 +010076
Nico Huber3b654a02017-07-15 22:27:14 +020077 Screen_Backup : Screen_Type;
78
79 procedure Backup_Screen (FB : Framebuffer_Type)
80 is
81 First : constant Screen_Index := Natural (FB.Offset) / 4;
82 Last : constant Screen_Index := First + Natural (FB_Size (FB)) / 4 - 1;
83 begin
84 for Idx in Screen_Index range First .. Last loop
85 Screen.Read (Screen_Backup (Idx), Idx);
86 end loop;
87 end Backup_Screen;
88
89 procedure Restore_Screen (FB : Framebuffer_Type)
90 is
91 First : constant Screen_Index := Natural (FB.Offset) / 4;
92 Last : constant Screen_Index := First + Natural (FB_Size (FB)) / 4 - 1;
93 begin
94 for Idx in Screen_Index range First .. Last loop
95 Screen.Write (Idx, Screen_Backup (Idx));
96 end loop;
97 end Restore_Screen;
Nico Huber1d0abe42017-03-05 14:14:09 +010098
99 function Fill
100 (X, Y : Natural;
101 Framebuffer : Framebuffer_Type;
102 Pipe : GMA.Pipe_Index)
103 return Pixel_Type
104 is
105 use type HW.Byte;
106
107 Xp : constant Natural := X * 256 / Natural (Framebuffer.Width);
108 Yp : constant Natural := Y * 256 / Natural (Framebuffer.Height);
109 Xn : constant Natural := 255 - Xp;
110 Yn : constant Natural := 255 - Yp;
111
112 function Map (X, Y : Natural) return Byte is
113 begin
114 return Byte (X * Y / 255);
115 end Map;
116 begin
117 return
118 (case Pipe is
119 when GMA.Primary => (Map (Xn, Yn), Map (Xp, Yn), Map (Xp, Yp), 255),
120 when GMA.Secondary => (Map (Xn, Yp), Map (Xn, Yn), Map (Xp, Yn), 255),
121 when GMA.Tertiary => (Map (Xp, Yp), Map (Xn, Yp), Map (Xn, Yn), 255));
122 end Fill;
123
124 procedure Test_Screen
125 (Framebuffer : Framebuffer_Type;
126 Pipe : GMA.Pipe_Index)
127 is
Nico Huber1d0abe42017-03-05 14:14:09 +0100128 P : Pixel_Type;
129 -- We have pixel offset wheras the framebuffer has a byte offset
130 Offset_Y : Natural := Natural (Framebuffer.Offset / 4);
131 Offset : Natural;
132 begin
133 for Y in 0 .. Natural (Framebuffer.Height) - 1 loop
134 Offset := Offset_Y;
135 for X in 0 .. Natural (Framebuffer.Width) - 1 loop
136 if Y mod 16 = 0 or X mod 16 = 0 then
137 P := (0, 0, 0, 0);
138 else
139 P := Fill (X, Y, Framebuffer, Pipe);
140 end if;
Nico Huberfda2d6e2017-07-09 16:47:52 +0200141 Screen.Write (Offset, Pixel_To_Word (P));
Nico Huber1d0abe42017-03-05 14:14:09 +0100142 Offset := Offset + 1;
143 end loop;
144 Offset_Y := Offset_Y + Natural (Framebuffer.Stride);
145 end loop;
146 end Test_Screen;
147
148 procedure Calc_Framebuffer
149 (FB : out Framebuffer_Type;
150 Mode : in Mode_Type;
151 Offset : in out Word32)
152 is
Nico Huber1d0abe42017-03-05 14:14:09 +0100153 begin
154 Offset := (Offset + FB_Align - 1) and not (FB_Align - 1);
155 FB :=
156 (Width => Width_Type (Mode.H_Visible),
157 Height => Height_Type (Mode.V_Visible),
158 BPC => 8,
159 Stride => Width_Type ((Word32 (Mode.H_Visible) + 15) and not 15),
Nico Huberb7470492017-11-30 14:48:35 +0100160 V_Stride => Height_Type (Mode.V_Visible),
Nico Huber51375ad2017-08-24 14:44:06 +0200161 Tiling => Linear,
Nico Huberb7470492017-11-30 14:48:35 +0100162 Rotation => No_Rotation,
Nico Huber1d0abe42017-03-05 14:14:09 +0100163 Offset => Offset);
Nico Huberb7470492017-11-30 14:48:35 +0100164 Offset := Offset + Word32 (FB_Size (FB));
Nico Huber1d0abe42017-03-05 14:14:09 +0100165 end Calc_Framebuffer;
166
Nico Huber3b654a02017-07-15 22:27:14 +0200167 Pipes : GMA.Pipe_Configs;
168
Nico Huber1d0abe42017-03-05 14:14:09 +0100169 procedure Prepare_Configs
170 is
171 use type HW.GFX.GMA.Port_Type;
172
Nico Huberfda2d6e2017-07-09 16:47:52 +0200173 Offset : Word32 := 0;
Nico Huber3b654a02017-07-15 22:27:14 +0200174 Success : Boolean;
Nico Huber1d0abe42017-03-05 14:14:09 +0100175 begin
176 GMA.Display_Probing.Scan_Ports (Pipes);
177
178 for Pipe in GMA.Pipe_Index loop
179 if Pipes (Pipe).Port /= GMA.Disabled then
180 Calc_Framebuffer
181 (FB => Pipes (Pipe).Framebuffer,
182 Mode => Pipes (Pipe).Mode,
183 Offset => Offset);
Nico Huber3b654a02017-07-15 22:27:14 +0200184 GMA.Setup_Default_FB
185 (FB => Pipes (Pipe).Framebuffer,
186 Clear => False,
187 Success => Success);
188 if not Success then
189 Pipes (Pipe).Port := GMA.Disabled;
190 end if;
Nico Huber1d0abe42017-03-05 14:14:09 +0100191 end if;
192 end loop;
193
194 GMA.Dump_Configs (Pipes);
195 end Prepare_Configs;
196
Nico Huber3b654a02017-07-15 22:27:14 +0200197 procedure Print_Usage
198 is
199 begin
200 Debug.Put_Line
201 ("Usage: " & Ada.Command_Line.Command_Name & " <delay seconds>");
202 Debug.New_Line;
203 end Print_Usage;
204
Nico Huber1d0abe42017-03-05 14:14:09 +0100205 procedure Main
206 is
Nico Huber1d0abe42017-03-05 14:14:09 +0100207 use type HW.GFX.GMA.Port_Type;
Nico Huberfda2d6e2017-07-09 16:47:52 +0200208 use type HW.Word64;
Nico Huber1d0abe42017-03-05 14:14:09 +0100209 use type Interfaces.C.int;
210
Nico Huberfda2d6e2017-07-09 16:47:52 +0200211 Res_Addr : Word64;
212
Nico Huber3b654a02017-07-15 22:27:14 +0200213 Delay_S : Natural;
214
Nico Huberfda2d6e2017-07-09 16:47:52 +0200215 Dev_Init,
Nico Huber1d0abe42017-03-05 14:14:09 +0100216 Initialized : Boolean;
217
218 function iopl (level : Interfaces.C.int) return Interfaces.C.int;
219 pragma Import (C, iopl, "iopl");
220 begin
Nico Huber3b654a02017-07-15 22:27:14 +0200221 if Ada.Command_Line.Argument_Count /= 1 then
222 Print_Usage;
223 return;
224 end if;
225
226 Delay_S := Natural'Value (Ada.Command_Line.Argument (1));
227
Nico Huber1d0abe42017-03-05 14:14:09 +0100228 if iopl (3) /= 0 then
229 Debug.Put_Line ("Failed to change i/o privilege level.");
230 return;
231 end if;
232
Nico Huberfda2d6e2017-07-09 16:47:52 +0200233 Dev.Initialize (Dev_Init);
234 if not Dev_Init then
235 Debug.Put_Line ("Failed to map PCI config.");
Nico Huber1d0abe42017-03-05 14:14:09 +0100236 return;
237 end if;
238
Nico Huber3b654a02017-07-15 22:27:14 +0200239 Dev.Map (Res_Addr, PCI.Res0, Offset => Config.GTT_Offset);
240 if Res_Addr = 0 then
241 Debug.Put_Line ("Failed to map PCI resource0.");
242 return;
243 end if;
244 GTT.Set_Base_Address (Res_Addr);
245
Nico Huberfda2d6e2017-07-09 16:47:52 +0200246 Dev.Map (Res_Addr, PCI.Res2, WC => True);
247 if Res_Addr = 0 then
248 Debug.Put_Line ("Failed to map PCI resource2.");
249 return;
250 end if;
251 Screen.Set_Base_Address (Res_Addr);
252
Nico Huber1d0abe42017-03-05 14:14:09 +0100253 GMA.Initialize
Nico Huber2b6f6992017-07-09 18:11:34 +0200254 (Clean_State => True,
Nico Huber1d0abe42017-03-05 14:14:09 +0100255 Success => Initialized);
256
257 if Initialized then
Nico Huber3b654a02017-07-15 22:27:14 +0200258 Backup_GTT;
259
Nico Huber1d0abe42017-03-05 14:14:09 +0100260 Prepare_Configs;
261
262 GMA.Update_Outputs (Pipes);
263
264 for Pipe in GMA.Pipe_Index loop
265 if Pipes (Pipe).Port /= GMA.Disabled then
Nico Huber3b654a02017-07-15 22:27:14 +0200266 Backup_Screen (Pipes (Pipe).Framebuffer);
Nico Huber1d0abe42017-03-05 14:14:09 +0100267 Test_Screen
268 (Framebuffer => Pipes (Pipe).Framebuffer,
269 Pipe => Pipe);
270 end if;
271 end loop;
Nico Huber3b654a02017-07-15 22:27:14 +0200272
273 Time.M_Delay (Delay_S * 1_000);
274
275 for Pipe in GMA.Pipe_Index loop
276 if Pipes (Pipe).Port /= GMA.Disabled then
277 Restore_Screen (Pipes (Pipe).Framebuffer);
278 end if;
279 end loop;
280 Restore_GTT;
Nico Huber1d0abe42017-03-05 14:14:09 +0100281 end if;
282 end Main;
283
Nico Huberfda2d6e2017-07-09 16:47:52 +0200284end HW.GFX.GMA.GFX_Test;