blob: f9444e8eb84430312ddad0012c116ed82d0ecb3a [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
Nico Huber3d06de82018-05-29 01:35:04 +02002-- Copyright (C) 2015-2018 secunet Security Networks AG
Nico Huber194e57e2017-07-15 21:15:46 +02003-- Copyright (C) 2017 Nico Huber <nico.h@gmx.de>
Nico Huber83693c82016-10-08 22:17:55 +02004--
5-- This program is free software; you can redistribute it and/or modify
6-- it under the terms of the GNU General Public License as published by
Nico Huber125a29e2016-10-18 00:23:54 +02007-- the Free Software Foundation; either version 2 of the License, or
8-- (at your option) any later version.
Nico Huber83693c82016-10-08 22:17:55 +02009--
10-- This program is distributed in the hope that it will be useful,
11-- but WITHOUT ANY WARRANTY; without even the implied warranty of
12-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13-- GNU General Public License for more details.
14--
15
Nico Huber194e57e2017-07-15 21:15:46 +020016with HW.Config;
Nico Huber83693c82016-10-08 22:17:55 +020017with HW.Time;
18with HW.Port_IO;
Nico Hubercf88f3d2018-06-05 13:27:34 +020019with HW.GFX.Framebuffer_Filler;
Nico Huber83693c82016-10-08 22:17:55 +020020
21package HW.GFX.GMA
22with
23 Abstract_State =>
24 (State,
25 Init_State,
26 Config_State,
27 (Device_State with External)),
Nico Huber27088aa2018-06-10 13:28:05 +020028 Initializes => Init_State
Nico Huber83693c82016-10-08 22:17:55 +020029is
30
Nico Hubera02b2c62018-01-09 15:58:34 +010031 GTT_Page_Size : constant := 4096;
32 type GTT_Address_Type is mod 2 ** 39;
33 subtype GTT_Range is Natural range 0 .. 16#8_0000# - 1;
34 GTT_Rotation_Offset : constant GTT_Range := GTT_Range'Last / 2 + 1;
35
Nico Huber6621a142018-06-07 23:56:54 +020036 type Generation is (G45, Ironlake, Haswell, Broxton, Skylake);
37
Nico Huber83693c82016-10-08 22:17:55 +020038 type CPU_Type is
Arthur Heymans73ea0322018-03-28 17:17:07 +020039 (G45,
40 Ironlake,
Nico Huber83693c82016-10-08 22:17:55 +020041 Sandybridge,
42 Ivybridge,
43 Haswell,
44 Broadwell,
Nico Huber21da5742017-01-20 14:00:53 +010045 Broxton,
Nico Huber88badbe2018-09-27 16:36:47 +020046 Skylake,
47 Kabylake);
Nico Huber83693c82016-10-08 22:17:55 +020048
Nico Huber25fdb152019-02-17 15:54:39 +010049 type CPU_Variant is (Normal, ULT, ULX);
Nico Huber83693c82016-10-08 22:17:55 +020050
51 type Port_Type is
52 (Disabled,
53 Internal,
54 DP1,
55 DP2,
56 DP3,
Nico Huber0d454cd2016-11-21 13:33:43 +010057 HDMI1, -- or DVI
58 HDMI2, -- or DVI
59 HDMI3, -- or DVI
Nico Huber83693c82016-10-08 22:17:55 +020060 Analog);
Nico Huber040d9b62019-02-18 00:52:00 +010061 subtype Active_Port_Type is Port_Type
62 range Port_Type'Succ (Disabled) .. Port_Type'Last;
Nico Huber83693c82016-10-08 22:17:55 +020063
Nico Hubera02b2c62018-01-09 15:58:34 +010064 type Cursor_Mode is (No_Cursor, ARGB_Cursor);
65 type Cursor_Size is (Cursor_64x64, Cursor_128x128, Cursor_256x256);
66 Cursor_Width : constant array (Cursor_Size) of Width_Type := (64, 128, 256);
67
68 subtype Cursor_Pos is Int32 range Int32'First / 2 .. Int32'Last / 2;
69
70 type Cursor_Type is record
71 Mode : Cursor_Mode;
72 Size : Cursor_Size;
73 Center_X : Cursor_Pos;
74 Center_Y : Cursor_Pos;
75 GTT_Offset : GTT_Range;
76 end record;
77 Default_Cursor : constant Cursor_Type :=
78 (Mode => No_Cursor,
79 Size => Cursor_Size'First,
80 Center_X => 0,
81 Center_Y => 0,
82 GTT_Offset => 0);
83
Nico Huber99f10f32016-11-20 00:34:05 +010084 type Pipe_Config is record
Nico Huber83693c82016-10-08 22:17:55 +020085 Port : Port_Type;
86 Framebuffer : Framebuffer_Type;
Nico Hubera02b2c62018-01-09 15:58:34 +010087 Cursor : Cursor_Type;
Nico Huber83693c82016-10-08 22:17:55 +020088 Mode : Mode_Type;
89 end record;
Nico Huber99f10f32016-11-20 00:34:05 +010090 type Pipe_Index is (Primary, Secondary, Tertiary);
91 type Pipe_Configs is array (Pipe_Index) of Pipe_Config;
Nico Huber83693c82016-10-08 22:17:55 +020092
Nico Huber3675db52016-11-04 16:27:29 +010093 -- Special framebuffer offset to indicate legacy VGA plane.
94 -- Only valid on primary pipe.
95 VGA_PLANE_FRAMEBUFFER_OFFSET : constant := 16#ffff_ffff#;
96
Nico Huberbebca132017-06-12 23:04:46 +020097 pragma Warnings (GNATprove, Off, "unused variable ""Write_Delay""",
98 Reason => "Write_Delay is used for debugging only");
Nico Huber83693c82016-10-08 22:17:55 +020099 procedure Initialize
Nico Huber2b6f6992017-07-09 18:11:34 +0200100 (Write_Delay : in Word64 := 0;
Nico Huber793a8d42016-11-21 18:57:03 +0100101 Clean_State : in Boolean := False;
Nico Huber83693c82016-10-08 22:17:55 +0200102 Success : out Boolean)
103 with
104 Global =>
Nico Huber27088aa2018-06-10 13:28:05 +0200105 (In_Out => (Device_State, Port_IO.State),
106 Output => (State, Init_State, Config_State),
Nico Huber83693c82016-10-08 22:17:55 +0200107 Input => (Time.State)),
108 Post => Success = Is_Initialized;
109 function Is_Initialized return Boolean
110 with
111 Global => (Input => Init_State);
Nico Huberbebca132017-06-12 23:04:46 +0200112 pragma Warnings (GNATprove, On, "unused variable ""Write_Delay""");
Nico Huber83693c82016-10-08 22:17:55 +0200113
Nico Huber42fb2d02017-09-01 17:01:51 +0200114 procedure Power_Up_VGA
115 with
Nico Hubercf88f3d2018-06-05 13:27:34 +0200116 Global =>
Nico Huberadfe11f2018-06-10 14:59:04 +0200117 (Input => (State, Config_State, Time.State),
Nico Hubercf88f3d2018-06-05 13:27:34 +0200118 In_Out => (Device_State),
119 Proof_In => (Init_State)),
Nico Huber42fb2d02017-09-01 17:01:51 +0200120 Pre => Is_Initialized;
121
Nico Hubercf88f3d2018-06-05 13:27:34 +0200122 ----------------------------------------------------------------------------
Nico Huber83693c82016-10-08 22:17:55 +0200123
Nico Hubercf88f3d2018-06-05 13:27:34 +0200124 procedure Update_Outputs (Configs : Pipe_Configs)
125 with
126 Global =>
127 (Input => (Config_State, Time.State),
128 In_Out => (State, Device_State, Port_IO.State),
129 Proof_In => (Init_State)),
130 Pre => Is_Initialized;
131
Nico Huber75a707f2018-06-18 16:28:33 +0200132 pragma Warnings (GNATprove, Off, "no check message justified by this",
133 Reason => "see Annotate aspects.");
Nico Hubercf88f3d2018-06-05 13:27:34 +0200134 procedure Update_Cursor (Pipe : Pipe_Index; Cursor : Cursor_Type)
135 with
136 Global =>
Nico Huber75a707f2018-06-18 16:28:33 +0200137 (Input => (Config_State),
138 In_Out => (State, Device_State),
Nico Hubercf88f3d2018-06-05 13:27:34 +0200139 Proof_In => (Init_State)),
Nico Huber75a707f2018-06-18 16:28:33 +0200140 Pre => Is_Initialized,
141 Annotate =>
142 (GNATprove, Intentional,
143 "global input ""GMA.Config_State"" of ""Update_Cursor"" not read",
144 "Reading of Config_State depends on the platform configuration.");
Nico Hubercf88f3d2018-06-05 13:27:34 +0200145
Nico Huber15ffc4f2018-01-11 14:44:43 +0100146 procedure Place_Cursor
147 (Pipe : Pipe_Index;
148 X : Cursor_Pos;
Nico Hubercf88f3d2018-06-05 13:27:34 +0200149 Y : Cursor_Pos)
150 with
151 Global =>
Nico Huber75a707f2018-06-18 16:28:33 +0200152 (Input => (Config_State),
153 In_Out => (State, Device_State),
Nico Hubercf88f3d2018-06-05 13:27:34 +0200154 Proof_In => (Init_State)),
Nico Huber75a707f2018-06-18 16:28:33 +0200155 Pre => Is_Initialized,
156 Annotate =>
157 (GNATprove, Intentional,
158 "global input ""GMA.Config_State"" of ""Place_Cursor"" not read",
159 "Reading of Config_State depends on the platform configuration.");
Nico Hubercf88f3d2018-06-05 13:27:34 +0200160
Nico Huber15ffc4f2018-01-11 14:44:43 +0100161 procedure Move_Cursor
162 (Pipe : Pipe_Index;
163 X : Cursor_Pos;
Nico Hubercf88f3d2018-06-05 13:27:34 +0200164 Y : Cursor_Pos)
165 with
166 Global =>
Nico Huber75a707f2018-06-18 16:28:33 +0200167 (Input => (Config_State),
168 In_Out => (State, Device_State),
Nico Hubercf88f3d2018-06-05 13:27:34 +0200169 Proof_In => (Init_State)),
Nico Huber75a707f2018-06-18 16:28:33 +0200170 Pre => Is_Initialized,
171 Annotate =>
172 (GNATprove, Intentional,
173 "global input ""GMA.Config_State"" of ""Move_Cursor"" not read",
174 "Reading of Config_State depends on the platform configuration.");
Nico Huber15ffc4f2018-01-11 14:44:43 +0100175
Nico Hubercf88f3d2018-06-05 13:27:34 +0200176 ----------------------------------------------------------------------------
Nico Huber83693c82016-10-08 22:17:55 +0200177
Nico Huber83693c82016-10-08 22:17:55 +0200178 procedure Write_GTT
179 (GTT_Page : GTT_Range;
180 Device_Address : GTT_Address_Type;
Nico Hubercf88f3d2018-06-05 13:27:34 +0200181 Valid : Boolean)
182 with
Nico Huberadfe11f2018-06-10 14:59:04 +0200183 Global =>
184 (Input => Config_State,
185 In_Out => Device_State, Proof_In => Init_State),
Nico Hubercf88f3d2018-06-05 13:27:34 +0200186 Pre => Is_Initialized;
Nico Huber83693c82016-10-08 22:17:55 +0200187
Nico Huberceda17d2018-06-09 22:00:29 +0200188 procedure Read_GTT
189 (Device_Address : out GTT_Address_Type;
190 Valid : out Boolean;
191 GTT_Page : in GTT_Range)
192 with
Nico Huberadfe11f2018-06-10 14:59:04 +0200193 Global =>
194 (Input => Config_State,
195 In_Out => Device_State, Proof_In => Init_State),
Nico Huberceda17d2018-06-09 22:00:29 +0200196 Pre => Is_Initialized;
197
Nico Huber5374c3a2017-07-15 21:48:06 +0200198 procedure Setup_Default_FB
199 (FB : in Framebuffer_Type;
200 Clear : in Boolean := True;
201 Success : out Boolean)
Nico Huber194e57e2017-07-15 21:15:46 +0200202 with
Nico Hubercf88f3d2018-06-05 13:27:34 +0200203 Global =>
Nico Huberadfe11f2018-06-10 14:59:04 +0200204 (Input => Config_State,
205 In_Out =>
Nico Hubercf88f3d2018-06-05 13:27:34 +0200206 (State, Device_State,
207 Framebuffer_Filler.State, Framebuffer_Filler.Base_Address),
208 Proof_In => (Init_State)),
Nico Huber5374c3a2017-07-15 21:48:06 +0200209 Pre => Is_Initialized and HW.Config.Dynamic_MMIO;
Nico Huber83693c82016-10-08 22:17:55 +0200210
Nico Huberc3f66f62017-07-16 21:39:54 +0200211 procedure Map_Linear_FB (Linear_FB : out Word64; FB : in Framebuffer_Type)
212 with
Nico Hubercf88f3d2018-06-05 13:27:34 +0200213 Global =>
Nico Huberadfe11f2018-06-10 14:59:04 +0200214 (Input => Config_State,
215 In_Out => (State, Device_State),
Nico Hubercf88f3d2018-06-05 13:27:34 +0200216 Proof_In => (Init_State)),
Nico Huberadfe11f2018-06-10 14:59:04 +0200217 Pre => Is_Initialized and HW.Config.Dynamic_MMIO,
218 Annotate =>
219 (GNATprove, Intentional,
220 "global input ""GMA.Config_State"" of ""Map_Linear_FB"" not read",
221 "Reading of Config_State depends on the platform configuration.");
222 pragma Warnings (GNATprove, On, "no check message justified by this");
Nico Huberc3f66f62017-07-16 21:39:54 +0200223
Nico Hubercf88f3d2018-06-05 13:27:34 +0200224 ----------------------------------------------------------------------------
225
226 pragma Warnings (GNATprove, Off, "subprogram ""Dump_Configs"" has no effect",
227 Reason => "It's only used for debugging");
228 procedure Dump_Configs (Configs : Pipe_Configs);
229
Nico Huber83693c82016-10-08 22:17:55 +0200230private
231
Nico Huber3299ad52018-06-02 16:53:39 +0200232 -- For the default framebuffer setup (see below) with 90 degree rotations,
233 -- we expect the offset which is used for the final scanout to be above
234 -- `GTT_Rotation_Offset`. So we can use `Offset - GTT_Rotation_Offset` for
235 -- the physical memory location and aperture mapping.
236 function Phys_Offset (FB : Framebuffer_Type) return Word32 is
237 (if Rotation_90 (FB)
238 then FB.Offset - Word32 (GTT_Rotation_Offset) * GTT_Page_Size
239 else FB.Offset);
240
Nico Huber8c45bcf2016-11-20 17:30:57 +0100241 ----------------------------------------------------------------------------
242 -- State tracking for the currently configured pipes
243
244 Cur_Configs : Pipe_Configs with Part_Of => State;
245
Nico Huber3d06de82018-05-29 01:35:04 +0200246 function Requires_Scaling (Pipe_Cfg : Pipe_Config) return Boolean is
247 (Requires_Scaling (Pipe_Cfg.Framebuffer, Pipe_Cfg.Mode));
248
Nico Huberb217ece2018-06-02 16:56:35 +0200249 function Scaling_Type (Pipe_Cfg : Pipe_Config) return Scaling_Aspect is
250 (Scaling_Type (Pipe_Cfg.Framebuffer, Pipe_Cfg.Mode));
251
Nico Huber8c45bcf2016-11-20 17:30:57 +0100252 ----------------------------------------------------------------------------
253 -- Internal representation of a single pipe's configuration
254
Arthur Heymans5d08a932018-03-28 17:00:18 +0200255 type GPU_Port is (DIGI_A, DIGI_B, DIGI_C, DIGI_D, DIGI_E, LVDS, VGA);
Nico Huber83693c82016-10-08 22:17:55 +0200256
257 subtype Digital_Port is GPU_Port range DIGI_A .. DIGI_E;
Arthur Heymans5d08a932018-03-28 17:00:18 +0200258 subtype GMCH_DP_Port is GPU_Port range DIGI_B .. DIGI_D;
259 subtype GMCH_HDMI_Port is GPU_Port range DIGI_B .. DIGI_C;
Nico Huber83693c82016-10-08 22:17:55 +0200260
261 type PCH_Port is
262 (PCH_DAC, PCH_LVDS,
263 PCH_HDMI_B, PCH_HDMI_C, PCH_HDMI_D,
264 PCH_DP_B, PCH_DP_C, PCH_DP_D);
265
266 subtype PCH_HDMI_Port is PCH_Port range PCH_HDMI_B .. PCH_HDMI_D;
267 subtype PCH_DP_Port is PCH_Port range PCH_DP_B .. PCH_DP_D;
268
Nico Huber83693c82016-10-08 22:17:55 +0200269 type Port_Config is
270 record
271 Port : GPU_Port;
272 PCH_Port : GMA.PCH_Port;
273 Display : Display_Type;
274 Mode : Mode_Type;
275 Is_FDI : Boolean;
276 FDI : DP_Link;
277 DP : DP_Link;
278 end record;
279
280 type FDI_Training_Type is (Simple_Training, Full_Training, Auto_Training);
281
282 ----------------------------------------------------------------------------
283
284 type DP_Port is (DP_A, DP_B, DP_C, DP_D);
285
Nico Huber247adf32017-06-12 14:39:11 +0200286 ----------------------------------------------------------------------------
287
288 subtype DDI_HDMI_Buf_Trans_Range is Integer range 0 .. 11;
289
Nico Huber0164b022017-08-24 15:12:51 +0200290 ----------------------------------------------------------------------------
291
Nico Huberc5c767a2018-06-03 01:09:04 +0200292 Tile_Width : constant array (Tiling_Type) of Width_Type :=
Nico Huber0164b022017-08-24 15:12:51 +0200293 (Linear => 16, X_Tiled => 128, Y_Tiled => 32);
Nico Huberc5c767a2018-06-03 01:09:04 +0200294 Tile_Rows : constant array (Tiling_Type) of Height_Type :=
Nico Huber9b479412017-08-27 11:55:56 +0200295 (Linear => 1, X_Tiled => 8, Y_Tiled => 32);
Nico Huber0164b022017-08-24 15:12:51 +0200296
Nico Huber5ef4d602017-12-13 13:56:47 +0100297 function FB_Pitch (Px : Pos_Pixel_Type; FB : Framebuffer_Type) return Natural
298 is (Natural (Div_Round_Up
299 (Pixel_To_Bytes (Px, FB), Tile_Width (FB.Tiling) * 4)));
Nico Huber0164b022017-08-24 15:12:51 +0200300
301 function Valid_Stride (FB : Framebuffer_Type) return Boolean is
Nico Huber5ef4d602017-12-13 13:56:47 +0100302 (FB.Width + FB.Start_X <= FB.Stride and
Nico Huber9b479412017-08-27 11:55:56 +0200303 Pixel_To_Bytes (FB.Stride, FB) mod (Tile_Width (FB.Tiling) * 4) = 0 and
Nico Huber5ef4d602017-12-13 13:56:47 +0100304 FB.Height + FB.Start_Y <= FB.V_Stride and
Nico Huber9b479412017-08-27 11:55:56 +0200305 FB.V_Stride mod Tile_Rows (FB.Tiling) = 0);
Nico Huber0164b022017-08-24 15:12:51 +0200306
Nico Huber83693c82016-10-08 22:17:55 +0200307end HW.GFX.GMA;