blob: c210dd5bd4644314f773416f3ec374a86ccdef76 [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
Nico Huberfdb0df12018-02-07 14:30:34 +01002-- Copyright (C) 2015-2018 secunet Security Networks AG
Nico Huber83693c82016-10-08 22:17:55 +02003--
4-- This program is free software; you can redistribute it and/or modify
5-- it under the terms of the GNU General Public License as published by
Nico Huber125a29e2016-10-18 00:23:54 +02006-- the Free Software Foundation; either version 2 of the License, or
7-- (at your option) any later version.
Nico Huber83693c82016-10-08 22:17:55 +02008--
9-- This program is distributed in the hope that it will be useful,
10-- but WITHOUT ANY WARRANTY; without even the implied warranty of
11-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12-- GNU General Public License for more details.
13--
14
15with HW.Debug;
16with GNAT.Source_Info;
17
Nico Huber7ad2d652016-12-07 15:19:32 +010018with HW.GFX.GMA.Transcoder;
Nico Huber83693c82016-10-08 22:17:55 +020019
20package body HW.GFX.GMA.Pipe_Setup is
21
Nico Huberfbb42202016-11-07 15:08:26 +010022 ILK_DISPLAY_CHICKEN1_VGA_MASK : constant := 7 * 2 ** 29;
23 ILK_DISPLAY_CHICKEN1_VGA_ENABLE : constant := 5 * 2 ** 29;
24 ILK_DISPLAY_CHICKEN2_VGA_MASK : constant := 1 * 2 ** 25;
25 ILK_DISPLAY_CHICKEN2_VGA_ENABLE : constant := 0 * 2 ** 25;
26
Nico Huber7ad2d652016-12-07 15:19:32 +010027 DSPCNTR_ENABLE : constant := 1 * 2 ** 31;
28 DSPCNTR_GAMMA_CORRECTION : constant := 1 * 2 ** 30;
Nico Huber7ad2d652016-12-07 15:19:32 +010029 DSPCNTR_FORMAT_MASK : constant := 15 * 2 ** 26;
Arthur Heymans960e2392026-03-03 19:45:24 +010030 DSPCNTR_PIPE_SEL_MASK : constant := 3 * 2 ** 24;
31 DSPCNTR_PIPE_B_SELECT : constant := 1 * 2 ** 24;
Nico Huberab69e362018-05-29 21:20:30 +020032 DSPCNTR_DISABLE_TRICKLE_FEED : constant := 1 * 2 ** 14;
33 DSPCNTR_TILED_SURFACE_LINEAR : constant := 0 * 2 ** 10;
34 DSPCNTR_TILED_SURFACE_X_TILED : constant := 1 * 2 ** 10;
35
36 DSPCNTR_TILED_SURFACE : constant array (Tiling_Type) of Word32 :=
37 (Linear => DSPCNTR_TILED_SURFACE_LINEAR,
38 X_Tiled => DSPCNTR_TILED_SURFACE_X_TILED,
39 Y_Tiled => 0); -- unsupported
Nico Huber83693c82016-10-08 22:17:55 +020040
Arthur Heymans960e2392026-03-03 19:45:24 +010041 function DSPCNTR_PIPE_SEL (Pipe : Pipe_Index) return Word32 is
42 (if Pipe = Secondary then DSPCNTR_PIPE_B_SELECT else 0);
43
Nico Huber83693c82016-10-08 22:17:55 +020044 DSPCNTR_MASK : constant Word32 :=
45 DSPCNTR_ENABLE or
46 DSPCNTR_GAMMA_CORRECTION or
47 DSPCNTR_FORMAT_MASK or
Arthur Heymans960e2392026-03-03 19:45:24 +010048 DSPCNTR_PIPE_SEL_MASK or
Nico Huberab69e362018-05-29 21:20:30 +020049 DSPCNTR_DISABLE_TRICKLE_FEED or
50 DSPCNTR_TILED_SURFACE_X_TILED;
Nico Huber83693c82016-10-08 22:17:55 +020051
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -060052 PLANE_COLOR_CTL_PLANE_GAMMA_DISABLE : constant := 1 * 2 ** 13;
53
Nico Huber83693c82016-10-08 22:17:55 +020054 PLANE_CTL_PLANE_ENABLE : constant := 1 * 2 ** 31;
55 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 : constant := 4 * 2 ** 24;
56 PLANE_CTL_PLANE_GAMMA_DISABLE : constant := 1 * 2 ** 13;
Nico Huber0164b022017-08-24 15:12:51 +020057 PLANE_CTL_TILED_SURFACE_MASK : constant := 7 * 2 ** 10;
58 PLANE_CTL_TILED_SURFACE_LINEAR : constant := 0 * 2 ** 10;
59 PLANE_CTL_TILED_SURFACE_X_TILED : constant := 1 * 2 ** 10;
60 PLANE_CTL_TILED_SURFACE_Y_TILED : constant := 4 * 2 ** 10;
61 PLANE_CTL_TILED_SURFACE_YF_TILED : constant := 5 * 2 ** 10;
62
63 PLANE_CTL_TILED_SURFACE : constant array (Tiling_Type) of Word32 :=
64 (Linear => PLANE_CTL_TILED_SURFACE_LINEAR,
65 X_Tiled => PLANE_CTL_TILED_SURFACE_X_TILED,
66 Y_Tiled => PLANE_CTL_TILED_SURFACE_Y_TILED);
Nico Huber83693c82016-10-08 22:17:55 +020067
Nico Huber9b479412017-08-27 11:55:56 +020068 PLANE_CTL_PLANE_ROTATION_MASK : constant := 3 * 2 ** 0;
69 PLANE_CTL_PLANE_ROTATION : constant array (Rotation_Type) of Word32 :=
70 (No_Rotation => 0 * 2 ** 0,
71 Rotated_90 => 1 * 2 ** 0,
72 Rotated_180 => 2 * 2 ** 0,
73 Rotated_270 => 3 * 2 ** 0);
74
Nico Huber83693c82016-10-08 22:17:55 +020075 PLANE_WM_ENABLE : constant := 1 * 2 ** 31;
76 PLANE_WM_LINES_SHIFT : constant := 14;
77 PLANE_WM_LINES_MASK : constant := 16#001f# * 2 ** 14;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -060078 PLANE_WM_BLOCKS_MASK : constant :=
79 (if Config.Has_Wide_Watermarks then 16#7ff# else 16#3ff#);
80
81 PIPEMISC_HDR_MODE_PRECISION : constant := 1 * 2 ** 23;
82 PIPEMISC_PIXEL_ROUNDING_TRUNC : constant := 1 * 2 ** 8;
Nico Huber83693c82016-10-08 22:17:55 +020083
Nico Huber33912aa2016-12-06 20:36:23 +010084 VGA_SR_INDEX : constant := 16#03c4#;
85 VGA_SR_DATA : constant := 16#03c5#;
86 VGA_SR01 : constant := 16#01#;
87 VGA_SR01_SCREEN_OFF : constant := 1 * 2 ** 5;
Nico Huber3675db52016-11-04 16:27:29 +010088
89 VGA_CONTROL_VGA_DISPLAY_DISABLE : constant := 1 * 2 ** 31;
90 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK : constant := 16#0003# * 2 ** 6;
91 VGA_CONTROL_BLINK_DUTY_CYCLE_50 : constant := 2 * 2 ** 6;
92 VGA_CONTROL_VSYNC_BLINK_RATE_MASK : constant := 16#003f# * 2 ** 0;
93
Nico Huber4dc4c612018-01-10 15:55:09 +010094 CUR_CTL_PIPE_SELECT : constant array (Pipe_Index) of Word32 :=
95 (Primary => 0 * 2 ** 28,
96 Secondary => 1 * 2 ** 28,
97 Tertiary => 2 * 2 ** 28);
98 CUR_CTL_MODE : constant array (Cursor_Mode, Cursor_Size) of Word32 :=
99 (No_Cursor => (others => 16#00#),
100 ARGB_Cursor =>
101 (Cursor_64x64 => 16#27#,
102 Cursor_128x128 => 16#22#,
103 Cursor_256x256 => 16#23#));
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600104 subtype ARB_Slots is Natural range 0 .. 7;
105 function MCURSOR_ARB_SLOTS (N : ARB_Slots) return Word32 is
106 (Shift_Left (Word32 (N), 28));
Nico Huber4dc4c612018-01-10 15:55:09 +0100107
108 function CUR_POS_Y (Y : Int32) return Word32 is
109 ((if Y >= 0 then 0 else 1 * 2 ** 31) or Shift_Left (Word32 (abs Y), 16))
110 with
111 Pre => Y > Int32'First;
112 function CUR_POS_X (X : Int32) return Word32 is
113 ((if X >= 0 then 0 else 1 * 2 ** 15) or Word32 (abs X))
114 with
115 Pre => X > Int32'First;
116
Nico Huber3675db52016-11-04 16:27:29 +0100117 subtype VGA_Cycle_Count is Pos32 range 2 .. 128;
118 function VGA_CONTROL_VSYNC_BLINK_RATE
119 (Cycles : VGA_Cycle_Count)
120 return Word32
121 is
122 begin
123 return Word32 (Cycles) / 2 - 1;
124 end VGA_CONTROL_VSYNC_BLINK_RATE;
125
Nico Huber7ad2d652016-12-07 15:19:32 +0100126 PF_CTRL_ENABLE : constant := 1 * 2 ** 31;
127 PF_CTRL_PIPE_SELECT_MASK : constant := 3 * 2 ** 29;
128 PF_CTRL_FILTER_MED : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200129
Nico Huber7ad2d652016-12-07 15:19:32 +0100130 PS_CTRL_ENABLE_SCALER : constant := 1 * 2 ** 31;
131 PS_CTRL_SCALER_MODE_7X5_EXTENDED : constant := 1 * 2 ** 28;
132 PS_CTRL_FILTER_SELECT_MEDIUM_2 : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200133
Arthur Heymansd5198442018-03-28 17:05:12 +0200134 GMCH_PFIT_CONTROL_SELECT_MASK : constant := 3 * 2 ** 29;
135 GMCH_PFIT_CONTROL_SELECT_PIPE_A : constant := 0 * 2 ** 29;
136 GMCH_PFIT_CONTROL_SELECT_PIPE_B : constant := 1 * 2 ** 29;
Nico Huber958c5642018-06-02 16:59:31 +0200137 GMCH_PFIT_CONTROL_SCALING_MASK : constant := 3 * 2 ** 26;
138 GMCH_PFIT_CONTROL_SCALING : constant array (Scaling_Aspect) of Word32 :=
139 (Uniform => 0 * 2 ** 26,
140 Pillarbox => 2 * 2 ** 26,
141 Letterbox => 3 * 2 ** 26);
Arthur Heymansd5198442018-03-28 17:05:12 +0200142
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200143 VGACNTRL_REG : constant Registers.Registers_Index :=
144 (if Config.Has_GMCH_VGACNTRL then
145 Registers.GMCH_VGACNTRL
146 else Registers.CPU_VGACNTRL);
147
Nico Huber83693c82016-10-08 22:17:55 +0200148 ---------------------------------------------------------------------------
149
Nico Huber83693c82016-10-08 22:17:55 +0200150 function PLANE_WM_LINES (Lines : Natural) return Word32 is
151 begin
152 return Shift_Left (Word32 (Lines), PLANE_WM_LINES_SHIFT)
153 and PLANE_WM_LINES_MASK;
154 end PLANE_WM_LINES;
155
156 function PLANE_WM_BLOCKS (Blocks : Natural) return Word32 is
157 begin
158 return Word32 (Blocks) and PLANE_WM_BLOCKS_MASK;
159 end PLANE_WM_BLOCKS;
160
161 ---------------------------------------------------------------------------
162
Nico Hubera7e1cd32026-07-03 09:23:24 +0000163 subtype Source_Size is Width_Type;
Nico Huberfb6dbad2026-04-10 16:23:39 +0000164
Nico Hubera7e1cd32026-07-03 09:23:24 +0000165 function Encode_Size (LSW, MSW : Source_Size) return Word32
Nico Huberfb6dbad2026-04-10 16:23:39 +0000166 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000167 (Shift_Left (Word32 (MSW) - 1, 16) or (Word32 (LSW) - 1));
168
169 function Source_Width (FB : Framebuffer_Type) return Source_Size
170 is
171 (if Config.Needs_Even_Source_Width and then Rotated_Width (FB) > 2 then
172 Rotated_Width (FB) - Rotated_Width (FB) mod 2
Nico Huberfb6dbad2026-04-10 16:23:39 +0000173 else
Nico Hubera7e1cd32026-07-03 09:23:24 +0000174 Rotated_Width (FB));
Nico Huberfb6dbad2026-04-10 16:23:39 +0000175
Nico Hubera7e1cd32026-07-03 09:23:24 +0000176 function Source_Height (FB : Framebuffer_Type) return Source_Size
Nico Huberfb6dbad2026-04-10 16:23:39 +0000177 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000178 (Rotated_Height (FB));
Nico Huber83693c82016-10-08 22:17:55 +0200179
180 ----------------------------------------------------------------------------
181
Nico Huber83693c82016-10-08 22:17:55 +0200182 procedure Clear_Watermarks (Controller : Controller_Type) is
183 begin
Nico Huber4dc4c612018-01-10 15:55:09 +0100184 Registers.Write (Controller.CUR_BUF_CFG, 16#0000_0000#);
185 for Level in WM_Levels loop
186 Registers.Write (Controller.CUR_WM (Level), 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200187 end loop;
Nico Huber9e78dda2020-10-01 15:30:54 +0200188 Registers.Write (Controller.PLANE_2_BUF_CFG, 16#0000_0000#);
189 for Level in WM_Levels loop
190 Registers.Write (Controller.PLANE_2_WM (Level), 16#0000_0000#);
191 end loop;
Nico Huber4dc4c612018-01-10 15:55:09 +0100192 Registers.Write (Controller.PLANE_BUF_CFG, 16#0000_0000#);
193 for Level in WM_Levels loop
194 Registers.Write (Controller.PLANE_WM (Level), 16#0000_0000#);
195 end loop;
196 Registers.Write (Controller.WM_LINETIME, 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200197 end Clear_Watermarks;
198
199 procedure Setup_Watermarks (Controller : Controller_Type)
200 is
Nico Huber9e78dda2020-10-01 15:30:54 +0200201 subtype Buffer_Count is Natural range 1 .. 508;
202 subtype Buffer_Index is Natural range 0 .. Buffer_Count'Last - 1;
203
204 function Encode_Buffers (Start : Buffer_Index; Count : Buffer_Count)
205 return Word32
206 is
207 (Shift_Left (Word32 (Start + Count - 1), 16) or Word32 (Start));
208
Nico Huberf3e23662016-12-05 21:33:03 +0100209 type Per_Plane_Buffer_Range is array (Pipe_Index) of Word32;
Nico Huber9e78dda2020-10-01 15:30:54 +0200210 Plane_1_Buffer_Range : constant Per_Plane_Buffer_Range :=
211 (Primary => Encode_Buffers ( 0, 150),
212 Secondary => Encode_Buffers (169, 150),
213 Tertiary => Encode_Buffers (338, 150));
214 Plane_2_Buffer_Range : constant Per_Plane_Buffer_Range :=
215 (Primary => Encode_Buffers (150, 11),
216 Secondary => Encode_Buffers (319, 11),
217 Tertiary => Encode_Buffers (488, 11));
Nico Huber4dc4c612018-01-10 15:55:09 +0100218 Cur_Buffer_Range : constant Per_Plane_Buffer_Range :=
Nico Huber9e78dda2020-10-01 15:30:54 +0200219 (Primary => Encode_Buffers (161, 8),
220 Secondary => Encode_Buffers (330, 8),
221 Tertiary => Encode_Buffers (499, 8));
Nico Huber83693c82016-10-08 22:17:55 +0200222 begin
223 Registers.Write
224 (Register => Controller.PLANE_BUF_CFG,
Nico Huber9e78dda2020-10-01 15:30:54 +0200225 Value => Plane_1_Buffer_Range (Controller.Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200226 Registers.Write
227 (Register => Controller.PLANE_WM (0),
228 Value => PLANE_WM_ENABLE or
229 PLANE_WM_LINES (2) or
Nico Huber9e78dda2020-10-01 15:30:54 +0200230 PLANE_WM_BLOCKS (150));
231 Registers.Write
232 (Register => Controller.PLANE_2_BUF_CFG,
233 Value => Plane_2_Buffer_Range (Controller.Pipe));
234 Registers.Write
235 (Register => Controller.PLANE_2_WM (0),
236 Value => PLANE_WM_ENABLE or
237 PLANE_WM_LINES (2) or
238 PLANE_WM_BLOCKS (11));
Nico Huber4dc4c612018-01-10 15:55:09 +0100239 Registers.Write
240 (Register => Controller.CUR_BUF_CFG,
241 Value => Cur_Buffer_Range (Controller.Pipe));
242 Registers.Write
243 (Register => Controller.CUR_WM (0),
244 Value => PLANE_WM_ENABLE or
245 PLANE_WM_LINES (2) or
246 PLANE_WM_BLOCKS (8));
Nico Huber83693c82016-10-08 22:17:55 +0200247 end Setup_Watermarks;
248
249 ----------------------------------------------------------------------------
250
Nico Huber3675db52016-11-04 16:27:29 +0100251 procedure Setup_Hires_Plane
Nico Huber6a4dfc82016-11-04 15:50:58 +0100252 (Controller : Controller_Type;
Nico Huber0164b022017-08-24 15:12:51 +0200253 FB : HW.GFX.Framebuffer_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200254 with
Nico Huber5ef4d602017-12-13 13:56:47 +0100255 Pre => FB.Height + FB.Start_Y <= FB.V_Stride
Nico Huber83693c82016-10-08 22:17:55 +0200256 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000257 Width : constant Source_Size := Source_Width (FB);
258 Height : constant Source_Size := Source_Height (FB);
Nico Huberfb6dbad2026-04-10 16:23:39 +0000259
Nico Huber83693c82016-10-08 22:17:55 +0200260 -- FIXME: setup correct format, based on framebuffer RGB format
261 Format : constant Word32 := 6 * 2 ** 26;
Arthur Heymans960e2392026-03-03 19:45:24 +0100262 PRI : Word32 := Format;
Nico Huber83693c82016-10-08 22:17:55 +0200263 begin
264 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
265
Nico Huber83693c82016-10-08 22:17:55 +0200266 if Config.Has_Plane_Control then
Nico Huber9b479412017-08-27 11:55:56 +0200267 declare
Nico Huber34be6542017-12-13 09:26:24 +0100268 Stride, Offset : Word32;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600269
270 function PLANE_CTL_ARB_SLOTS (N : Word32) return Word32 is
271 (if Config.Need_Pipe_Arb_Slots then Shift_Left (N, 28) else 0);
272
273 -- TODO: Hard coded format and arbitration slots for now,
274 -- for 4B-per-pixel XRGB, just like `Format` above.
275 -- ARB_SLOTS(1) matches the 4B per pixel.
276 Plane_Ctl : constant Word32 :=
277 PLANE_CTL_PLANE_ENABLE or
278 PLANE_CTL_TILED_SURFACE (FB.Tiling) or
279 PLANE_CTL_PLANE_ROTATION (FB.Rotation) or
280 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
281 PLANE_CTL_ARB_SLOTS (1) or
282 (if not Config.Has_Plane_Color_Control
283 then PLANE_CTL_PLANE_GAMMA_DISABLE
284 else 0);
Nico Huber9b479412017-08-27 11:55:56 +0200285 begin
286 if Rotation_90 (FB) then
Nico Huber5ef4d602017-12-13 13:56:47 +0100287 Stride := Word32 (FB_Pitch (FB.V_Stride, FB));
288 Offset := Shift_Left (Word32 (FB.Start_X), 16) or
289 Word32 (FB.V_Stride - FB.Height - FB.Start_Y);
Nico Huber9b479412017-08-27 11:55:56 +0200290 else
Nico Huber5ef4d602017-12-13 13:56:47 +0100291 Stride := Word32 (FB_Pitch (FB.Stride, FB));
292 Offset := Shift_Left (Word32 (FB.Start_Y), 16) or
293 Word32 (FB.Start_X);
Nico Huber9b479412017-08-27 11:55:56 +0200294 end if;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600295
296 if Config.Has_Plane_Color_Control then
297 Registers.Write
298 (Register => Controller.PLANE_COLOR_CTL,
299 Value => PLANE_COLOR_CTL_PLANE_GAMMA_DISABLE);
300 end if;
301 Registers.Write (Controller.PLANE_AUX_DIST, 0);
302 Registers.Write (Controller.PLANE_CTL, Plane_Ctl);
Nico Huber9b479412017-08-27 11:55:56 +0200303 Registers.Write (Controller.PLANE_OFFSET, Offset);
Nico Huberfb6dbad2026-04-10 16:23:39 +0000304 Registers.Write (Controller.PLANE_SIZE, Encode_Size (Width, Height));
Nico Huber9b479412017-08-27 11:55:56 +0200305 Registers.Write (Controller.PLANE_STRIDE, Stride);
306 Registers.Write (Controller.PLANE_POS, 16#0000_0000#);
Nico Huber34be6542017-12-13 09:26:24 +0100307 Registers.Write (Controller.PLANE_SURF, FB.Offset and 16#ffff_f000#);
Nico Huber9b479412017-08-27 11:55:56 +0200308 end;
Nico Huber83693c82016-10-08 22:17:55 +0200309 else
Arthur Heymans960e2392026-03-03 19:45:24 +0100310 if Config.Has_DSPCNTR_Pipe_Select then
311 PRI := PRI or DSPCNTR_PIPE_SEL (Controller.Pipe);
312 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200313 if Config.Disable_Trickle_Feed then
314 PRI := PRI or DSPCNTR_DISABLE_TRICKLE_FEED;
315 end if;
Arthur Heymans960e2392026-03-03 19:45:24 +0100316
317 -- Write DSPCNTR *without* the enable bit first. On pre-SKL
318 -- hardware the control register self-arms when the plane
319 -- transitions from disabled to enabled, latching whatever
320 -- stride/size/offset values happen to be in the registers at
321 -- that moment. Programming format, pipe-select, and trickle-
322 -- feed now avoids a glitch with stale geometry values.
Nico Huber83693c82016-10-08 22:17:55 +0200323 Registers.Unset_And_Set_Mask
324 (Register => Controller.DSPCNTR,
325 Mask_Unset => DSPCNTR_MASK,
Nico Huberab69e362018-05-29 21:20:30 +0200326 Mask_Set => PRI or DSPCNTR_TILED_SURFACE (FB.Tiling));
Nico Huber83693c82016-10-08 22:17:55 +0200327
Nico Huber0164b022017-08-24 15:12:51 +0200328 Registers.Write
329 (Controller.DSPSTRIDE, Word32 (Pixel_To_Bytes (FB.Stride, FB)));
Arthur Heymans960e2392026-03-03 19:45:24 +0100330
331 -- Gen3 (i945): program DSPSIZE and DSPPOS before the surface
332 -- address write that arms the double-buffered plane registers.
333 if Config.Gen_I945 then
Nico Huberfb6dbad2026-04-10 16:23:39 +0000334 Registers.Write (Controller.DSPSIZE, Encode_Size (Width, Height));
Arthur Heymans960e2392026-03-03 19:45:24 +0100335 Registers.Write (Controller.DSPPOS, 16#0000_0000#);
336 end if;
337
Nico Huberab69e362018-05-29 21:20:30 +0200338 if Config.Has_DSP_Linoff and then FB.Tiling = Linear then
Arthur Heymans3f37cce2026-03-03 18:52:12 +0100339 pragma Assert_And_Cut
340 (FB.Start_Y * FB.Stride + FB.Start_X in Pixel_Type);
Nico Huberd49b56b2018-06-18 17:19:15 +0200341 declare
342 Linear_Offset : constant Pixel_Type :=
343 FB.Start_Y * FB.Stride + FB.Start_X;
344 begin
345 Registers.Write
346 (Register => Controller.DSPLINOFF,
Arthur Heymans960e2392026-03-03 19:45:24 +0100347 Value => (if Config.Has_DSPSURF
348 then Word32 (Pixel_To_Bytes (Linear_Offset, FB))
349 else (FB.Offset and 16#ffff_f000#) or
350 Word32 (Pixel_To_Bytes (Linear_Offset, FB))));
Nico Huberd49b56b2018-06-18 17:19:15 +0200351 Registers.Write (Controller.DSPTILEOFF, 0);
352 end;
Nico Huber5ef4d602017-12-13 13:56:47 +0100353 else
Nico Huberab69e362018-05-29 21:20:30 +0200354 if Config.Has_DSP_Linoff then
Arthur Heymans960e2392026-03-03 19:45:24 +0100355 Registers.Write (Controller.DSPLINOFF,
356 (if Config.Has_DSPSURF then 0
357 else FB.Offset and 16#ffff_f000#));
Nico Huberab69e362018-05-29 21:20:30 +0200358 end if;
Nico Huber5ef4d602017-12-13 13:56:47 +0100359 Registers.Write
360 (Register => Controller.DSPTILEOFF,
361 Value => Shift_Left (Word32 (FB.Start_Y), 16) or
362 Word32 (FB.Start_X));
Nico Huber83693c82016-10-08 22:17:55 +0200363 end if;
Arthur Heymans960e2392026-03-03 19:45:24 +0100364 if Config.Has_DSPSURF then
365 Registers.Write (Controller.DSPSURF, FB.Offset and 16#ffff_f000#);
366 end if;
367
368 -- Now enable the plane. All geometry registers are in place,
369 -- so the self-arm latches correct values.
370 Registers.Write
371 (Register => Controller.DSPCNTR,
372 Value => DSPCNTR_ENABLE or PRI or
373 DSPCNTR_TILED_SURFACE (FB.Tiling));
Nico Huber83693c82016-10-08 22:17:55 +0200374 end if;
Nico Huber3675db52016-11-04 16:27:29 +0100375 end Setup_Hires_Plane;
376
377 procedure Setup_Display
Nico Huber113a14b2016-12-06 21:59:15 +0100378 (Controller : Controller_Type;
379 Framebuffer : Framebuffer_Type;
380 Dither_BPC : BPC_Type;
381 Dither : Boolean)
Nico Huber3675db52016-11-04 16:27:29 +0100382 with
Nico Huber9b479412017-08-27 11:55:56 +0200383 Pre =>
384 Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
Nico Huber5ef4d602017-12-13 13:56:47 +0100385 Framebuffer.Height + Framebuffer.Start_Y <= Framebuffer.V_Stride
Nico Huber3675db52016-11-04 16:27:29 +0100386 is
387 use type Word8;
388
389 Reg8 : Word8;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600390
391 type BW_Credit is new Natural range 0 .. 3;
392 function MBUS_DBOX_BW_CREDIT (C : BW_Credit) return Word32 is
393 (Shift_Left (Word32 (C), 14));
394
395 type B_Credit is new Natural range 0 .. 31;
396 function MBUS_DBOX_B_CREDIT (C : B_Credit) return Word32 is
397 (Shift_Left (Word32 (C), 8));
398
399 type A_Credit is new Natural range 0 .. 15;
400 function MBUS_DBOX_A_CREDIT (C : A_Credit) return Word32 is
401 (Word32 (C));
402
403 type B2B_Trans_Max is new Natural range 0 .. 31;
404 function MBUS_DBOX_B2B_TRANSACTIONS_MAX (B : B2B_Trans_Max) return Word32 is
405 (Shift_Left (Word32 (B), 20));
406
407 type B2B_Trans_Delay is new Natural range 0 .. 7;
408 function MBUS_DBOX_B2B_TRANSACTIONS_DELAY (B : B2B_Trans_Delay) return Word32 is
409 (Shift_Left (Word32 (B), 17));
410 MBUS_DBOX_REGULATE_B2B_TRANSACTIONS_EN : constant := 1 * 2 ** 16;
411
412 procedure Program_Mbus_Dbox_Credits is
413 Tmp : Word32;
414 begin
415 Tmp := MBUS_DBOX_B2B_TRANSACTIONS_MAX (16) or
416 MBUS_DBOX_B2B_TRANSACTIONS_DELAY (1) or
417 MBUS_DBOX_REGULATE_B2B_TRANSACTIONS_EN;
418
419 if Config.Has_New_Mbus_Dbox_Credits then
420 Tmp := Tmp or MBUS_DBOX_BW_CREDIT (2) or
421 MBUS_DBOX_B_CREDIT (8) or
422 MBUS_DBOX_A_CREDIT (4); -- No joined MBus support,
423 -- hence always use 4 for now.
424 else
425 Tmp := Tmp or MBUS_DBOX_BW_CREDIT (2) or
426 MBUS_DBOX_B_CREDIT (12) or
427 MBUS_DBOX_A_CREDIT (2);
428 end if;
429
430 Registers.Write
431 (Register => Controller.MBUS_DBOX_CTL,
432 Value => Tmp);
433 end Program_Mbus_Dbox_Credits;
434
435 -- Display WA # 1605353570: icl
436 -- Set the pixel rounding bit to 1 for allowing
437 -- passthrough of Frame buffer pixels unmodified
438 -- across pipe
439 PIXEL_ROUNDING_TRUNC_FB_PASSTHRU : constant := 1 * 2 ** 15;
440
441 -- Display WA #1153: icl
442 -- enable hardware to bypass the alpha math
443 -- and rounding for per-pixel values 00 and 0xff
444 PER_PIXEL_ALPHA_BYPASS_EN : constant := 1 * 2 ** 7;
445
446 -- ADL_P requires that we disable underrun recovery when
447 -- downscaling (or using the scaler for YUV420 pipe output),
448 -- using DSC, or using PSR2.
449 -- i915 always disables underrun recovery for gen 13+.
450 UNDERRUN_RECOVERY_DISABLE : constant := 1 * 2 ** 30;
Nico Huberfb6dbad2026-04-10 16:23:39 +0000451
Nico Hubera7e1cd32026-07-03 09:23:24 +0000452 Width : constant Source_Size := Source_Width (Framebuffer);
453 Height : constant Source_Size := Source_Height (Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100454 begin
455 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
456
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600457 if Config.Has_Type_C_Ports then
458 Registers.Set_Mask
459 (Register => Controller.PIPE_CHICKEN,
460 Mask => PER_PIXEL_ALPHA_BYPASS_EN or
461 PIXEL_ROUNDING_TRUNC_FB_PASSTHRU or
462 (if Config.Need_Underrun_Rec_Disable
463 then UNDERRUN_RECOVERY_DISABLE
464 else 0));
465 end if;
466
Nico Huber3675db52016-11-04 16:27:29 +0100467 if Config.Has_Plane_Control then
468 Setup_Watermarks (Controller);
469 end if;
470
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600471 if Config.Has_Mbus_Dbox_Credits then
472 Program_Mbus_Dbox_Credits;
473 end if;
474
Nico Huber3675db52016-11-04 16:27:29 +0100475 if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
Nico Huberfbb42202016-11-07 15:08:26 +0100476 if Config.VGA_Plane_Workaround then
477 Registers.Unset_And_Set_Mask
478 (Register => Registers.ILK_DISPLAY_CHICKEN1,
479 Mask_Unset => ILK_DISPLAY_CHICKEN1_VGA_MASK,
480 Mask_Set => ILK_DISPLAY_CHICKEN1_VGA_ENABLE);
481 Registers.Unset_And_Set_Mask
482 (Register => Registers.ILK_DISPLAY_CHICKEN2,
483 Mask_Unset => ILK_DISPLAY_CHICKEN2_VGA_MASK,
484 Mask_Set => ILK_DISPLAY_CHICKEN2_VGA_ENABLE);
485 end if;
486
Nico Huber3675db52016-11-04 16:27:29 +0100487 Registers.Unset_And_Set_Mask
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200488 (Register => VGACNTRL_REG,
Nico Huber3675db52016-11-04 16:27:29 +0100489 Mask_Unset => VGA_CONTROL_VGA_DISPLAY_DISABLE or
490 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK or
491 VGA_CONTROL_VSYNC_BLINK_RATE_MASK,
492 Mask_Set => VGA_CONTROL_BLINK_DUTY_CYCLE_50 or
493 VGA_CONTROL_VSYNC_BLINK_RATE (30));
494
495 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
496 Port_IO.InB (Reg8, VGA_SR_DATA);
497 Port_IO.OutB (VGA_SR_DATA, Reg8 and not (VGA_SR01_SCREEN_OFF));
498 else
Nico Huber6a4dfc82016-11-04 15:50:58 +0100499 Setup_Hires_Plane (Controller, Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100500 end if;
501
502 Registers.Write
503 (Register => Controller.PIPESRC,
Nico Huberfb6dbad2026-04-10 16:23:39 +0000504 Value => Encode_Size (Height, Width));
Nico Huber83693c82016-10-08 22:17:55 +0200505
Nico Huber113a14b2016-12-06 21:59:15 +0100506 if Config.Has_Pipeconf_Misc then
507 Registers.Write
508 (Register => Controller.PIPEMISC,
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600509 Value => Transcoder.BPC_Conf (Dither_BPC, Dither) or
510 -- FIXME: Should we set these at all?
511 (if Config.Has_Plane_Color_Control then
512 (PIPEMISC_PIXEL_ROUNDING_TRUNC or PIPEMISC_HDR_MODE_PRECISION) else 0));
Nico Huber113a14b2016-12-06 21:59:15 +0100513 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200514 end Setup_Display;
515
516 ----------------------------------------------------------------------------
517
Nico Huber4dc4c612018-01-10 15:55:09 +0100518 procedure Update_Cursor
519 (Pipe : Pipe_Index;
520 FB : Framebuffer_Type;
521 Cursor : Cursor_Type)
522 is
523 begin
524 -- on some platforms writing CUR_CTL disables self-arming of CUR_POS
525 -- so keep it first
526 Registers.Write
Nico Huber75a707f2018-06-18 16:28:33 +0200527 (Register => Cursors (Pipe).CTL,
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600528 Value => CUR_CTL_MODE (Cursor.Mode, Cursor.Size) or
529 (if Config.Need_Pipe_Arb_Slots
530 then MCURSOR_ARB_SLOTS (1)
531 else CUR_CTL_PIPE_SELECT (Pipe)));
Nico Huber1dae2202020-10-05 13:31:25 +0200532 Place_Cursor (Pipe, FB, Cursor, (Cursor.Center_X, Cursor.Center_Y));
Nico Huber4dc4c612018-01-10 15:55:09 +0100533 end Update_Cursor;
534
535 procedure Place_Cursor
536 (Pipe : Pipe_Index;
537 FB : Framebuffer_Type;
Nico Huber1dae2202020-10-05 13:31:25 +0200538 Cursor : Cursor_Type;
539 Center : Cursor_Coord)
Nico Huber4dc4c612018-01-10 15:55:09 +0100540 is
541 Width : constant Width_Type := Cursor_Width (Cursor.Size);
Nico Huber3d7c33f2020-10-01 15:14:38 +0200542
Nico Huber902d8032020-10-05 14:14:16 +0200543 -- Like `Cursor_Pos`/`Cursor_Coord` but allowing wider range for proof.
544 subtype Relaxed_Pos is Int32 range
545 Cursor_Pos'First - Width_Type'Last .. Cursor_Pos'Last + Width_Type'Last;
546 type Relaxed_Coord is record
547 X : Relaxed_Pos;
548 Y : Relaxed_Pos;
549 end record;
550
Nico Huber3d7c33f2020-10-01 15:14:38 +0200551 -- The cursor's coordinates are on the framebuffer surface
552 -- but we need to place it on the physical screen:
Nico Huber902d8032020-10-05 14:14:16 +0200553 function Rotate (Center : Cursor_Coord) return Relaxed_Coord is
554 (X =>
555 (case FB.Rotation is
556 when No_Rotation => Center.X,
557 when Rotated_90 => FB.Height - 1 - Center.Y,
558 when Rotated_180 => FB.Width - 1 - Center.X,
559 when Rotated_270 => Center.Y),
560 Y =>
561 (case FB.Rotation is
562 when No_Rotation => Center.Y,
563 when Rotated_90 => Center.X,
564 when Rotated_180 => FB.Height - 1 - Center.Y,
565 when Rotated_270 => FB.Width - 1 - Center.X));
Nico Huber3d7c33f2020-10-01 15:14:38 +0200566
Nico Huber902d8032020-10-05 14:14:16 +0200567 -- Calculates the coordinates of the cursor plane's
568 -- upper-left corner on the bigger screen (pipe input).
569 function Phys_Origin (Center : Cursor_Coord) return Relaxed_Coord is
570 (X => Rotate (Center).X - Width / 2,
571 Y => Rotate (Center).Y - Width / 2);
572
573 Origin : Relaxed_Coord := Phys_Origin (Center);
Nico Huber4dc4c612018-01-10 15:55:09 +0100574 begin
575 -- off-screen cursor needs special care
Nico Huber902d8032020-10-05 14:14:16 +0200576 if Origin.X <= -Width or Origin.Y <= -Width or
577 Origin.X >= Source_Width (FB) or Origin.Y >= Source_Height (FB) or
578 Origin.X > Config.Maximum_Cursor_X or Origin.Y > Config.Maximum_Cursor_Y
Nico Huber4dc4c612018-01-10 15:55:09 +0100579 then
Nico Huber902d8032020-10-05 14:14:16 +0200580 Origin.X := -Width;
581 Origin.Y := -Width;
Nico Huber4dc4c612018-01-10 15:55:09 +0100582 end if;
583 Registers.Write
Nico Huber75a707f2018-06-18 16:28:33 +0200584 (Register => Cursors (Pipe).POS,
Nico Huber902d8032020-10-05 14:14:16 +0200585 Value => CUR_POS_Y (Origin.Y) or CUR_POS_X (Origin.X),
Nico Huberaae8a352020-06-15 13:09:29 +0200586 Verbose => False);
Nico Huber4dc4c612018-01-10 15:55:09 +0100587 -- write to CUR_BASE always arms other CUR_* registers
588 Registers.Write
Nico Huber75a707f2018-06-18 16:28:33 +0200589 (Register => Cursors (Pipe).BASE,
Nico Huberaae8a352020-06-15 13:09:29 +0200590 Value => Shift_Left (Word32 (Cursor.GTT_Offset), 12),
591 Verbose => False);
Nico Huber4dc4c612018-01-10 15:55:09 +0100592 end Place_Cursor;
593
594 ----------------------------------------------------------------------------
595
Nico Huber4916e342016-11-04 14:37:53 +0100596 procedure Scale_Keep_Aspect
Nico Huberc5c767a2018-06-03 01:09:04 +0200597 (Width : out Width_Type;
598 Height : out Height_Type;
599 Max_Width : in Width_Type;
600 Max_Height : in Height_Type;
Nico Huber4916e342016-11-04 14:37:53 +0100601 Framebuffer : in Framebuffer_Type)
602 with
603 Pre =>
Nico Hubera7e1cd32026-07-03 09:23:24 +0000604 Source_Width (Framebuffer) <= Max_Width and
605 Source_Height (Framebuffer) <= Max_Height,
Nico Huber4916e342016-11-04 14:37:53 +0100606 Post =>
607 Width <= Max_Width and Height <= Max_Height
608 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000609 Src_Width : constant Width_Type := Source_Width (Framebuffer);
610 Src_Height : constant Height_Type := Source_Height (Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100611 begin
Nico Huberda1185e2018-06-03 01:07:46 +0200612 case Scaling_Type (Src_Width, Src_Height, Max_Width, Max_Height) is
613 when Letterbox =>
Nico Huber99200fe2026-04-14 16:37:45 +0200614 Height := (Src_Height * Max_Width) / Src_Width;
615 pragma Assert (Height <= Max_Height);
Nico Huberda1185e2018-06-03 01:07:46 +0200616 Width := Max_Width;
Nico Huberda1185e2018-06-03 01:07:46 +0200617 when Pillarbox =>
Nico Huber99200fe2026-04-14 16:37:45 +0200618 Width := (Src_Width * Max_Height) / Src_Height;
619 pragma Assert (Max_Height * Src_Width < Max_Width * Src_Height);
620 pragma Assert ((Max_Height * Src_Width) / Src_Height < Max_Width);
621 pragma Assert (Width <= Max_Width);
Nico Huberda1185e2018-06-03 01:07:46 +0200622 Height := Max_Height;
623 when Uniform =>
624 Width := Max_Width;
625 Height := Max_Height;
626 end case;
Nico Huber4916e342016-11-04 14:37:53 +0100627 end Scale_Keep_Aspect;
628
Nico Huberba84df22026-06-23 13:29:29 +0000629 procedure Scale
630 (Width : out Width_Type;
631 Height : out Height_Type;
632 Scaling : in GMA.Scaling;
633 Max_Width : in Width_Type;
634 Max_Height : in Height_Type;
635 Framebuffer : in Framebuffer_Type)
636 with
637 Pre =>
Nico Hubera7e1cd32026-07-03 09:23:24 +0000638 Source_Width (Framebuffer) <= Max_Width and
639 Source_Height (Framebuffer) <= Max_Height,
Nico Huberba84df22026-06-23 13:29:29 +0000640 Post =>
641 Width <= Max_Width and Height <= Max_Height
642 is
643 begin
644 case Scaling is
645 when None =>
Nico Hubera7e1cd32026-07-03 09:23:24 +0000646 Width := Source_Width (Framebuffer);
647 Height := Source_Height (Framebuffer);
Nico Huberba84df22026-06-23 13:29:29 +0000648 when Fit =>
649 Scale_Keep_Aspect (Width, Height, Max_Width, Max_Height, Framebuffer);
650 when Stretch =>
651 Width := Max_Width;
652 Height := Max_Height;
653 end case;
654 end Scale;
655
656 procedure Align_Framebuffer
657 (Pos_X : out Position_Type;
658 Pos_Y : out Position_Type;
659 Align : in Alignment;
660 Width : in Width_Type;
661 Height : in Height_Type;
662 Mode : in Mode_Type)
663 with
664 Pre => Width <= Mode.H_Visible and Height <= Mode.V_Visible
665 is
666 Gap_X : constant Position_Type := Mode.H_Visible - Width;
667 Gap_Y : constant Position_Type := Mode.V_Visible - Height;
668 begin
669 case Align is
670 when Top_Left => Pos_X := 0; Pos_Y := 0;
671 when Top => Pos_X := Gap_X / 2; Pos_Y := 0;
672 when Top_Right => Pos_X := Gap_X; Pos_Y := 0;
673 when Left => Pos_X := 0; Pos_Y := Gap_Y / 2;
674 when Center => Pos_X := Gap_X / 2; Pos_Y := Gap_Y / 2;
675 when Right => Pos_X := Gap_X; Pos_Y := Gap_Y / 2;
676 when Bottom_Left => Pos_X := 0; Pos_Y := Gap_Y;
677 when Bottom => Pos_X := Gap_X / 2; Pos_Y := Gap_Y;
678 when Bottom_Right => Pos_X := Gap_X; Pos_Y := Gap_Y;
679 end case;
680 end Align_Framebuffer;
681
Nico Huberfb6dbad2026-04-10 16:23:39 +0000682 type Pipe_Scaler_Limit_Config is record
683 Control : Word32;
684 Horizontal : Pos32;
685 Vertical : Pos32;
686 end record;
687
688 function Skylake_Scaler_Limits
689 (Controller : Controller_Type;
690 Width : Width_Type;
691 Height : Height_Type)
692 return Pipe_Scaler_Limit_Config
693 with
694 Post => Skylake_Scaler_Limits'Result.Horizontal >= Width
695 and Skylake_Scaler_Limits'Result.Vertical >= Height
696 is
697 use type Registers.Registers_Invalid_Index;
698
699 -- Enable 7x5 extended mode where possible:
700 Scaler_Mode : constant Word32 :=
701 (if Controller.PS_CTRL_2 /= Registers.Invalid_Register then
702 PS_CTRL_SCALER_MODE_7X5_EXTENDED else 0);
703
704 -- We can scale up to 2.99x horizontally:
705 Horizontal_Limit : constant Pos32 := (Width * 299) / 100;
706 -- The third scaler is limited to 1.99x
707 -- vertical scaling for source widths > 2048:
708 Vertical_Limit : constant Pos32 :=
709 (Height *
710 (if Controller.PS_CTRL_2 = Registers.Invalid_Register and
711 Width > 2048
712 then
713 199
714 else
715 299)) / 100;
716 begin
717 return (Scaler_Mode, Horizontal_Limit, Vertical_Limit);
718 end Skylake_Scaler_Limits;
719
720 function Tigerlake_Scaler_Limits
721 (Width : Width_Type;
722 Height : Height_Type)
723 return Pipe_Scaler_Limit_Config
724 with
725 Post => Tigerlake_Scaler_Limits'Result.Horizontal >= Width
726 and Tigerlake_Scaler_Limits'Result.Vertical >= Height
727 is
728 Scaling : constant := 32_000; -- PRM says: Scaling * 2**15 >= 1.0
729 -- so virtually unlimited
730 begin
731 return (Control => 0, Horizontal => Width * Scaling, Vertical => Height * Scaling);
732 end Tigerlake_Scaler_Limits;
733
Nico Huber4916e342016-11-04 14:37:53 +0100734 procedure Setup_Skylake_Pipe_Scaler
735 (Controller : in Controller_Type;
Nico Huber4d592b42026-06-23 12:21:37 +0000736 Pipe_Cfg : in Pipe_Config;
737 Mode : in HW.GFX.Mode_Type)
Nico Huber4916e342016-11-04 14:37:53 +0100738 with
739 Pre =>
Nico Huber4d592b42026-06-23 12:21:37 +0000740 Rotated_Width (Pipe_Cfg.Framebuffer) <= Mode.H_Visible and
741 Rotated_Height (Pipe_Cfg.Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100742 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000743 Width_In : constant Width_Type := Source_Width (Pipe_Cfg.Framebuffer);
744 Height_In : constant Height_Type := Source_Height (Pipe_Cfg.Framebuffer);
Nico Huberfb6dbad2026-04-10 16:23:39 +0000745 Limits : constant Pipe_Scaler_Limit_Config :=
746 (if Config.Has_Skylake_Scaler_Limits then
747 Skylake_Scaler_Limits (Controller, Width_In, Height_In)
748 else
749 Tigerlake_Scaler_Limits (Width_In, Height_In));
Nico Huber4916e342016-11-04 14:37:53 +0100750
Nico Huberc5c767a2018-06-03 01:09:04 +0200751 Width : Width_Type;
752 Height : Height_Type;
Nico Huberba84df22026-06-23 13:29:29 +0000753 Pos_X, Pos_Y : Position_Type;
Nico Huber4916e342016-11-04 14:37:53 +0100754 begin
755 -- Writes to WIN_SZ arm the PS registers.
756
Nico Huberba84df22026-06-23 13:29:29 +0000757 Scale
Nico Huber4916e342016-11-04 14:37:53 +0100758 (Width => Width,
759 Height => Height,
Nico Huberba84df22026-06-23 13:29:29 +0000760 Scaling => Pipe_Cfg.Scaling,
Nico Huberfb6dbad2026-04-10 16:23:39 +0000761 Max_Width => Pos32'Min (Limits.Horizontal, Mode.H_Visible),
762 Max_Height => Pos32'Min (Limits.Vertical, Mode.V_Visible),
Nico Huber4d592b42026-06-23 12:21:37 +0000763 Framebuffer => Pipe_Cfg.Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100764
Nico Huberba84df22026-06-23 13:29:29 +0000765 Align_Framebuffer
766 (Pos_X => Pos_X,
767 Pos_Y => Pos_Y,
768 Align => Pipe_Cfg.Alignment,
769 Width => Width,
770 Height => Height,
771 Mode => Mode);
772
Nico Huber4916e342016-11-04 14:37:53 +0100773 Registers.Write
774 (Register => Controller.PS_CTRL_1,
Nico Huberfb6dbad2026-04-10 16:23:39 +0000775 Value => PS_CTRL_ENABLE_SCALER or Limits.Control);
Nico Huber4916e342016-11-04 14:37:53 +0100776 Registers.Write
777 (Register => Controller.PS_WIN_POS_1,
Nico Huberba84df22026-06-23 13:29:29 +0000778 Value => Shift_Left (Word32 (Pos_X), 16) or Word32 (Pos_Y));
Nico Huber4916e342016-11-04 14:37:53 +0100779 Registers.Write
780 (Register => Controller.PS_WIN_SZ_1,
781 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
782 end Setup_Skylake_Pipe_Scaler;
783
784 procedure Setup_Ironlake_Panel_Fitter
785 (Controller : in Controller_Type;
Nico Huber4d592b42026-06-23 12:21:37 +0000786 Pipe_Cfg : in Pipe_Config;
787 Mode : in HW.GFX.Mode_Type)
Nico Huber4916e342016-11-04 14:37:53 +0100788 with
789 Pre =>
Nico Huber4d592b42026-06-23 12:21:37 +0000790 Rotated_Width (Pipe_Cfg.Framebuffer) <= Mode.H_Visible and
791 Rotated_Height (Pipe_Cfg.Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100792 is
793 -- Force 1:1 mapping of panel fitter:pipe
794 PF_Ctrl_Pipe_Sel : constant Word32 :=
795 (if Config.Has_PF_Pipe_Select then
796 (case Controller.PF_CTRL is
797 when Registers.PFA_CTL_1 => 0 * 2 ** 29,
798 when Registers.PFB_CTL_1 => 1 * 2 ** 29,
799 when Registers.PFC_CTL_1 => 2 * 2 ** 29,
800 when others => 0) else 0);
801
Nico Huberc5c767a2018-06-03 01:09:04 +0200802 Width : Width_Type;
803 Height : Height_Type;
Nico Huberba84df22026-06-23 13:29:29 +0000804 Pos_X, Pos_Y : Position_Type;
Nico Huber4916e342016-11-04 14:37:53 +0100805 begin
806 -- Writes to WIN_SZ arm the PF registers.
807
Nico Huberba84df22026-06-23 13:29:29 +0000808 Scale
Nico Huber4916e342016-11-04 14:37:53 +0100809 (Width => Width,
810 Height => Height,
Nico Huberba84df22026-06-23 13:29:29 +0000811 Scaling => Pipe_Cfg.Scaling,
Nico Huberc5c767a2018-06-03 01:09:04 +0200812 Max_Width => Mode.H_Visible,
813 Max_Height => Mode.V_Visible,
Nico Huber4d592b42026-06-23 12:21:37 +0000814 Framebuffer => Pipe_Cfg.Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100815
Nico Huberfdb0df12018-02-07 14:30:34 +0100816 -- Do not scale to odd width (at least Haswell has trouble with this).
Nico Huberc5c767a2018-06-03 01:09:04 +0200817 if Width < Mode.H_Visible and Width mod 2 = 1 then
Nico Huberfdb0df12018-02-07 14:30:34 +0100818 Width := Width + 1;
819 end if;
Nico Huberb3b9fa32018-06-18 16:16:41 +0200820 -- Do not scale to odd height (at least Sandy Bridge makes trouble).
821 if Height < Mode.V_Visible and Height mod 2 = 1 then
822 Height := Height + 1;
823 end if;
Nico Huberfdb0df12018-02-07 14:30:34 +0100824
Nico Huberba84df22026-06-23 13:29:29 +0000825 Align_Framebuffer
826 (Pos_X => Pos_X,
827 Pos_Y => Pos_Y,
828 Align => Pipe_Cfg.Alignment,
829 Width => Width,
830 Height => Height,
831 Mode => Mode);
Nico Huberfdb0df12018-02-07 14:30:34 +0100832
833 -- Hardware is picky about minimal horizontal gaps.
Nico Huberc5c767a2018-06-03 01:09:04 +0200834 if Mode.H_Visible - Width <= 3 then
835 Width := Mode.H_Visible;
Nico Huberba84df22026-06-23 13:29:29 +0000836 Pos_X := 0;
Nico Huberfdb0df12018-02-07 14:30:34 +0100837 end if;
838
Nico Huber4916e342016-11-04 14:37:53 +0100839 Registers.Write
840 (Register => Controller.PF_CTRL,
841 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_CTRL_FILTER_MED);
842 Registers.Write
843 (Register => Controller.PF_WIN_POS,
Nico Huberba84df22026-06-23 13:29:29 +0000844 Value => Shift_Left (Word32 (Pos_X), 16) or Word32 (Pos_Y));
Nico Huber4916e342016-11-04 14:37:53 +0100845 Registers.Write
846 (Register => Controller.PF_WIN_SZ,
847 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
848 end Setup_Ironlake_Panel_Fitter;
849
Arthur Heymansd5198442018-03-28 17:05:12 +0200850 procedure Setup_Gmch_Panel_Fitter
Nico Huber958c5642018-06-02 16:59:31 +0200851 (Controller : in Controller_Type;
852 Mode : in HW.GFX.Mode_Type;
853 Framebuffer : in HW.GFX.Framebuffer_Type)
Arthur Heymansd5198442018-03-28 17:05:12 +0200854 is
855 PF_Ctrl_Pipe_Sel : constant Word32 :=
856 (case Controller.Pipe is
857 when Primary => GMCH_PFIT_CONTROL_SELECT_PIPE_A,
858 when Secondary => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
859 when others => 0);
Nico Huber958c5642018-06-02 16:59:31 +0200860
Arthur Heymansf70edda2018-08-21 18:37:00 +0200861 -- Work around a quirk:
862 -- In legacy VGA mode Pillarbox fails to display anything so just force
863 -- 'auto' mode on all displays, which will the output stretched to
864 -- fullscreen .
Nico Huber958c5642018-06-02 16:59:31 +0200865 PF_Ctrl_Scaling : constant Word32 :=
Arthur Heymansf70edda2018-08-21 18:37:00 +0200866 (if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
867 GMCH_PFIT_CONTROL_SCALING (Uniform)
868 else
869 GMCH_PFIT_CONTROL_SCALING (Scaling_Type (Framebuffer, Mode)));
Nico Huber958c5642018-06-02 16:59:31 +0200870
Arthur Heymansd5198442018-03-28 17:05:12 +0200871 In_Use : Boolean;
872 begin
873 Registers.Is_Set_Mask
874 (Register => Registers.GMCH_PFIT_CONTROL,
875 Mask => PF_CTRL_ENABLE,
876 Result => In_Use);
877
878 if not In_Use then
879 Registers.Write
880 (Register => Registers.GMCH_PFIT_CONTROL,
Nico Huber958c5642018-06-02 16:59:31 +0200881 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_Ctrl_Scaling);
Arthur Heymansd5198442018-03-28 17:05:12 +0200882 else
Nico Huber7ba7bd62018-06-06 12:27:09 +0200883 pragma Debug (Debug.Put_Line
884 ("GMCH Pannel fitter already in use, skipping..."));
Arthur Heymansd5198442018-03-28 17:05:12 +0200885 end if;
886 end Setup_Gmch_Panel_Fitter;
887
Nico Huberf361ec82018-06-02 18:01:45 +0200888 procedure Gmch_Panel_Fitter_Pipe (Pipe : out Pipe_Index)
889 is
890 Used_For_Secondary : Boolean;
891 begin
Arthur Heymans960e2392026-03-03 19:45:24 +0100892 if Config.Gen_I945 then
893 -- Gen3: panel fitter is hardwired to Pipe B (Secondary).
894 -- The PFIT_PIPE field (bits 30:29) does not exist on Gen3.
895 Pipe := Secondary;
896 else
897 Registers.Is_Set_Mask
898 (Register => Registers.GMCH_PFIT_CONTROL,
899 Mask => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
900 Result => Used_For_Secondary);
901 Pipe := (if Used_For_Secondary then Secondary else Primary);
902 end if;
Nico Huberac2a1412026-07-02 10:41:59 +0200903 end Gmch_Panel_Fitter_Pipe;
Nico Huberf361ec82018-06-02 18:01:45 +0200904
Nico Huberb4b72792018-01-02 13:45:41 +0100905 procedure Panel_Fitter_Off (Controller : Controller_Type)
906 is
907 use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
Nico Huberf361ec82018-06-02 18:01:45 +0200908 Pipe_Using_PF : Pipe_Index;
Nico Huberb4b72792018-01-02 13:45:41 +0100909 begin
910 -- Writes to WIN_SZ arm the PS/PF registers.
911 if Config.Has_Plane_Control then
912 Registers.Unset_Mask (Controller.PS_CTRL_1, PS_CTRL_ENABLE_SCALER);
913 Registers.Write (Controller.PS_WIN_SZ_1, 16#0000_0000#);
914 if Controller.PS_CTRL_2 /= Registers.Invalid_Register and
915 Controller.PS_WIN_SZ_2 /= Registers.Invalid_Register
916 then
917 Registers.Unset_Mask (Controller.PS_CTRL_2, PS_CTRL_ENABLE_SCALER);
918 Registers.Write (Controller.PS_WIN_SZ_2, 16#0000_0000#);
919 end if;
Arthur Heymansd5198442018-03-28 17:05:12 +0200920 elsif Config.Has_GMCH_PFIT_CONTROL then
Nico Huberf361ec82018-06-02 18:01:45 +0200921 Gmch_Panel_Fitter_Pipe (Pipe_Using_PF);
922 if Pipe_Using_PF = Controller.Pipe then
Arthur Heymans960e2392026-03-03 19:45:24 +0100923 -- Write 0 to clear all bits (enable, scaling mode, auto-scale,
924 -- interpolation). Just clearing the enable bit can leave stale
925 -- Gen3 auto-scale bits that confuse the hardware.
926 Registers.Write (Registers.GMCH_PFIT_CONTROL, 16#0000_0000#);
Arthur Heymansd5198442018-03-28 17:05:12 +0200927 end if;
Nico Huberb4b72792018-01-02 13:45:41 +0100928 else
929 Registers.Unset_Mask (Controller.PF_CTRL, PF_CTRL_ENABLE);
930 Registers.Write (Controller.PF_WIN_SZ, 16#0000_0000#);
931 end if;
932 end Panel_Fitter_Off;
933
Nico Huber4916e342016-11-04 14:37:53 +0100934 procedure Setup_Scaling
935 (Controller : in Controller_Type;
Nico Huber4d592b42026-06-23 12:21:37 +0000936 Pipe_Cfg : in Pipe_Config;
937 Mode : in HW.GFX.Mode_Type)
Nico Huber4916e342016-11-04 14:37:53 +0100938 with
939 Pre =>
Nico Huber4d592b42026-06-23 12:21:37 +0000940 Rotated_Width (Pipe_Cfg.Framebuffer) <= Mode.H_Visible and
941 Rotated_Height (Pipe_Cfg.Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100942 is
943 begin
Nico Huber4d592b42026-06-23 12:21:37 +0000944 if Requires_Scaling (Pipe_Cfg.Framebuffer, Mode) then
Nico Huber4916e342016-11-04 14:37:53 +0100945 if Config.Has_Plane_Control then
Nico Huber4d592b42026-06-23 12:21:37 +0000946 Setup_Skylake_Pipe_Scaler (Controller, Pipe_Cfg, Mode);
Arthur Heymansd5198442018-03-28 17:05:12 +0200947 elsif Config.Has_GMCH_PFIT_CONTROL then
Nico Huber4d592b42026-06-23 12:21:37 +0000948 Setup_Gmch_Panel_Fitter (Controller, Mode, Pipe_Cfg.Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100949 else
Nico Huber4d592b42026-06-23 12:21:37 +0000950 Setup_Ironlake_Panel_Fitter (Controller, Pipe_Cfg, Mode);
Nico Huber4916e342016-11-04 14:37:53 +0100951 end if;
Nico Huberb4b72792018-01-02 13:45:41 +0100952 else
953 Panel_Fitter_Off (Controller);
Nico Huber4916e342016-11-04 14:37:53 +0100954 end if;
955 end Setup_Scaling;
956
Nico Huber9a4c4c32019-09-16 22:05:11 +0200957 procedure Reserve_Scaler
958 (Success : out Boolean;
959 Reservation : in out Scaler_Reservation;
960 Pipe : in Pipe_Index)
Nico Huberf361ec82018-06-02 18:01:45 +0200961 is
962 Pipe_Using_PF : Pipe_Index := Pipe_Index'First;
963 PF_Enabled : Boolean;
964 begin
965 if Config.Has_GMCH_PFIT_CONTROL then
Nico Huber9a4c4c32019-09-16 22:05:11 +0200966 if Reservation.Reserved then
967 Success := Reservation.Pipe = Pipe;
968 return;
969 end if;
970
Nico Huberf361ec82018-06-02 18:01:45 +0200971 Registers.Is_Set_Mask
972 (Register => Registers.GMCH_PFIT_CONTROL,
973 Mask => PF_CTRL_ENABLE,
974 Result => PF_Enabled);
975 if PF_Enabled then
976 Gmch_Panel_Fitter_Pipe (Pipe_Using_PF);
977 end if;
978
Nico Huber9a4c4c32019-09-16 22:05:11 +0200979 Success := not PF_Enabled or Pipe_Using_PF = Pipe;
980 if Success then
981 Reservation.Reserved := True;
982 Reservation.Pipe := Pipe;
983 end if;
Nico Huberf361ec82018-06-02 18:01:45 +0200984 else
Nico Huber9a4c4c32019-09-16 22:05:11 +0200985 Success := True;
Nico Huberf361ec82018-06-02 18:01:45 +0200986 end if;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200987 end Reserve_Scaler;
Nico Huberf361ec82018-06-02 18:01:45 +0200988
Nico Huber4916e342016-11-04 14:37:53 +0100989 ----------------------------------------------------------------------------
990
Nico Huberf7f537e2018-01-02 14:15:43 +0100991 procedure Setup_FB
992 (Pipe : Pipe_Index;
Nico Huber4d592b42026-06-23 12:21:37 +0000993 Pipe_Cfg : Pipe_Config;
994 Mode : Mode_Type)
Nico Huberf7f537e2018-01-02 14:15:43 +0100995 is
996 -- Enable dithering if framebuffer BPC differs from port BPC,
997 -- as smooth gradients look really bad without.
Nico Huber4d592b42026-06-23 12:21:37 +0000998 Dither : constant Boolean := Pipe_Cfg.Framebuffer.BPC /= Mode.BPC;
Nico Huberf7f537e2018-01-02 14:15:43 +0100999 begin
1000 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
1001
Nico Huber4dc4c612018-01-10 15:55:09 +01001002 -- Disable the cursor first.
Nico Huber4d592b42026-06-23 12:21:37 +00001003 Update_Cursor (Pipe, Pipe_Cfg.Framebuffer, Default_Cursor);
Nico Huber4dc4c612018-01-10 15:55:09 +01001004
Nico Huber4d592b42026-06-23 12:21:37 +00001005 Setup_Display (Controllers (Pipe), Pipe_Cfg.Framebuffer, Mode.BPC, Dither);
1006 Setup_Scaling (Controllers (Pipe), Pipe_Cfg, Mode);
Nico Huberf7f537e2018-01-02 14:15:43 +01001007 end Setup_FB;
1008
Nico Huber83693c82016-10-08 22:17:55 +02001009 procedure On
Nico Huberf3e23662016-12-05 21:33:03 +01001010 (Pipe : Pipe_Index;
Nico Huber4d592b42026-06-23 12:21:37 +00001011 Pipe_Cfg : Pipe_Config;
1012 Port_Cfg : Port_Config)
Nico Huber83693c82016-10-08 22:17:55 +02001013 is
1014 begin
1015 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
1016
Nico Huber7ad2d652016-12-07 15:19:32 +01001017 Transcoder.Setup (Pipe, Port_Cfg);
Nico Huber83693c82016-10-08 22:17:55 +02001018
Nico Huber4d592b42026-06-23 12:21:37 +00001019 Setup_FB (Pipe, Pipe_Cfg, Port_Cfg.Mode);
1020 Update_Cursor (Pipe, Pipe_Cfg.Framebuffer, Pipe_Cfg.Cursor);
Nico Huber83693c82016-10-08 22:17:55 +02001021
Nico Huberabb16d92018-05-29 01:44:26 +02001022 Transcoder.On
1023 (Pipe => Pipe,
1024 Port_Cfg => Port_Cfg,
Nico Huber4d592b42026-06-23 12:21:37 +00001025 Dither => Pipe_Cfg.Framebuffer.BPC /= Port_Cfg.Mode.BPC,
1026 Scale => Requires_Scaling (Pipe_Cfg.Framebuffer, Port_Cfg.Mode));
Nico Huber83693c82016-10-08 22:17:55 +02001027 end On;
1028
1029 ----------------------------------------------------------------------------
1030
Nico Huber75a707f2018-06-18 16:28:33 +02001031 procedure Planes_Off (Controller : Controller_Type; CUR : Cursor_Regs)
1032 is
1033 use type Registers.Registers_Invalid_Index;
Nico Huber83693c82016-10-08 22:17:55 +02001034 begin
Nico Huber75a707f2018-06-18 16:28:33 +02001035 Registers.Write (CUR.CTL, 16#0000_0000#);
1036 if CUR.FBC_CTL /= Registers.Invalid_Register then
1037 Registers.Write (CUR.FBC_CTL, 16#0000_0000#);
Nico Huber4dc4c612018-01-10 15:55:09 +01001038 end if;
Nico Huber07aab5a2020-10-01 15:06:53 +02001039 Registers.Unset_Mask (Controller.PLANE_2_CTL, DSPCNTR_ENABLE);
Nico Huber83693c82016-10-08 22:17:55 +02001040 if Config.Has_Plane_Control then
1041 Clear_Watermarks (Controller);
1042 Registers.Unset_Mask (Controller.PLANE_CTL, PLANE_CTL_PLANE_ENABLE);
1043 Registers.Write (Controller.PLANE_SURF, 16#0000_0000#);
1044 else
1045 Registers.Unset_Mask (Controller.DSPCNTR, DSPCNTR_ENABLE);
1046 end if;
1047 end Planes_Off;
1048
Nico Huber7ad2d652016-12-07 15:19:32 +01001049 procedure Off (Pipe : Pipe_Index)
Nico Huberf3e23662016-12-05 21:33:03 +01001050 is
Nico Huber83693c82016-10-08 22:17:55 +02001051 begin
1052 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
1053
Nico Huber75a707f2018-06-18 16:28:33 +02001054 Planes_Off (Controllers (Pipe), Cursors (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +01001055 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +01001056 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +01001057 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +02001058 end Off;
1059
Nico Huber33912aa2016-12-06 20:36:23 +01001060 procedure Legacy_VGA_Off
1061 is
1062 use type HW.Word8;
1063 Reg8 : Word8;
1064 begin
1065 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
1066 Port_IO.InB (Reg8, VGA_SR_DATA);
1067 Port_IO.OutB (VGA_SR_DATA, Reg8 or VGA_SR01_SCREEN_OFF);
1068 Time.U_Delay (100); -- PRM says 100us, Linux does 300
Arthur Heymansdfcdd772018-03-28 16:42:50 +02001069 Registers.Set_Mask (VGACNTRL_REG, VGA_CONTROL_VGA_DISPLAY_DISABLE);
Nico Huber33912aa2016-12-06 20:36:23 +01001070 end Legacy_VGA_Off;
1071
Nico Huber83693c82016-10-08 22:17:55 +02001072 procedure All_Off
1073 is
Nico Huber83693c82016-10-08 22:17:55 +02001074 begin
1075 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
1076
Nico Huber33912aa2016-12-06 20:36:23 +01001077 Legacy_VGA_Off;
1078
Arthur Heymans960e2392026-03-03 19:45:24 +01001079 for Pipe in Pipe_Index range Pipe_Index'First .. Config.Max_Pipe loop
Nico Huber75a707f2018-06-18 16:28:33 +02001080 Planes_Off (Controllers (Pipe), Cursors (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +01001081 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +01001082 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +01001083 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +02001084 end loop;
Nico Huber83693c82016-10-08 22:17:55 +02001085 end All_Off;
1086
Nico Huber83693c82016-10-08 22:17:55 +02001087end HW.GFX.GMA.Pipe_Setup;