blob: 8975778a54963d8d680127a9d9298e65d3ec71e7 [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 Huberfb6dbad2026-04-10 16:23:39 +0000163 function Encode_Size (LSW, MSW : Word32) return Word32
164 is
165 (Shift_Left (MSW - 1, 16) or (LSW - 1));
166
167 function Prepare_Source_Width (Framebuffer : Framebuffer_Type) return Word32
168 is
169 (if Config.Needs_Even_Source_Width then
170 Word32 (Rotated_Width (Framebuffer)) and not 1
171 else
172 Word32 (Rotated_Width (Framebuffer)));
173
174 function Prepare_Source_Height (Framebuffer : Framebuffer_Type) return Word32
175 is
176 (Word32 (Rotated_Height (Framebuffer)));
Nico Huber83693c82016-10-08 22:17:55 +0200177
178 ----------------------------------------------------------------------------
179
Nico Huber83693c82016-10-08 22:17:55 +0200180 procedure Clear_Watermarks (Controller : Controller_Type) is
181 begin
Nico Huber4dc4c612018-01-10 15:55:09 +0100182 Registers.Write (Controller.CUR_BUF_CFG, 16#0000_0000#);
183 for Level in WM_Levels loop
184 Registers.Write (Controller.CUR_WM (Level), 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200185 end loop;
Nico Huber4dc4c612018-01-10 15:55:09 +0100186 Registers.Write (Controller.PLANE_BUF_CFG, 16#0000_0000#);
187 for Level in WM_Levels loop
188 Registers.Write (Controller.PLANE_WM (Level), 16#0000_0000#);
189 end loop;
190 Registers.Write (Controller.WM_LINETIME, 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200191 end Clear_Watermarks;
192
193 procedure Setup_Watermarks (Controller : Controller_Type)
194 is
Nico Huberf3e23662016-12-05 21:33:03 +0100195 type Per_Plane_Buffer_Range is array (Pipe_Index) of Word32;
Nico Huber4dc4c612018-01-10 15:55:09 +0100196 Cur_Buffer_Range : constant Per_Plane_Buffer_Range :=
197 (Primary => Shift_Left ( 7, 16) or 0,
198 Secondary => Shift_Left (167, 16) or 160,
199 Tertiary => Shift_Left (327, 16) or 320);
200 Plane_Buffer_Range : constant Per_Plane_Buffer_Range :=
201 (Primary => Shift_Left (159, 16) or 8,
202 Secondary => Shift_Left (319, 16) or 168,
203 Tertiary => Shift_Left (479, 16) or 328);
Nico Huber83693c82016-10-08 22:17:55 +0200204 begin
205 Registers.Write
206 (Register => Controller.PLANE_BUF_CFG,
Nico Huber4dc4c612018-01-10 15:55:09 +0100207 Value => Plane_Buffer_Range (Controller.Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200208 Registers.Write
209 (Register => Controller.PLANE_WM (0),
210 Value => PLANE_WM_ENABLE or
211 PLANE_WM_LINES (2) or
Nico Huber4dc4c612018-01-10 15:55:09 +0100212 PLANE_WM_BLOCKS (152));
213 Registers.Write
214 (Register => Controller.CUR_BUF_CFG,
215 Value => Cur_Buffer_Range (Controller.Pipe));
216 Registers.Write
217 (Register => Controller.CUR_WM (0),
218 Value => PLANE_WM_ENABLE or
219 PLANE_WM_LINES (2) or
220 PLANE_WM_BLOCKS (8));
Nico Huber83693c82016-10-08 22:17:55 +0200221 end Setup_Watermarks;
222
223 ----------------------------------------------------------------------------
224
Nico Huber3675db52016-11-04 16:27:29 +0100225 procedure Setup_Hires_Plane
Nico Huber6a4dfc82016-11-04 15:50:58 +0100226 (Controller : Controller_Type;
Nico Huber0164b022017-08-24 15:12:51 +0200227 FB : HW.GFX.Framebuffer_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200228 with
Nico Huber5ef4d602017-12-13 13:56:47 +0100229 Pre => FB.Height + FB.Start_Y <= FB.V_Stride
Nico Huber83693c82016-10-08 22:17:55 +0200230 is
Nico Huberfb6dbad2026-04-10 16:23:39 +0000231 Width : constant Word32 := Prepare_Source_Width (FB);
232 Height : constant Word32 := Prepare_Source_Height (FB);
233
Nico Huber83693c82016-10-08 22:17:55 +0200234 -- FIXME: setup correct format, based on framebuffer RGB format
235 Format : constant Word32 := 6 * 2 ** 26;
Arthur Heymans960e2392026-03-03 19:45:24 +0100236 PRI : Word32 := Format;
Nico Huber83693c82016-10-08 22:17:55 +0200237 begin
238 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
239
Nico Huber83693c82016-10-08 22:17:55 +0200240 if Config.Has_Plane_Control then
Nico Huber9b479412017-08-27 11:55:56 +0200241 declare
Nico Huber34be6542017-12-13 09:26:24 +0100242 Stride, Offset : Word32;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600243
244 function PLANE_CTL_ARB_SLOTS (N : Word32) return Word32 is
245 (if Config.Need_Pipe_Arb_Slots then Shift_Left (N, 28) else 0);
246
247 -- TODO: Hard coded format and arbitration slots for now,
248 -- for 4B-per-pixel XRGB, just like `Format` above.
249 -- ARB_SLOTS(1) matches the 4B per pixel.
250 Plane_Ctl : constant Word32 :=
251 PLANE_CTL_PLANE_ENABLE or
252 PLANE_CTL_TILED_SURFACE (FB.Tiling) or
253 PLANE_CTL_PLANE_ROTATION (FB.Rotation) or
254 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
255 PLANE_CTL_ARB_SLOTS (1) or
256 (if not Config.Has_Plane_Color_Control
257 then PLANE_CTL_PLANE_GAMMA_DISABLE
258 else 0);
Nico Huber9b479412017-08-27 11:55:56 +0200259 begin
260 if Rotation_90 (FB) then
Nico Huber5ef4d602017-12-13 13:56:47 +0100261 Stride := Word32 (FB_Pitch (FB.V_Stride, FB));
262 Offset := Shift_Left (Word32 (FB.Start_X), 16) or
263 Word32 (FB.V_Stride - FB.Height - FB.Start_Y);
Nico Huber9b479412017-08-27 11:55:56 +0200264 else
Nico Huber5ef4d602017-12-13 13:56:47 +0100265 Stride := Word32 (FB_Pitch (FB.Stride, FB));
266 Offset := Shift_Left (Word32 (FB.Start_Y), 16) or
267 Word32 (FB.Start_X);
Nico Huber9b479412017-08-27 11:55:56 +0200268 end if;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600269
270 if Config.Has_Plane_Color_Control then
271 Registers.Write
272 (Register => Controller.PLANE_COLOR_CTL,
273 Value => PLANE_COLOR_CTL_PLANE_GAMMA_DISABLE);
274 end if;
275 Registers.Write (Controller.PLANE_AUX_DIST, 0);
276 Registers.Write (Controller.PLANE_CTL, Plane_Ctl);
Nico Huber9b479412017-08-27 11:55:56 +0200277 Registers.Write (Controller.PLANE_OFFSET, Offset);
Nico Huberfb6dbad2026-04-10 16:23:39 +0000278 Registers.Write (Controller.PLANE_SIZE, Encode_Size (Width, Height));
Nico Huber9b479412017-08-27 11:55:56 +0200279 Registers.Write (Controller.PLANE_STRIDE, Stride);
280 Registers.Write (Controller.PLANE_POS, 16#0000_0000#);
Nico Huber34be6542017-12-13 09:26:24 +0100281 Registers.Write (Controller.PLANE_SURF, FB.Offset and 16#ffff_f000#);
Nico Huber9b479412017-08-27 11:55:56 +0200282 end;
Nico Huber83693c82016-10-08 22:17:55 +0200283 else
Arthur Heymans960e2392026-03-03 19:45:24 +0100284 if Config.Has_DSPCNTR_Pipe_Select then
285 PRI := PRI or DSPCNTR_PIPE_SEL (Controller.Pipe);
286 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200287 if Config.Disable_Trickle_Feed then
288 PRI := PRI or DSPCNTR_DISABLE_TRICKLE_FEED;
289 end if;
Arthur Heymans960e2392026-03-03 19:45:24 +0100290
291 -- Write DSPCNTR *without* the enable bit first. On pre-SKL
292 -- hardware the control register self-arms when the plane
293 -- transitions from disabled to enabled, latching whatever
294 -- stride/size/offset values happen to be in the registers at
295 -- that moment. Programming format, pipe-select, and trickle-
296 -- feed now avoids a glitch with stale geometry values.
Nico Huber83693c82016-10-08 22:17:55 +0200297 Registers.Unset_And_Set_Mask
298 (Register => Controller.DSPCNTR,
299 Mask_Unset => DSPCNTR_MASK,
Nico Huberab69e362018-05-29 21:20:30 +0200300 Mask_Set => PRI or DSPCNTR_TILED_SURFACE (FB.Tiling));
Nico Huber83693c82016-10-08 22:17:55 +0200301
Nico Huber0164b022017-08-24 15:12:51 +0200302 Registers.Write
303 (Controller.DSPSTRIDE, Word32 (Pixel_To_Bytes (FB.Stride, FB)));
Arthur Heymans960e2392026-03-03 19:45:24 +0100304
305 -- Gen3 (i945): program DSPSIZE and DSPPOS before the surface
306 -- address write that arms the double-buffered plane registers.
307 if Config.Gen_I945 then
Nico Huberfb6dbad2026-04-10 16:23:39 +0000308 Registers.Write (Controller.DSPSIZE, Encode_Size (Width, Height));
Arthur Heymans960e2392026-03-03 19:45:24 +0100309 Registers.Write (Controller.DSPPOS, 16#0000_0000#);
310 end if;
311
Nico Huberab69e362018-05-29 21:20:30 +0200312 if Config.Has_DSP_Linoff and then FB.Tiling = Linear then
Arthur Heymans3f37cce2026-03-03 18:52:12 +0100313 pragma Assert_And_Cut
314 (FB.Start_Y * FB.Stride + FB.Start_X in Pixel_Type);
Nico Huberd49b56b2018-06-18 17:19:15 +0200315 declare
316 Linear_Offset : constant Pixel_Type :=
317 FB.Start_Y * FB.Stride + FB.Start_X;
318 begin
319 Registers.Write
320 (Register => Controller.DSPLINOFF,
Arthur Heymans960e2392026-03-03 19:45:24 +0100321 Value => (if Config.Has_DSPSURF
322 then Word32 (Pixel_To_Bytes (Linear_Offset, FB))
323 else (FB.Offset and 16#ffff_f000#) or
324 Word32 (Pixel_To_Bytes (Linear_Offset, FB))));
Nico Huberd49b56b2018-06-18 17:19:15 +0200325 Registers.Write (Controller.DSPTILEOFF, 0);
326 end;
Nico Huber5ef4d602017-12-13 13:56:47 +0100327 else
Nico Huberab69e362018-05-29 21:20:30 +0200328 if Config.Has_DSP_Linoff then
Arthur Heymans960e2392026-03-03 19:45:24 +0100329 Registers.Write (Controller.DSPLINOFF,
330 (if Config.Has_DSPSURF then 0
331 else FB.Offset and 16#ffff_f000#));
Nico Huberab69e362018-05-29 21:20:30 +0200332 end if;
Nico Huber5ef4d602017-12-13 13:56:47 +0100333 Registers.Write
334 (Register => Controller.DSPTILEOFF,
335 Value => Shift_Left (Word32 (FB.Start_Y), 16) or
336 Word32 (FB.Start_X));
Nico Huber83693c82016-10-08 22:17:55 +0200337 end if;
Arthur Heymans960e2392026-03-03 19:45:24 +0100338 if Config.Has_DSPSURF then
339 Registers.Write (Controller.DSPSURF, FB.Offset and 16#ffff_f000#);
340 end if;
341
342 -- Now enable the plane. All geometry registers are in place,
343 -- so the self-arm latches correct values.
344 Registers.Write
345 (Register => Controller.DSPCNTR,
346 Value => DSPCNTR_ENABLE or PRI or
347 DSPCNTR_TILED_SURFACE (FB.Tiling));
Nico Huber83693c82016-10-08 22:17:55 +0200348 end if;
Nico Huber3675db52016-11-04 16:27:29 +0100349 end Setup_Hires_Plane;
350
351 procedure Setup_Display
Nico Huber113a14b2016-12-06 21:59:15 +0100352 (Controller : Controller_Type;
353 Framebuffer : Framebuffer_Type;
354 Dither_BPC : BPC_Type;
355 Dither : Boolean)
Nico Huber3675db52016-11-04 16:27:29 +0100356 with
Nico Huber9b479412017-08-27 11:55:56 +0200357 Pre =>
358 Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
Nico Huber5ef4d602017-12-13 13:56:47 +0100359 Framebuffer.Height + Framebuffer.Start_Y <= Framebuffer.V_Stride
Nico Huber3675db52016-11-04 16:27:29 +0100360 is
361 use type Word8;
362
363 Reg8 : Word8;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600364
365 type BW_Credit is new Natural range 0 .. 3;
366 function MBUS_DBOX_BW_CREDIT (C : BW_Credit) return Word32 is
367 (Shift_Left (Word32 (C), 14));
368
369 type B_Credit is new Natural range 0 .. 31;
370 function MBUS_DBOX_B_CREDIT (C : B_Credit) return Word32 is
371 (Shift_Left (Word32 (C), 8));
372
373 type A_Credit is new Natural range 0 .. 15;
374 function MBUS_DBOX_A_CREDIT (C : A_Credit) return Word32 is
375 (Word32 (C));
376
377 type B2B_Trans_Max is new Natural range 0 .. 31;
378 function MBUS_DBOX_B2B_TRANSACTIONS_MAX (B : B2B_Trans_Max) return Word32 is
379 (Shift_Left (Word32 (B), 20));
380
381 type B2B_Trans_Delay is new Natural range 0 .. 7;
382 function MBUS_DBOX_B2B_TRANSACTIONS_DELAY (B : B2B_Trans_Delay) return Word32 is
383 (Shift_Left (Word32 (B), 17));
384 MBUS_DBOX_REGULATE_B2B_TRANSACTIONS_EN : constant := 1 * 2 ** 16;
385
386 procedure Program_Mbus_Dbox_Credits is
387 Tmp : Word32;
388 begin
389 Tmp := MBUS_DBOX_B2B_TRANSACTIONS_MAX (16) or
390 MBUS_DBOX_B2B_TRANSACTIONS_DELAY (1) or
391 MBUS_DBOX_REGULATE_B2B_TRANSACTIONS_EN;
392
393 if Config.Has_New_Mbus_Dbox_Credits then
394 Tmp := Tmp or MBUS_DBOX_BW_CREDIT (2) or
395 MBUS_DBOX_B_CREDIT (8) or
396 MBUS_DBOX_A_CREDIT (4); -- No joined MBus support,
397 -- hence always use 4 for now.
398 else
399 Tmp := Tmp or MBUS_DBOX_BW_CREDIT (2) or
400 MBUS_DBOX_B_CREDIT (12) or
401 MBUS_DBOX_A_CREDIT (2);
402 end if;
403
404 Registers.Write
405 (Register => Controller.MBUS_DBOX_CTL,
406 Value => Tmp);
407 end Program_Mbus_Dbox_Credits;
408
409 -- Display WA # 1605353570: icl
410 -- Set the pixel rounding bit to 1 for allowing
411 -- passthrough of Frame buffer pixels unmodified
412 -- across pipe
413 PIXEL_ROUNDING_TRUNC_FB_PASSTHRU : constant := 1 * 2 ** 15;
414
415 -- Display WA #1153: icl
416 -- enable hardware to bypass the alpha math
417 -- and rounding for per-pixel values 00 and 0xff
418 PER_PIXEL_ALPHA_BYPASS_EN : constant := 1 * 2 ** 7;
419
420 -- ADL_P requires that we disable underrun recovery when
421 -- downscaling (or using the scaler for YUV420 pipe output),
422 -- using DSC, or using PSR2.
423 -- i915 always disables underrun recovery for gen 13+.
424 UNDERRUN_RECOVERY_DISABLE : constant := 1 * 2 ** 30;
Nico Huberfb6dbad2026-04-10 16:23:39 +0000425
426 Width : constant Word32 := Prepare_Source_Width (Framebuffer);
427 Height : constant Word32 := Prepare_Source_Height (Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100428 begin
429 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
430
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600431 if Config.Has_Type_C_Ports then
432 Registers.Set_Mask
433 (Register => Controller.PIPE_CHICKEN,
434 Mask => PER_PIXEL_ALPHA_BYPASS_EN or
435 PIXEL_ROUNDING_TRUNC_FB_PASSTHRU or
436 (if Config.Need_Underrun_Rec_Disable
437 then UNDERRUN_RECOVERY_DISABLE
438 else 0));
439 end if;
440
Nico Huber3675db52016-11-04 16:27:29 +0100441 if Config.Has_Plane_Control then
442 Setup_Watermarks (Controller);
443 end if;
444
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600445 if Config.Has_Mbus_Dbox_Credits then
446 Program_Mbus_Dbox_Credits;
447 end if;
448
Nico Huber3675db52016-11-04 16:27:29 +0100449 if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
Nico Huberfbb42202016-11-07 15:08:26 +0100450 if Config.VGA_Plane_Workaround then
451 Registers.Unset_And_Set_Mask
452 (Register => Registers.ILK_DISPLAY_CHICKEN1,
453 Mask_Unset => ILK_DISPLAY_CHICKEN1_VGA_MASK,
454 Mask_Set => ILK_DISPLAY_CHICKEN1_VGA_ENABLE);
455 Registers.Unset_And_Set_Mask
456 (Register => Registers.ILK_DISPLAY_CHICKEN2,
457 Mask_Unset => ILK_DISPLAY_CHICKEN2_VGA_MASK,
458 Mask_Set => ILK_DISPLAY_CHICKEN2_VGA_ENABLE);
459 end if;
460
Nico Huber3675db52016-11-04 16:27:29 +0100461 Registers.Unset_And_Set_Mask
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200462 (Register => VGACNTRL_REG,
Nico Huber3675db52016-11-04 16:27:29 +0100463 Mask_Unset => VGA_CONTROL_VGA_DISPLAY_DISABLE or
464 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK or
465 VGA_CONTROL_VSYNC_BLINK_RATE_MASK,
466 Mask_Set => VGA_CONTROL_BLINK_DUTY_CYCLE_50 or
467 VGA_CONTROL_VSYNC_BLINK_RATE (30));
468
469 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
470 Port_IO.InB (Reg8, VGA_SR_DATA);
471 Port_IO.OutB (VGA_SR_DATA, Reg8 and not (VGA_SR01_SCREEN_OFF));
472 else
Nico Huber6a4dfc82016-11-04 15:50:58 +0100473 Setup_Hires_Plane (Controller, Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100474 end if;
475
476 Registers.Write
477 (Register => Controller.PIPESRC,
Nico Huberfb6dbad2026-04-10 16:23:39 +0000478 Value => Encode_Size (Height, Width));
Nico Huber83693c82016-10-08 22:17:55 +0200479
Nico Huber113a14b2016-12-06 21:59:15 +0100480 if Config.Has_Pipeconf_Misc then
481 Registers.Write
482 (Register => Controller.PIPEMISC,
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600483 Value => Transcoder.BPC_Conf (Dither_BPC, Dither) or
484 -- FIXME: Should we set these at all?
485 (if Config.Has_Plane_Color_Control then
486 (PIPEMISC_PIXEL_ROUNDING_TRUNC or PIPEMISC_HDR_MODE_PRECISION) else 0));
Nico Huber113a14b2016-12-06 21:59:15 +0100487 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200488 end Setup_Display;
489
490 ----------------------------------------------------------------------------
491
Nico Huber4dc4c612018-01-10 15:55:09 +0100492 procedure Update_Cursor
493 (Pipe : Pipe_Index;
494 FB : Framebuffer_Type;
495 Cursor : Cursor_Type)
496 is
497 begin
498 -- on some platforms writing CUR_CTL disables self-arming of CUR_POS
499 -- so keep it first
500 Registers.Write
Nico Huber75a707f2018-06-18 16:28:33 +0200501 (Register => Cursors (Pipe).CTL,
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600502 Value => CUR_CTL_MODE (Cursor.Mode, Cursor.Size) or
503 (if Config.Need_Pipe_Arb_Slots
504 then MCURSOR_ARB_SLOTS (1)
505 else CUR_CTL_PIPE_SELECT (Pipe)));
Nico Huber4dc4c612018-01-10 15:55:09 +0100506 Place_Cursor (Pipe, FB, Cursor);
507 end Update_Cursor;
508
509 procedure Place_Cursor
510 (Pipe : Pipe_Index;
511 FB : Framebuffer_Type;
512 Cursor : Cursor_Type)
513 is
514 Width : constant Width_Type := Cursor_Width (Cursor.Size);
515 X : Int32 := Cursor.Center_X - Width / 2;
516 Y : Int32 := Cursor.Center_Y - Width / 2;
517 begin
518 -- off-screen cursor needs special care
519 if X <= -Width or Y <= -Width or
Nico Huberc5c767a2018-06-03 01:09:04 +0200520 X >= Rotated_Width (FB) or Y >= Rotated_Height (FB) or
Nico Huber4dc4c612018-01-10 15:55:09 +0100521 X > Config.Maximum_Cursor_X or Y > Config.Maximum_Cursor_Y
522 then
523 X := -Width;
524 Y := -Width;
525 end if;
526 Registers.Write
Nico Huber75a707f2018-06-18 16:28:33 +0200527 (Register => Cursors (Pipe).POS,
Nico Huber4dc4c612018-01-10 15:55:09 +0100528 Value => CUR_POS_Y (Y) or CUR_POS_X (X));
529 -- write to CUR_BASE always arms other CUR_* registers
530 Registers.Write
Nico Huber75a707f2018-06-18 16:28:33 +0200531 (Register => Cursors (Pipe).BASE,
Nico Huber4dc4c612018-01-10 15:55:09 +0100532 Value => Shift_Left (Word32 (Cursor.GTT_Offset), 12));
533 end Place_Cursor;
534
535 ----------------------------------------------------------------------------
536
Nico Huber4916e342016-11-04 14:37:53 +0100537 procedure Scale_Keep_Aspect
Nico Huberc5c767a2018-06-03 01:09:04 +0200538 (Width : out Width_Type;
539 Height : out Height_Type;
540 Max_Width : in Width_Type;
541 Max_Height : in Height_Type;
Nico Huber4916e342016-11-04 14:37:53 +0100542 Framebuffer : in Framebuffer_Type)
543 with
544 Pre =>
Nico Huberc5c767a2018-06-03 01:09:04 +0200545 Rotated_Width (Framebuffer) <= Max_Width and
546 Rotated_Height (Framebuffer) <= Max_Height,
Nico Huber4916e342016-11-04 14:37:53 +0100547 Post =>
548 Width <= Max_Width and Height <= Max_Height
549 is
Nico Huberc5c767a2018-06-03 01:09:04 +0200550 Src_Width : constant Width_Type := Rotated_Width (Framebuffer);
551 Src_Height : constant Height_Type := Rotated_Height (Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100552 begin
Nico Huberda1185e2018-06-03 01:07:46 +0200553 case Scaling_Type (Src_Width, Src_Height, Max_Width, Max_Height) is
554 when Letterbox =>
Nico Huber99200fe2026-04-14 16:37:45 +0200555 Height := (Src_Height * Max_Width) / Src_Width;
556 pragma Assert (Height <= Max_Height);
Nico Huberda1185e2018-06-03 01:07:46 +0200557 Width := Max_Width;
Nico Huberda1185e2018-06-03 01:07:46 +0200558 when Pillarbox =>
Nico Huber99200fe2026-04-14 16:37:45 +0200559 Width := (Src_Width * Max_Height) / Src_Height;
560 pragma Assert (Max_Height * Src_Width < Max_Width * Src_Height);
561 pragma Assert ((Max_Height * Src_Width) / Src_Height < Max_Width);
562 pragma Assert (Width <= Max_Width);
Nico Huberda1185e2018-06-03 01:07:46 +0200563 Height := Max_Height;
564 when Uniform =>
565 Width := Max_Width;
566 Height := Max_Height;
567 end case;
Nico Huber4916e342016-11-04 14:37:53 +0100568 end Scale_Keep_Aspect;
569
Nico Huberfb6dbad2026-04-10 16:23:39 +0000570 type Pipe_Scaler_Limit_Config is record
571 Control : Word32;
572 Horizontal : Pos32;
573 Vertical : Pos32;
574 end record;
575
576 function Skylake_Scaler_Limits
577 (Controller : Controller_Type;
578 Width : Width_Type;
579 Height : Height_Type)
580 return Pipe_Scaler_Limit_Config
581 with
582 Post => Skylake_Scaler_Limits'Result.Horizontal >= Width
583 and Skylake_Scaler_Limits'Result.Vertical >= Height
584 is
585 use type Registers.Registers_Invalid_Index;
586
587 -- Enable 7x5 extended mode where possible:
588 Scaler_Mode : constant Word32 :=
589 (if Controller.PS_CTRL_2 /= Registers.Invalid_Register then
590 PS_CTRL_SCALER_MODE_7X5_EXTENDED else 0);
591
592 -- We can scale up to 2.99x horizontally:
593 Horizontal_Limit : constant Pos32 := (Width * 299) / 100;
594 -- The third scaler is limited to 1.99x
595 -- vertical scaling for source widths > 2048:
596 Vertical_Limit : constant Pos32 :=
597 (Height *
598 (if Controller.PS_CTRL_2 = Registers.Invalid_Register and
599 Width > 2048
600 then
601 199
602 else
603 299)) / 100;
604 begin
605 return (Scaler_Mode, Horizontal_Limit, Vertical_Limit);
606 end Skylake_Scaler_Limits;
607
608 function Tigerlake_Scaler_Limits
609 (Width : Width_Type;
610 Height : Height_Type)
611 return Pipe_Scaler_Limit_Config
612 with
613 Post => Tigerlake_Scaler_Limits'Result.Horizontal >= Width
614 and Tigerlake_Scaler_Limits'Result.Vertical >= Height
615 is
616 Scaling : constant := 32_000; -- PRM says: Scaling * 2**15 >= 1.0
617 -- so virtually unlimited
618 begin
619 return (Control => 0, Horizontal => Width * Scaling, Vertical => Height * Scaling);
620 end Tigerlake_Scaler_Limits;
621
Nico Huber4916e342016-11-04 14:37:53 +0100622 procedure Setup_Skylake_Pipe_Scaler
623 (Controller : in Controller_Type;
624 Mode : in HW.GFX.Mode_Type;
625 Framebuffer : in HW.GFX.Framebuffer_Type)
626 with
627 Pre =>
Nico Huber9b479412017-08-27 11:55:56 +0200628 Rotated_Width (Framebuffer) <= Mode.H_Visible and
629 Rotated_Height (Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100630 is
Nico Huberc5c767a2018-06-03 01:09:04 +0200631 Width_In : constant Width_Type := Rotated_Width (Framebuffer);
632 Height_In : constant Height_Type := Rotated_Height (Framebuffer);
Nico Huberfb6dbad2026-04-10 16:23:39 +0000633 Limits : constant Pipe_Scaler_Limit_Config :=
634 (if Config.Has_Skylake_Scaler_Limits then
635 Skylake_Scaler_Limits (Controller, Width_In, Height_In)
636 else
637 Tigerlake_Scaler_Limits (Width_In, Height_In));
Nico Huber4916e342016-11-04 14:37:53 +0100638
Nico Huberc5c767a2018-06-03 01:09:04 +0200639 Width : Width_Type;
640 Height : Height_Type;
Nico Huber4916e342016-11-04 14:37:53 +0100641 begin
642 -- Writes to WIN_SZ arm the PS registers.
643
644 Scale_Keep_Aspect
645 (Width => Width,
646 Height => Height,
Nico Huberfb6dbad2026-04-10 16:23:39 +0000647 Max_Width => Pos32'Min (Limits.Horizontal, Mode.H_Visible),
648 Max_Height => Pos32'Min (Limits.Vertical, Mode.V_Visible),
Nico Huber4916e342016-11-04 14:37:53 +0100649 Framebuffer => Framebuffer);
650
651 Registers.Write
652 (Register => Controller.PS_CTRL_1,
Nico Huberfb6dbad2026-04-10 16:23:39 +0000653 Value => PS_CTRL_ENABLE_SCALER or Limits.Control);
Nico Huber4916e342016-11-04 14:37:53 +0100654 Registers.Write
655 (Register => Controller.PS_WIN_POS_1,
656 Value =>
Nico Huberc5c767a2018-06-03 01:09:04 +0200657 Shift_Left (Word32 (Mode.H_Visible - Width) / 2, 16) or
658 Word32 (Mode.V_Visible - Height) / 2);
Nico Huber4916e342016-11-04 14:37:53 +0100659 Registers.Write
660 (Register => Controller.PS_WIN_SZ_1,
661 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
662 end Setup_Skylake_Pipe_Scaler;
663
664 procedure Setup_Ironlake_Panel_Fitter
665 (Controller : in Controller_Type;
666 Mode : in HW.GFX.Mode_Type;
667 Framebuffer : in HW.GFX.Framebuffer_Type)
668 with
669 Pre =>
Nico Huber9b479412017-08-27 11:55:56 +0200670 Rotated_Width (Framebuffer) <= Mode.H_Visible and
671 Rotated_Height (Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100672 is
673 -- Force 1:1 mapping of panel fitter:pipe
674 PF_Ctrl_Pipe_Sel : constant Word32 :=
675 (if Config.Has_PF_Pipe_Select then
676 (case Controller.PF_CTRL is
677 when Registers.PFA_CTL_1 => 0 * 2 ** 29,
678 when Registers.PFB_CTL_1 => 1 * 2 ** 29,
679 when Registers.PFC_CTL_1 => 2 * 2 ** 29,
680 when others => 0) else 0);
681
Nico Huberc5c767a2018-06-03 01:09:04 +0200682 Width : Width_Type;
683 Height : Height_Type;
Nico Huberfdb0df12018-02-07 14:30:34 +0100684 X, Y : Int32;
Nico Huber4916e342016-11-04 14:37:53 +0100685 begin
686 -- Writes to WIN_SZ arm the PF registers.
687
688 Scale_Keep_Aspect
689 (Width => Width,
690 Height => Height,
Nico Huberc5c767a2018-06-03 01:09:04 +0200691 Max_Width => Mode.H_Visible,
692 Max_Height => Mode.V_Visible,
Nico Huber4916e342016-11-04 14:37:53 +0100693 Framebuffer => Framebuffer);
694
Nico Huberfdb0df12018-02-07 14:30:34 +0100695 -- Do not scale to odd width (at least Haswell has trouble with this).
Nico Huberc5c767a2018-06-03 01:09:04 +0200696 if Width < Mode.H_Visible and Width mod 2 = 1 then
Nico Huberfdb0df12018-02-07 14:30:34 +0100697 Width := Width + 1;
698 end if;
Nico Huberb3b9fa32018-06-18 16:16:41 +0200699 -- Do not scale to odd height (at least Sandy Bridge makes trouble).
700 if Height < Mode.V_Visible and Height mod 2 = 1 then
701 Height := Height + 1;
702 end if;
Nico Huberfdb0df12018-02-07 14:30:34 +0100703
Nico Huberc5c767a2018-06-03 01:09:04 +0200704 X := (Mode.H_Visible - Width) / 2;
705 Y := (Mode.V_Visible - Height) / 2;
Nico Huberfdb0df12018-02-07 14:30:34 +0100706
707 -- Hardware is picky about minimal horizontal gaps.
Nico Huberc5c767a2018-06-03 01:09:04 +0200708 if Mode.H_Visible - Width <= 3 then
709 Width := Mode.H_Visible;
Nico Huberfdb0df12018-02-07 14:30:34 +0100710 X := 0;
711 end if;
712
Nico Huber4916e342016-11-04 14:37:53 +0100713 Registers.Write
714 (Register => Controller.PF_CTRL,
715 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_CTRL_FILTER_MED);
716 Registers.Write
717 (Register => Controller.PF_WIN_POS,
Nico Huberfdb0df12018-02-07 14:30:34 +0100718 Value => Shift_Left (Word32 (X), 16) or Word32 (Y));
Nico Huber4916e342016-11-04 14:37:53 +0100719 Registers.Write
720 (Register => Controller.PF_WIN_SZ,
721 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
722 end Setup_Ironlake_Panel_Fitter;
723
Arthur Heymansd5198442018-03-28 17:05:12 +0200724 procedure Setup_Gmch_Panel_Fitter
Nico Huber958c5642018-06-02 16:59:31 +0200725 (Controller : in Controller_Type;
726 Mode : in HW.GFX.Mode_Type;
727 Framebuffer : in HW.GFX.Framebuffer_Type)
Arthur Heymansd5198442018-03-28 17:05:12 +0200728 is
729 PF_Ctrl_Pipe_Sel : constant Word32 :=
730 (case Controller.Pipe is
731 when Primary => GMCH_PFIT_CONTROL_SELECT_PIPE_A,
732 when Secondary => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
733 when others => 0);
Nico Huber958c5642018-06-02 16:59:31 +0200734
Arthur Heymansf70edda2018-08-21 18:37:00 +0200735 -- Work around a quirk:
736 -- In legacy VGA mode Pillarbox fails to display anything so just force
737 -- 'auto' mode on all displays, which will the output stretched to
738 -- fullscreen .
Nico Huber958c5642018-06-02 16:59:31 +0200739 PF_Ctrl_Scaling : constant Word32 :=
Arthur Heymansf70edda2018-08-21 18:37:00 +0200740 (if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
741 GMCH_PFIT_CONTROL_SCALING (Uniform)
742 else
743 GMCH_PFIT_CONTROL_SCALING (Scaling_Type (Framebuffer, Mode)));
Nico Huber958c5642018-06-02 16:59:31 +0200744
Arthur Heymansd5198442018-03-28 17:05:12 +0200745 In_Use : Boolean;
746 begin
747 Registers.Is_Set_Mask
748 (Register => Registers.GMCH_PFIT_CONTROL,
749 Mask => PF_CTRL_ENABLE,
750 Result => In_Use);
751
752 if not In_Use then
753 Registers.Write
754 (Register => Registers.GMCH_PFIT_CONTROL,
Nico Huber958c5642018-06-02 16:59:31 +0200755 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_Ctrl_Scaling);
Arthur Heymansd5198442018-03-28 17:05:12 +0200756 else
Nico Huber7ba7bd62018-06-06 12:27:09 +0200757 pragma Debug (Debug.Put_Line
758 ("GMCH Pannel fitter already in use, skipping..."));
Arthur Heymansd5198442018-03-28 17:05:12 +0200759 end if;
760 end Setup_Gmch_Panel_Fitter;
761
Nico Huberf361ec82018-06-02 18:01:45 +0200762 procedure Gmch_Panel_Fitter_Pipe (Pipe : out Pipe_Index)
763 is
764 Used_For_Secondary : Boolean;
765 begin
Arthur Heymans960e2392026-03-03 19:45:24 +0100766 if Config.Gen_I945 then
767 -- Gen3: panel fitter is hardwired to Pipe B (Secondary).
768 -- The PFIT_PIPE field (bits 30:29) does not exist on Gen3.
769 Pipe := Secondary;
770 else
771 Registers.Is_Set_Mask
772 (Register => Registers.GMCH_PFIT_CONTROL,
773 Mask => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
774 Result => Used_For_Secondary);
775 Pipe := (if Used_For_Secondary then Secondary else Primary);
776 end if;
Nico Huberf361ec82018-06-02 18:01:45 +0200777 end;
778
Nico Huberb4b72792018-01-02 13:45:41 +0100779 procedure Panel_Fitter_Off (Controller : Controller_Type)
780 is
781 use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
Nico Huberf361ec82018-06-02 18:01:45 +0200782 Pipe_Using_PF : Pipe_Index;
Nico Huberb4b72792018-01-02 13:45:41 +0100783 begin
784 -- Writes to WIN_SZ arm the PS/PF registers.
785 if Config.Has_Plane_Control then
786 Registers.Unset_Mask (Controller.PS_CTRL_1, PS_CTRL_ENABLE_SCALER);
787 Registers.Write (Controller.PS_WIN_SZ_1, 16#0000_0000#);
788 if Controller.PS_CTRL_2 /= Registers.Invalid_Register and
789 Controller.PS_WIN_SZ_2 /= Registers.Invalid_Register
790 then
791 Registers.Unset_Mask (Controller.PS_CTRL_2, PS_CTRL_ENABLE_SCALER);
792 Registers.Write (Controller.PS_WIN_SZ_2, 16#0000_0000#);
793 end if;
Arthur Heymansd5198442018-03-28 17:05:12 +0200794 elsif Config.Has_GMCH_PFIT_CONTROL then
Nico Huberf361ec82018-06-02 18:01:45 +0200795 Gmch_Panel_Fitter_Pipe (Pipe_Using_PF);
796 if Pipe_Using_PF = Controller.Pipe then
Arthur Heymans960e2392026-03-03 19:45:24 +0100797 -- Write 0 to clear all bits (enable, scaling mode, auto-scale,
798 -- interpolation). Just clearing the enable bit can leave stale
799 -- Gen3 auto-scale bits that confuse the hardware.
800 Registers.Write (Registers.GMCH_PFIT_CONTROL, 16#0000_0000#);
Arthur Heymansd5198442018-03-28 17:05:12 +0200801 end if;
Nico Huberb4b72792018-01-02 13:45:41 +0100802 else
803 Registers.Unset_Mask (Controller.PF_CTRL, PF_CTRL_ENABLE);
804 Registers.Write (Controller.PF_WIN_SZ, 16#0000_0000#);
805 end if;
806 end Panel_Fitter_Off;
807
Nico Huber4916e342016-11-04 14:37:53 +0100808 procedure Setup_Scaling
809 (Controller : in Controller_Type;
810 Mode : in HW.GFX.Mode_Type;
811 Framebuffer : in HW.GFX.Framebuffer_Type)
812 with
813 Pre =>
Nico Huber9b479412017-08-27 11:55:56 +0200814 Rotated_Width (Framebuffer) <= Mode.H_Visible and
815 Rotated_Height (Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100816 is
817 begin
Nico Huber3d06de82018-05-29 01:35:04 +0200818 if Requires_Scaling (Framebuffer, Mode) then
Nico Huber4916e342016-11-04 14:37:53 +0100819 if Config.Has_Plane_Control then
820 Setup_Skylake_Pipe_Scaler (Controller, Mode, Framebuffer);
Arthur Heymansd5198442018-03-28 17:05:12 +0200821 elsif Config.Has_GMCH_PFIT_CONTROL then
Nico Huber958c5642018-06-02 16:59:31 +0200822 Setup_Gmch_Panel_Fitter (Controller, Mode, Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100823 else
824 Setup_Ironlake_Panel_Fitter (Controller, Mode, Framebuffer);
825 end if;
Nico Huberb4b72792018-01-02 13:45:41 +0100826 else
827 Panel_Fitter_Off (Controller);
Nico Huber4916e342016-11-04 14:37:53 +0100828 end if;
829 end Setup_Scaling;
830
Nico Huber9a4c4c32019-09-16 22:05:11 +0200831 procedure Reserve_Scaler
832 (Success : out Boolean;
833 Reservation : in out Scaler_Reservation;
834 Pipe : in Pipe_Index)
Nico Huberf361ec82018-06-02 18:01:45 +0200835 is
836 Pipe_Using_PF : Pipe_Index := Pipe_Index'First;
837 PF_Enabled : Boolean;
838 begin
839 if Config.Has_GMCH_PFIT_CONTROL then
Nico Huber9a4c4c32019-09-16 22:05:11 +0200840 if Reservation.Reserved then
841 Success := Reservation.Pipe = Pipe;
842 return;
843 end if;
844
Nico Huberf361ec82018-06-02 18:01:45 +0200845 Registers.Is_Set_Mask
846 (Register => Registers.GMCH_PFIT_CONTROL,
847 Mask => PF_CTRL_ENABLE,
848 Result => PF_Enabled);
849 if PF_Enabled then
850 Gmch_Panel_Fitter_Pipe (Pipe_Using_PF);
851 end if;
852
Nico Huber9a4c4c32019-09-16 22:05:11 +0200853 Success := not PF_Enabled or Pipe_Using_PF = Pipe;
854 if Success then
855 Reservation.Reserved := True;
856 Reservation.Pipe := Pipe;
857 end if;
Nico Huberf361ec82018-06-02 18:01:45 +0200858 else
Nico Huber9a4c4c32019-09-16 22:05:11 +0200859 Success := True;
Nico Huberf361ec82018-06-02 18:01:45 +0200860 end if;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200861 end Reserve_Scaler;
Nico Huberf361ec82018-06-02 18:01:45 +0200862
Nico Huber4916e342016-11-04 14:37:53 +0100863 ----------------------------------------------------------------------------
864
Nico Huberf7f537e2018-01-02 14:15:43 +0100865 procedure Setup_FB
866 (Pipe : Pipe_Index;
867 Mode : Mode_Type;
868 Framebuffer : Framebuffer_Type)
869 is
870 -- Enable dithering if framebuffer BPC differs from port BPC,
871 -- as smooth gradients look really bad without.
872 Dither : constant Boolean := Framebuffer.BPC /= Mode.BPC;
873 begin
874 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
875
Nico Huber4dc4c612018-01-10 15:55:09 +0100876 -- Disable the cursor first.
877 Update_Cursor (Pipe, Framebuffer, Default_Cursor);
878
Nico Huberf7f537e2018-01-02 14:15:43 +0100879 Setup_Display (Controllers (Pipe), Framebuffer, Mode.BPC, Dither);
880 Setup_Scaling (Controllers (Pipe), Mode, Framebuffer);
881 end Setup_FB;
882
Nico Huber83693c82016-10-08 22:17:55 +0200883 procedure On
Nico Huberf3e23662016-12-05 21:33:03 +0100884 (Pipe : Pipe_Index;
Nico Huber83693c82016-10-08 22:17:55 +0200885 Port_Cfg : Port_Config;
Nico Huber4dc4c612018-01-10 15:55:09 +0100886 Framebuffer : Framebuffer_Type;
887 Cursor : Cursor_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200888 is
889 begin
890 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
891
Nico Huber7ad2d652016-12-07 15:19:32 +0100892 Transcoder.Setup (Pipe, Port_Cfg);
Nico Huber83693c82016-10-08 22:17:55 +0200893
Nico Huberf7f537e2018-01-02 14:15:43 +0100894 Setup_FB (Pipe, Port_Cfg.Mode, Framebuffer);
Nico Huber4dc4c612018-01-10 15:55:09 +0100895 Update_Cursor (Pipe, Framebuffer, Cursor);
Nico Huber83693c82016-10-08 22:17:55 +0200896
Nico Huberabb16d92018-05-29 01:44:26 +0200897 Transcoder.On
898 (Pipe => Pipe,
899 Port_Cfg => Port_Cfg,
900 Dither => Framebuffer.BPC /= Port_Cfg.Mode.BPC,
901 Scale => Requires_Scaling (Framebuffer, Port_Cfg.Mode));
Nico Huber83693c82016-10-08 22:17:55 +0200902 end On;
903
904 ----------------------------------------------------------------------------
905
Nico Huber75a707f2018-06-18 16:28:33 +0200906 procedure Planes_Off (Controller : Controller_Type; CUR : Cursor_Regs)
907 is
908 use type Registers.Registers_Invalid_Index;
Nico Huber83693c82016-10-08 22:17:55 +0200909 begin
Nico Huber75a707f2018-06-18 16:28:33 +0200910 Registers.Write (CUR.CTL, 16#0000_0000#);
911 if CUR.FBC_CTL /= Registers.Invalid_Register then
912 Registers.Write (CUR.FBC_CTL, 16#0000_0000#);
Nico Huber4dc4c612018-01-10 15:55:09 +0100913 end if;
Nico Huber7ad2d652016-12-07 15:19:32 +0100914 Registers.Unset_Mask (Controller.SPCNTR, DSPCNTR_ENABLE);
Nico Huber83693c82016-10-08 22:17:55 +0200915 if Config.Has_Plane_Control then
916 Clear_Watermarks (Controller);
917 Registers.Unset_Mask (Controller.PLANE_CTL, PLANE_CTL_PLANE_ENABLE);
918 Registers.Write (Controller.PLANE_SURF, 16#0000_0000#);
919 else
920 Registers.Unset_Mask (Controller.DSPCNTR, DSPCNTR_ENABLE);
921 end if;
922 end Planes_Off;
923
Nico Huber7ad2d652016-12-07 15:19:32 +0100924 procedure Off (Pipe : Pipe_Index)
Nico Huberf3e23662016-12-05 21:33:03 +0100925 is
Nico Huber83693c82016-10-08 22:17:55 +0200926 begin
927 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
928
Nico Huber75a707f2018-06-18 16:28:33 +0200929 Planes_Off (Controllers (Pipe), Cursors (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100930 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +0100931 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100932 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +0200933 end Off;
934
Nico Huber33912aa2016-12-06 20:36:23 +0100935 procedure Legacy_VGA_Off
936 is
937 use type HW.Word8;
938 Reg8 : Word8;
939 begin
940 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
941 Port_IO.InB (Reg8, VGA_SR_DATA);
942 Port_IO.OutB (VGA_SR_DATA, Reg8 or VGA_SR01_SCREEN_OFF);
943 Time.U_Delay (100); -- PRM says 100us, Linux does 300
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200944 Registers.Set_Mask (VGACNTRL_REG, VGA_CONTROL_VGA_DISPLAY_DISABLE);
Nico Huber33912aa2016-12-06 20:36:23 +0100945 end Legacy_VGA_Off;
946
Nico Huber83693c82016-10-08 22:17:55 +0200947 procedure All_Off
948 is
Nico Huber83693c82016-10-08 22:17:55 +0200949 begin
950 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
951
Nico Huber33912aa2016-12-06 20:36:23 +0100952 Legacy_VGA_Off;
953
Arthur Heymans960e2392026-03-03 19:45:24 +0100954 for Pipe in Pipe_Index range Pipe_Index'First .. Config.Max_Pipe loop
Nico Huber75a707f2018-06-18 16:28:33 +0200955 Planes_Off (Controllers (Pipe), Cursors (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100956 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +0100957 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100958 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +0200959 end loop;
Nico Huber83693c82016-10-08 22:17:55 +0200960 end All_Off;
961
Nico Huber83693c82016-10-08 22:17:55 +0200962end HW.GFX.GMA.Pipe_Setup;