blob: f915a52c306bac6cb6d1b16e24ee1512c8a20304 [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;
Nico Huber5903f922020-10-05 14:15:57 +020053 PLANE_COLOR_CTL_ALPHA_MODE_SW_PREMUL: constant := 2 * 2 ** 4;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -060054
Nico Huber83693c82016-10-08 22:17:55 +020055 PLANE_CTL_PLANE_ENABLE : constant := 1 * 2 ** 31;
56 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 : constant := 4 * 2 ** 24;
Nico Huberf7a644b2020-10-20 15:26:01 +020057 PLANE_CTL_KEY_ENABLE_MASK : constant := 3 * 2 ** 21;
58 PLANE_CTL_KEY_ENABLE_SOURCE : constant := 1 * 2 ** 21;
Nico Huber83693c82016-10-08 22:17:55 +020059 PLANE_CTL_PLANE_GAMMA_DISABLE : constant := 1 * 2 ** 13;
Nico Huber0164b022017-08-24 15:12:51 +020060 PLANE_CTL_TILED_SURFACE_MASK : constant := 7 * 2 ** 10;
61 PLANE_CTL_TILED_SURFACE_LINEAR : constant := 0 * 2 ** 10;
62 PLANE_CTL_TILED_SURFACE_X_TILED : constant := 1 * 2 ** 10;
63 PLANE_CTL_TILED_SURFACE_Y_TILED : constant := 4 * 2 ** 10;
64 PLANE_CTL_TILED_SURFACE_YF_TILED : constant := 5 * 2 ** 10;
Nico Huber5903f922020-10-05 14:15:57 +020065 PLANE_CTL_ALPHA_MODE_MASK : constant := 3 * 2 ** 4;
66 PLANE_CTL_ALPHA_MODE_SW_PREMULTIPLY : constant := 2 * 2 ** 4;
Nico Huberf7a644b2020-10-20 15:26:01 +020067 PLANE_CTL_ALPHA_MODE_HW_PREMULTIPLY : constant := 3 * 2 ** 4;
Nico Huber0164b022017-08-24 15:12:51 +020068
69 PLANE_CTL_TILED_SURFACE : constant array (Tiling_Type) of Word32 :=
70 (Linear => PLANE_CTL_TILED_SURFACE_LINEAR,
71 X_Tiled => PLANE_CTL_TILED_SURFACE_X_TILED,
72 Y_Tiled => PLANE_CTL_TILED_SURFACE_Y_TILED);
Nico Huber83693c82016-10-08 22:17:55 +020073
Nico Huber9b479412017-08-27 11:55:56 +020074 PLANE_CTL_PLANE_ROTATION_MASK : constant := 3 * 2 ** 0;
75 PLANE_CTL_PLANE_ROTATION : constant array (Rotation_Type) of Word32 :=
76 (No_Rotation => 0 * 2 ** 0,
77 Rotated_90 => 1 * 2 ** 0,
78 Rotated_180 => 2 * 2 ** 0,
79 Rotated_270 => 3 * 2 ** 0);
80
Nico Huber83693c82016-10-08 22:17:55 +020081 PLANE_WM_ENABLE : constant := 1 * 2 ** 31;
82 PLANE_WM_LINES_SHIFT : constant := 14;
83 PLANE_WM_LINES_MASK : constant := 16#001f# * 2 ** 14;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -060084 PLANE_WM_BLOCKS_MASK : constant :=
85 (if Config.Has_Wide_Watermarks then 16#7ff# else 16#3ff#);
86
87 PIPEMISC_HDR_MODE_PRECISION : constant := 1 * 2 ** 23;
88 PIPEMISC_PIXEL_ROUNDING_TRUNC : constant := 1 * 2 ** 8;
Nico Huber83693c82016-10-08 22:17:55 +020089
Nico Huber33912aa2016-12-06 20:36:23 +010090 VGA_SR_INDEX : constant := 16#03c4#;
91 VGA_SR_DATA : constant := 16#03c5#;
92 VGA_SR01 : constant := 16#01#;
93 VGA_SR01_SCREEN_OFF : constant := 1 * 2 ** 5;
Nico Huber3675db52016-11-04 16:27:29 +010094
95 VGA_CONTROL_VGA_DISPLAY_DISABLE : constant := 1 * 2 ** 31;
96 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK : constant := 16#0003# * 2 ** 6;
97 VGA_CONTROL_BLINK_DUTY_CYCLE_50 : constant := 2 * 2 ** 6;
98 VGA_CONTROL_VSYNC_BLINK_RATE_MASK : constant := 16#003f# * 2 ** 0;
99
Nico Huber4dc4c612018-01-10 15:55:09 +0100100 CUR_CTL_PIPE_SELECT : constant array (Pipe_Index) of Word32 :=
101 (Primary => 0 * 2 ** 28,
102 Secondary => 1 * 2 ** 28,
103 Tertiary => 2 * 2 ** 28);
104 CUR_CTL_MODE : constant array (Cursor_Mode, Cursor_Size) of Word32 :=
105 (No_Cursor => (others => 16#00#),
106 ARGB_Cursor =>
107 (Cursor_64x64 => 16#27#,
108 Cursor_128x128 => 16#22#,
109 Cursor_256x256 => 16#23#));
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600110 subtype ARB_Slots is Natural range 0 .. 7;
111 function MCURSOR_ARB_SLOTS (N : ARB_Slots) return Word32 is
112 (Shift_Left (Word32 (N), 28));
Nico Huber4dc4c612018-01-10 15:55:09 +0100113
114 function CUR_POS_Y (Y : Int32) return Word32 is
115 ((if Y >= 0 then 0 else 1 * 2 ** 31) or Shift_Left (Word32 (abs Y), 16))
116 with
117 Pre => Y > Int32'First;
118 function CUR_POS_X (X : Int32) return Word32 is
119 ((if X >= 0 then 0 else 1 * 2 ** 15) or Word32 (abs X))
120 with
121 Pre => X > Int32'First;
122
Nico Huber3675db52016-11-04 16:27:29 +0100123 subtype VGA_Cycle_Count is Pos32 range 2 .. 128;
124 function VGA_CONTROL_VSYNC_BLINK_RATE
125 (Cycles : VGA_Cycle_Count)
126 return Word32
127 is
128 begin
129 return Word32 (Cycles) / 2 - 1;
130 end VGA_CONTROL_VSYNC_BLINK_RATE;
131
Nico Huber7ad2d652016-12-07 15:19:32 +0100132 PF_CTRL_ENABLE : constant := 1 * 2 ** 31;
133 PF_CTRL_PIPE_SELECT_MASK : constant := 3 * 2 ** 29;
134 PF_CTRL_FILTER_MED : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200135
Nico Huber7ad2d652016-12-07 15:19:32 +0100136 PS_CTRL_ENABLE_SCALER : constant := 1 * 2 ** 31;
137 PS_CTRL_SCALER_MODE_7X5_EXTENDED : constant := 1 * 2 ** 28;
138 PS_CTRL_FILTER_SELECT_MEDIUM_2 : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200139
Arthur Heymansd5198442018-03-28 17:05:12 +0200140 GMCH_PFIT_CONTROL_SELECT_MASK : constant := 3 * 2 ** 29;
141 GMCH_PFIT_CONTROL_SELECT_PIPE_A : constant := 0 * 2 ** 29;
142 GMCH_PFIT_CONTROL_SELECT_PIPE_B : constant := 1 * 2 ** 29;
Nico Huber958c5642018-06-02 16:59:31 +0200143 GMCH_PFIT_CONTROL_SCALING_MASK : constant := 3 * 2 ** 26;
144 GMCH_PFIT_CONTROL_SCALING : constant array (Scaling_Aspect) of Word32 :=
145 (Uniform => 0 * 2 ** 26,
146 Pillarbox => 2 * 2 ** 26,
147 Letterbox => 3 * 2 ** 26);
Arthur Heymansd5198442018-03-28 17:05:12 +0200148
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200149 VGACNTRL_REG : constant Registers.Registers_Index :=
150 (if Config.Has_GMCH_VGACNTRL then
151 Registers.GMCH_VGACNTRL
152 else Registers.CPU_VGACNTRL);
153
Nico Huber83693c82016-10-08 22:17:55 +0200154 ---------------------------------------------------------------------------
155
Nico Huber83693c82016-10-08 22:17:55 +0200156 function PLANE_WM_LINES (Lines : Natural) return Word32 is
157 begin
158 return Shift_Left (Word32 (Lines), PLANE_WM_LINES_SHIFT)
159 and PLANE_WM_LINES_MASK;
160 end PLANE_WM_LINES;
161
162 function PLANE_WM_BLOCKS (Blocks : Natural) return Word32 is
163 begin
164 return Word32 (Blocks) and PLANE_WM_BLOCKS_MASK;
165 end PLANE_WM_BLOCKS;
166
167 ---------------------------------------------------------------------------
168
Nico Hubera7e1cd32026-07-03 09:23:24 +0000169 subtype Source_Size is Width_Type;
Nico Huberfb6dbad2026-04-10 16:23:39 +0000170
Nico Hubera7e1cd32026-07-03 09:23:24 +0000171 function Encode_Size (LSW, MSW : Source_Size) return Word32
Nico Huberfb6dbad2026-04-10 16:23:39 +0000172 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000173 (Shift_Left (Word32 (MSW) - 1, 16) or (Word32 (LSW) - 1));
174
175 function Source_Width (FB : Framebuffer_Type) return Source_Size
176 is
177 (if Config.Needs_Even_Source_Width and then Rotated_Width (FB) > 2 then
178 Rotated_Width (FB) - Rotated_Width (FB) mod 2
Nico Huberfb6dbad2026-04-10 16:23:39 +0000179 else
Nico Hubera7e1cd32026-07-03 09:23:24 +0000180 Rotated_Width (FB));
Nico Huberfb6dbad2026-04-10 16:23:39 +0000181
Nico Hubera7e1cd32026-07-03 09:23:24 +0000182 function Source_Height (FB : Framebuffer_Type) return Source_Size
Nico Huberfb6dbad2026-04-10 16:23:39 +0000183 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000184 (Rotated_Height (FB));
Nico Huber83693c82016-10-08 22:17:55 +0200185
186 ----------------------------------------------------------------------------
187
Nico Huber83693c82016-10-08 22:17:55 +0200188 procedure Clear_Watermarks (Controller : Controller_Type) is
189 begin
Nico Huber4dc4c612018-01-10 15:55:09 +0100190 Registers.Write (Controller.CUR_BUF_CFG, 16#0000_0000#);
191 for Level in WM_Levels loop
192 Registers.Write (Controller.CUR_WM (Level), 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200193 end loop;
Nico Huber9e78dda2020-10-01 15:30:54 +0200194 Registers.Write (Controller.PLANE_2_BUF_CFG, 16#0000_0000#);
195 for Level in WM_Levels loop
196 Registers.Write (Controller.PLANE_2_WM (Level), 16#0000_0000#);
197 end loop;
Nico Huber4dc4c612018-01-10 15:55:09 +0100198 Registers.Write (Controller.PLANE_BUF_CFG, 16#0000_0000#);
199 for Level in WM_Levels loop
200 Registers.Write (Controller.PLANE_WM (Level), 16#0000_0000#);
201 end loop;
202 Registers.Write (Controller.WM_LINETIME, 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200203 end Clear_Watermarks;
204
205 procedure Setup_Watermarks (Controller : Controller_Type)
206 is
Nico Huber9e78dda2020-10-01 15:30:54 +0200207 subtype Buffer_Count is Natural range 1 .. 508;
208 subtype Buffer_Index is Natural range 0 .. Buffer_Count'Last - 1;
209
210 function Encode_Buffers (Start : Buffer_Index; Count : Buffer_Count)
211 return Word32
212 is
213 (Shift_Left (Word32 (Start + Count - 1), 16) or Word32 (Start));
214
Nico Huberf3e23662016-12-05 21:33:03 +0100215 type Per_Plane_Buffer_Range is array (Pipe_Index) of Word32;
Nico Huber9e78dda2020-10-01 15:30:54 +0200216 Plane_1_Buffer_Range : constant Per_Plane_Buffer_Range :=
217 (Primary => Encode_Buffers ( 0, 150),
218 Secondary => Encode_Buffers (169, 150),
219 Tertiary => Encode_Buffers (338, 150));
220 Plane_2_Buffer_Range : constant Per_Plane_Buffer_Range :=
221 (Primary => Encode_Buffers (150, 11),
222 Secondary => Encode_Buffers (319, 11),
223 Tertiary => Encode_Buffers (488, 11));
Nico Huber4dc4c612018-01-10 15:55:09 +0100224 Cur_Buffer_Range : constant Per_Plane_Buffer_Range :=
Nico Huber9e78dda2020-10-01 15:30:54 +0200225 (Primary => Encode_Buffers (161, 8),
226 Secondary => Encode_Buffers (330, 8),
227 Tertiary => Encode_Buffers (499, 8));
Nico Huber83693c82016-10-08 22:17:55 +0200228 begin
229 Registers.Write
230 (Register => Controller.PLANE_BUF_CFG,
Nico Huber9e78dda2020-10-01 15:30:54 +0200231 Value => Plane_1_Buffer_Range (Controller.Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200232 Registers.Write
233 (Register => Controller.PLANE_WM (0),
234 Value => PLANE_WM_ENABLE or
235 PLANE_WM_LINES (2) or
Nico Huber9e78dda2020-10-01 15:30:54 +0200236 PLANE_WM_BLOCKS (150));
237 Registers.Write
238 (Register => Controller.PLANE_2_BUF_CFG,
239 Value => Plane_2_Buffer_Range (Controller.Pipe));
240 Registers.Write
241 (Register => Controller.PLANE_2_WM (0),
242 Value => PLANE_WM_ENABLE or
243 PLANE_WM_LINES (2) or
244 PLANE_WM_BLOCKS (11));
Nico Huber4dc4c612018-01-10 15:55:09 +0100245 Registers.Write
246 (Register => Controller.CUR_BUF_CFG,
247 Value => Cur_Buffer_Range (Controller.Pipe));
248 Registers.Write
249 (Register => Controller.CUR_WM (0),
250 Value => PLANE_WM_ENABLE or
251 PLANE_WM_LINES (2) or
252 PLANE_WM_BLOCKS (8));
Nico Huber83693c82016-10-08 22:17:55 +0200253 end Setup_Watermarks;
254
255 ----------------------------------------------------------------------------
256
Nico Huber3675db52016-11-04 16:27:29 +0100257 procedure Setup_Hires_Plane
Nico Huber6a4dfc82016-11-04 15:50:58 +0100258 (Controller : Controller_Type;
Nico Huber0164b022017-08-24 15:12:51 +0200259 FB : HW.GFX.Framebuffer_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200260 with
Nico Huber5ef4d602017-12-13 13:56:47 +0100261 Pre => FB.Height + FB.Start_Y <= FB.V_Stride
Nico Huber83693c82016-10-08 22:17:55 +0200262 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000263 Width : constant Source_Size := Source_Width (FB);
264 Height : constant Source_Size := Source_Height (FB);
Nico Huberfb6dbad2026-04-10 16:23:39 +0000265
Nico Huber83693c82016-10-08 22:17:55 +0200266 -- FIXME: setup correct format, based on framebuffer RGB format
267 Format : constant Word32 := 6 * 2 ** 26;
Arthur Heymans960e2392026-03-03 19:45:24 +0100268 PRI : Word32 := Format;
Nico Huber83693c82016-10-08 22:17:55 +0200269 begin
270 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
271
Nico Huber83693c82016-10-08 22:17:55 +0200272 if Config.Has_Plane_Control then
Nico Huber9b479412017-08-27 11:55:56 +0200273 declare
Nico Huber34be6542017-12-13 09:26:24 +0100274 Stride, Offset : Word32;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600275
276 function PLANE_CTL_ARB_SLOTS (N : Word32) return Word32 is
277 (if Config.Need_Pipe_Arb_Slots then Shift_Left (N, 28) else 0);
278
279 -- TODO: Hard coded format and arbitration slots for now,
280 -- for 4B-per-pixel XRGB, just like `Format` above.
281 -- ARB_SLOTS(1) matches the 4B per pixel.
282 Plane_Ctl : constant Word32 :=
283 PLANE_CTL_PLANE_ENABLE or
284 PLANE_CTL_TILED_SURFACE (FB.Tiling) or
285 PLANE_CTL_PLANE_ROTATION (FB.Rotation) or
286 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
287 PLANE_CTL_ARB_SLOTS (1) or
288 (if not Config.Has_Plane_Color_Control
289 then PLANE_CTL_PLANE_GAMMA_DISABLE
290 else 0);
Nico Huber9b479412017-08-27 11:55:56 +0200291 begin
292 if Rotation_90 (FB) then
Nico Huber5ef4d602017-12-13 13:56:47 +0100293 Stride := Word32 (FB_Pitch (FB.V_Stride, FB));
294 Offset := Shift_Left (Word32 (FB.Start_X), 16) or
295 Word32 (FB.V_Stride - FB.Height - FB.Start_Y);
Nico Huber9b479412017-08-27 11:55:56 +0200296 else
Nico Huber5ef4d602017-12-13 13:56:47 +0100297 Stride := Word32 (FB_Pitch (FB.Stride, FB));
298 Offset := Shift_Left (Word32 (FB.Start_Y), 16) or
299 Word32 (FB.Start_X);
Nico Huber9b479412017-08-27 11:55:56 +0200300 end if;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600301
302 if Config.Has_Plane_Color_Control then
303 Registers.Write
304 (Register => Controller.PLANE_COLOR_CTL,
305 Value => PLANE_COLOR_CTL_PLANE_GAMMA_DISABLE);
306 end if;
307 Registers.Write (Controller.PLANE_AUX_DIST, 0);
308 Registers.Write (Controller.PLANE_CTL, Plane_Ctl);
Nico Huber9b479412017-08-27 11:55:56 +0200309 Registers.Write (Controller.PLANE_OFFSET, Offset);
Nico Huberfb6dbad2026-04-10 16:23:39 +0000310 Registers.Write (Controller.PLANE_SIZE, Encode_Size (Width, Height));
Nico Huber9b479412017-08-27 11:55:56 +0200311 Registers.Write (Controller.PLANE_STRIDE, Stride);
312 Registers.Write (Controller.PLANE_POS, 16#0000_0000#);
Nico Huber34be6542017-12-13 09:26:24 +0100313 Registers.Write (Controller.PLANE_SURF, FB.Offset and 16#ffff_f000#);
Nico Huber9b479412017-08-27 11:55:56 +0200314 end;
Nico Huber83693c82016-10-08 22:17:55 +0200315 else
Arthur Heymans960e2392026-03-03 19:45:24 +0100316 if Config.Has_DSPCNTR_Pipe_Select then
317 PRI := PRI or DSPCNTR_PIPE_SEL (Controller.Pipe);
318 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200319 if Config.Disable_Trickle_Feed then
320 PRI := PRI or DSPCNTR_DISABLE_TRICKLE_FEED;
321 end if;
Arthur Heymans960e2392026-03-03 19:45:24 +0100322
323 -- Write DSPCNTR *without* the enable bit first. On pre-SKL
324 -- hardware the control register self-arms when the plane
325 -- transitions from disabled to enabled, latching whatever
326 -- stride/size/offset values happen to be in the registers at
327 -- that moment. Programming format, pipe-select, and trickle-
328 -- feed now avoids a glitch with stale geometry values.
Nico Huber83693c82016-10-08 22:17:55 +0200329 Registers.Unset_And_Set_Mask
330 (Register => Controller.DSPCNTR,
331 Mask_Unset => DSPCNTR_MASK,
Nico Huberab69e362018-05-29 21:20:30 +0200332 Mask_Set => PRI or DSPCNTR_TILED_SURFACE (FB.Tiling));
Nico Huber83693c82016-10-08 22:17:55 +0200333
Nico Huber0164b022017-08-24 15:12:51 +0200334 Registers.Write
335 (Controller.DSPSTRIDE, Word32 (Pixel_To_Bytes (FB.Stride, FB)));
Arthur Heymans960e2392026-03-03 19:45:24 +0100336
337 -- Gen3 (i945): program DSPSIZE and DSPPOS before the surface
338 -- address write that arms the double-buffered plane registers.
339 if Config.Gen_I945 then
Nico Huberfb6dbad2026-04-10 16:23:39 +0000340 Registers.Write (Controller.DSPSIZE, Encode_Size (Width, Height));
Arthur Heymans960e2392026-03-03 19:45:24 +0100341 Registers.Write (Controller.DSPPOS, 16#0000_0000#);
342 end if;
343
Nico Huberab69e362018-05-29 21:20:30 +0200344 if Config.Has_DSP_Linoff and then FB.Tiling = Linear then
Arthur Heymans3f37cce2026-03-03 18:52:12 +0100345 pragma Assert_And_Cut
346 (FB.Start_Y * FB.Stride + FB.Start_X in Pixel_Type);
Nico Huberd49b56b2018-06-18 17:19:15 +0200347 declare
348 Linear_Offset : constant Pixel_Type :=
349 FB.Start_Y * FB.Stride + FB.Start_X;
350 begin
351 Registers.Write
352 (Register => Controller.DSPLINOFF,
Arthur Heymans960e2392026-03-03 19:45:24 +0100353 Value => (if Config.Has_DSPSURF
354 then Word32 (Pixel_To_Bytes (Linear_Offset, FB))
355 else (FB.Offset and 16#ffff_f000#) or
356 Word32 (Pixel_To_Bytes (Linear_Offset, FB))));
Nico Huberd49b56b2018-06-18 17:19:15 +0200357 Registers.Write (Controller.DSPTILEOFF, 0);
358 end;
Nico Huber5ef4d602017-12-13 13:56:47 +0100359 else
Nico Huberab69e362018-05-29 21:20:30 +0200360 if Config.Has_DSP_Linoff then
Arthur Heymans960e2392026-03-03 19:45:24 +0100361 Registers.Write (Controller.DSPLINOFF,
362 (if Config.Has_DSPSURF then 0
363 else FB.Offset and 16#ffff_f000#));
Nico Huberab69e362018-05-29 21:20:30 +0200364 end if;
Nico Huber5ef4d602017-12-13 13:56:47 +0100365 Registers.Write
366 (Register => Controller.DSPTILEOFF,
367 Value => Shift_Left (Word32 (FB.Start_Y), 16) or
368 Word32 (FB.Start_X));
Nico Huber83693c82016-10-08 22:17:55 +0200369 end if;
Arthur Heymans960e2392026-03-03 19:45:24 +0100370 if Config.Has_DSPSURF then
371 Registers.Write (Controller.DSPSURF, FB.Offset and 16#ffff_f000#);
372 end if;
373
374 -- Now enable the plane. All geometry registers are in place,
375 -- so the self-arm latches correct values.
376 Registers.Write
377 (Register => Controller.DSPCNTR,
378 Value => DSPCNTR_ENABLE or PRI or
379 DSPCNTR_TILED_SURFACE (FB.Tiling));
Nico Huber83693c82016-10-08 22:17:55 +0200380 end if;
Nico Huber3675db52016-11-04 16:27:29 +0100381 end Setup_Hires_Plane;
382
383 procedure Setup_Display
Nico Huber113a14b2016-12-06 21:59:15 +0100384 (Controller : Controller_Type;
385 Framebuffer : Framebuffer_Type;
386 Dither_BPC : BPC_Type;
387 Dither : Boolean)
Nico Huber3675db52016-11-04 16:27:29 +0100388 with
Nico Huber9b479412017-08-27 11:55:56 +0200389 Pre =>
390 Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
Nico Huber5ef4d602017-12-13 13:56:47 +0100391 Framebuffer.Height + Framebuffer.Start_Y <= Framebuffer.V_Stride
Nico Huber3675db52016-11-04 16:27:29 +0100392 is
393 use type Word8;
394
395 Reg8 : Word8;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600396
397 type BW_Credit is new Natural range 0 .. 3;
398 function MBUS_DBOX_BW_CREDIT (C : BW_Credit) return Word32 is
399 (Shift_Left (Word32 (C), 14));
400
401 type B_Credit is new Natural range 0 .. 31;
402 function MBUS_DBOX_B_CREDIT (C : B_Credit) return Word32 is
403 (Shift_Left (Word32 (C), 8));
404
405 type A_Credit is new Natural range 0 .. 15;
406 function MBUS_DBOX_A_CREDIT (C : A_Credit) return Word32 is
407 (Word32 (C));
408
409 type B2B_Trans_Max is new Natural range 0 .. 31;
410 function MBUS_DBOX_B2B_TRANSACTIONS_MAX (B : B2B_Trans_Max) return Word32 is
411 (Shift_Left (Word32 (B), 20));
412
413 type B2B_Trans_Delay is new Natural range 0 .. 7;
414 function MBUS_DBOX_B2B_TRANSACTIONS_DELAY (B : B2B_Trans_Delay) return Word32 is
415 (Shift_Left (Word32 (B), 17));
416 MBUS_DBOX_REGULATE_B2B_TRANSACTIONS_EN : constant := 1 * 2 ** 16;
417
418 procedure Program_Mbus_Dbox_Credits is
419 Tmp : Word32;
420 begin
421 Tmp := MBUS_DBOX_B2B_TRANSACTIONS_MAX (16) or
422 MBUS_DBOX_B2B_TRANSACTIONS_DELAY (1) or
423 MBUS_DBOX_REGULATE_B2B_TRANSACTIONS_EN;
424
425 if Config.Has_New_Mbus_Dbox_Credits then
426 Tmp := Tmp or MBUS_DBOX_BW_CREDIT (2) or
427 MBUS_DBOX_B_CREDIT (8) or
428 MBUS_DBOX_A_CREDIT (4); -- No joined MBus support,
429 -- hence always use 4 for now.
430 else
431 Tmp := Tmp or MBUS_DBOX_BW_CREDIT (2) or
432 MBUS_DBOX_B_CREDIT (12) or
433 MBUS_DBOX_A_CREDIT (2);
434 end if;
435
436 Registers.Write
437 (Register => Controller.MBUS_DBOX_CTL,
438 Value => Tmp);
439 end Program_Mbus_Dbox_Credits;
440
441 -- Display WA # 1605353570: icl
442 -- Set the pixel rounding bit to 1 for allowing
443 -- passthrough of Frame buffer pixels unmodified
444 -- across pipe
445 PIXEL_ROUNDING_TRUNC_FB_PASSTHRU : constant := 1 * 2 ** 15;
446
447 -- Display WA #1153: icl
448 -- enable hardware to bypass the alpha math
449 -- and rounding for per-pixel values 00 and 0xff
450 PER_PIXEL_ALPHA_BYPASS_EN : constant := 1 * 2 ** 7;
451
452 -- ADL_P requires that we disable underrun recovery when
453 -- downscaling (or using the scaler for YUV420 pipe output),
454 -- using DSC, or using PSR2.
455 -- i915 always disables underrun recovery for gen 13+.
456 UNDERRUN_RECOVERY_DISABLE : constant := 1 * 2 ** 30;
Nico Huberfb6dbad2026-04-10 16:23:39 +0000457
Nico Hubera7e1cd32026-07-03 09:23:24 +0000458 Width : constant Source_Size := Source_Width (Framebuffer);
459 Height : constant Source_Size := Source_Height (Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100460 begin
461 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
462
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600463 if Config.Has_Type_C_Ports then
464 Registers.Set_Mask
465 (Register => Controller.PIPE_CHICKEN,
466 Mask => PER_PIXEL_ALPHA_BYPASS_EN or
467 PIXEL_ROUNDING_TRUNC_FB_PASSTHRU or
468 (if Config.Need_Underrun_Rec_Disable
469 then UNDERRUN_RECOVERY_DISABLE
470 else 0));
471 end if;
472
Nico Huber3675db52016-11-04 16:27:29 +0100473 if Config.Has_Plane_Control then
474 Setup_Watermarks (Controller);
475 end if;
476
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600477 if Config.Has_Mbus_Dbox_Credits then
478 Program_Mbus_Dbox_Credits;
479 end if;
480
Nico Huber3675db52016-11-04 16:27:29 +0100481 if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
Nico Huberfbb42202016-11-07 15:08:26 +0100482 if Config.VGA_Plane_Workaround then
483 Registers.Unset_And_Set_Mask
484 (Register => Registers.ILK_DISPLAY_CHICKEN1,
485 Mask_Unset => ILK_DISPLAY_CHICKEN1_VGA_MASK,
486 Mask_Set => ILK_DISPLAY_CHICKEN1_VGA_ENABLE);
487 Registers.Unset_And_Set_Mask
488 (Register => Registers.ILK_DISPLAY_CHICKEN2,
489 Mask_Unset => ILK_DISPLAY_CHICKEN2_VGA_MASK,
490 Mask_Set => ILK_DISPLAY_CHICKEN2_VGA_ENABLE);
491 end if;
492
Nico Huber3675db52016-11-04 16:27:29 +0100493 Registers.Unset_And_Set_Mask
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200494 (Register => VGACNTRL_REG,
Nico Huber3675db52016-11-04 16:27:29 +0100495 Mask_Unset => VGA_CONTROL_VGA_DISPLAY_DISABLE or
496 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK or
497 VGA_CONTROL_VSYNC_BLINK_RATE_MASK,
498 Mask_Set => VGA_CONTROL_BLINK_DUTY_CYCLE_50 or
499 VGA_CONTROL_VSYNC_BLINK_RATE (30));
500
501 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
502 Port_IO.InB (Reg8, VGA_SR_DATA);
503 Port_IO.OutB (VGA_SR_DATA, Reg8 and not (VGA_SR01_SCREEN_OFF));
504 else
Nico Huber6a4dfc82016-11-04 15:50:58 +0100505 Setup_Hires_Plane (Controller, Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100506 end if;
507
508 Registers.Write
509 (Register => Controller.PIPESRC,
Nico Huberfb6dbad2026-04-10 16:23:39 +0000510 Value => Encode_Size (Height, Width));
Nico Huber83693c82016-10-08 22:17:55 +0200511
Nico Huber113a14b2016-12-06 21:59:15 +0100512 if Config.Has_Pipeconf_Misc then
513 Registers.Write
514 (Register => Controller.PIPEMISC,
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600515 Value => Transcoder.BPC_Conf (Dither_BPC, Dither) or
516 -- FIXME: Should we set these at all?
517 (if Config.Has_Plane_Color_Control then
518 (PIPEMISC_PIXEL_ROUNDING_TRUNC or PIPEMISC_HDR_MODE_PRECISION) else 0));
Nico Huber113a14b2016-12-06 21:59:15 +0100519 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200520 end Setup_Display;
521
522 ----------------------------------------------------------------------------
523
Nico Huber5903f922020-10-05 14:15:57 +0200524 function Use_Plane_For_Cursor (FB : Framebuffer_Type) return Boolean is
525 (Config.Has_Plane_Control and then FB.Tiling = Y_Tiled);
526
Nico Huber4dc4c612018-01-10 15:55:09 +0100527 procedure Update_Cursor
528 (Pipe : Pipe_Index;
529 FB : Framebuffer_Type;
530 Cursor : Cursor_Type)
531 is
Nico Huber5903f922020-10-05 14:15:57 +0200532 Controller : Controller_Type renames Controllers (Pipe);
Nico Huber4dc4c612018-01-10 15:55:09 +0100533 begin
Nico Huber5903f922020-10-05 14:15:57 +0200534 if Use_Plane_For_Cursor (FB) then
Nico Huberf7a644b2020-10-20 15:26:01 +0200535 -- Use feffff (most white cyan) as key color for transparency.
536 -- It turned out that at least on APL, even fully transparent
537 -- pixels are faintly visible when blended onto the primary
538 -- framebuffer.
539 Registers.Write (Controller.PLANE_2_KEYVAL, 16#00_fe_ff_ff#);
540 Registers.Write (Controller.PLANE_2_KEYMSK, 16#07_ff_ff_ff#);
541
Nico Huber5903f922020-10-05 14:15:57 +0200542 if Config.Has_Plane_Color_Control then
543 Registers.Write
544 (Register => Controller.PLANE_2_COLOR_CTL,
545 Value => PLANE_COLOR_CTL_PLANE_GAMMA_DISABLE or
546 PLANE_COLOR_CTL_ALPHA_MODE_SW_PREMUL);
547 end if;
548 else
549 -- on some platforms writing CUR_CTL disables self-arming of CUR_POS
550 -- so keep it first
551 Registers.Write
552 (Register => Cursors (Pipe).CTL,
553 Value => CUR_CTL_MODE (Cursor.Mode, Cursor.Size) or
554 (if Config.Need_Pipe_Arb_Slots
555 then MCURSOR_ARB_SLOTS (1)
556 else CUR_CTL_PIPE_SELECT (Pipe)));
557 end if;
558 Place_Cursor (Pipe, FB, Cursor, (Cursor.Center_X, Cursor.Center_Y), Update => True);
Nico Huber4dc4c612018-01-10 15:55:09 +0100559 end Update_Cursor;
560
561 procedure Place_Cursor
562 (Pipe : Pipe_Index;
563 FB : Framebuffer_Type;
Nico Huber1dae2202020-10-05 13:31:25 +0200564 Cursor : Cursor_Type;
Nico Huber5903f922020-10-05 14:15:57 +0200565 Center : Cursor_Coord;
566 Update : Boolean := False)
Nico Huber4dc4c612018-01-10 15:55:09 +0100567 is
Nico Huber5903f922020-10-05 14:15:57 +0200568 Controller : Controller_Type renames Controllers (Pipe);
569
Nico Huber4dc4c612018-01-10 15:55:09 +0100570 Width : constant Width_Type := Cursor_Width (Cursor.Size);
Nico Huber5903f922020-10-05 14:15:57 +0200571 Surface_Width : constant Width_Type := Source_Width (FB);
572 Surface_Height : constant Height_Type := Source_Height (FB);
Nico Huber3d7c33f2020-10-01 15:14:38 +0200573
Nico Huber902d8032020-10-05 14:14:16 +0200574 -- Like `Cursor_Pos`/`Cursor_Coord` but allowing wider range for proof.
575 subtype Relaxed_Pos is Int32 range
576 Cursor_Pos'First - Width_Type'Last .. Cursor_Pos'Last + Width_Type'Last;
577 type Relaxed_Coord is record
578 X : Relaxed_Pos;
579 Y : Relaxed_Pos;
580 end record;
581
Nico Huber3d7c33f2020-10-01 15:14:38 +0200582 -- The cursor's coordinates are on the framebuffer surface
583 -- but we need to place it on the physical screen:
Nico Huber902d8032020-10-05 14:14:16 +0200584 function Rotate (Center : Cursor_Coord) return Relaxed_Coord is
585 (X =>
586 (case FB.Rotation is
587 when No_Rotation => Center.X,
588 when Rotated_90 => FB.Height - 1 - Center.Y,
589 when Rotated_180 => FB.Width - 1 - Center.X,
590 when Rotated_270 => Center.Y),
591 Y =>
592 (case FB.Rotation is
593 when No_Rotation => Center.Y,
594 when Rotated_90 => Center.X,
595 when Rotated_180 => FB.Height - 1 - Center.Y,
596 when Rotated_270 => FB.Width - 1 - Center.X));
Nico Huber3d7c33f2020-10-01 15:14:38 +0200597
Nico Huber902d8032020-10-05 14:14:16 +0200598 -- Calculates the coordinates of the cursor plane's
599 -- upper-left corner on the bigger screen (pipe input).
600 function Phys_Origin (Center : Cursor_Coord) return Relaxed_Coord is
601 (X => Rotate (Center).X - Width / 2,
602 Y => Rotate (Center).Y - Width / 2);
603
Nico Huber5903f922020-10-05 14:15:57 +0200604 function Fully_Visible (Origin : Relaxed_Coord) return Boolean is
605 (Origin.X in 0 .. Surface_Width - Width - 1 and
606 Origin.Y in 0 .. Surface_Height - Width - 1);
607
Nico Huber902d8032020-10-05 14:14:16 +0200608 Origin : Relaxed_Coord := Phys_Origin (Center);
Nico Huber5903f922020-10-05 14:15:57 +0200609
610 Visible : constant Boolean :=
611 Origin.X in -Width + 1 .. Surface_Width - 1 and
612 Origin.Y in -Width + 1 .. Surface_Height - 1;
Nico Huber4dc4c612018-01-10 15:55:09 +0100613 begin
Nico Huber5903f922020-10-05 14:15:57 +0200614 if Use_Plane_For_Cursor (FB) and then
615 ((Update and Cursor.Mode /= ARGB_Cursor) or not Visible)
Nico Huber4dc4c612018-01-10 15:55:09 +0100616 then
Nico Huber5903f922020-10-05 14:15:57 +0200617 Registers.Write
618 (Register => Controller.PLANE_2_CTL,
619 Value => 0,
620 Verbose => False);
621 Registers.Write -- arming
622 (Register => Controller.PLANE_2_SURF,
623 Value => 0,
624 Verbose => False);
625 elsif Use_Plane_For_Cursor (FB) then
626 -- we may have to configure all registers
627 if Update or
628 not Fully_Visible (Phys_Origin ((Cursor.Center_X, Cursor.Center_Y))) or
629 not Fully_Visible (Origin)
630 then
631 declare
632 Visible_Width : Width_Type := Width;
633 Visible_Height : Height_Type := Width;
634 Offset_X : Word32;
635 Offset_Y : Word32;
636
637 -- Calculates where to start reading from the cursor plane's
638 -- framebuffer, iow. gives the first visible pixel of the
639 -- cursor (e.g. for an unrotated cursor whose upper-left
640 -- corner left the screen).
641 function Offset (Pos : Relaxed_Pos; Visible : Int32) return Word32
642 is
643 (if (Pos < 0 and FB.Rotation <= Rotated_90) or
644 (Pos >= 0 and FB.Rotation >= Rotated_180)
645 then Word32 (Width - Visible) else 0)
646 with
647 Pre => Visible in 0 .. Width;
648 begin
649 -- The hardware does neither support negative positions nor
650 -- clipping. So if the cursor should be clipped at an edge
651 -- of the framebuffer, we need to make these calculations
652 -- manually:
653
654 if Origin.X < 0 then
655 Visible_Width := Visible_Width + Origin.X;
656 elsif Origin.X > Surface_Width - Width then
657 Visible_Width := Surface_Width - Origin.X;
658 end if;
659 Offset_X := Offset (Origin.X, Visible_Width);
660 Origin.X := Int32'Max (Origin.X, 0);
661
662 if Origin.Y < 0 then
663 Visible_Height := Visible_Height + Origin.Y;
664 elsif Origin.Y > Surface_Height - Width then
665 Visible_Height := Surface_Height - Origin.Y;
666 end if;
667 Offset_Y := Offset (Origin.Y, Visible_Height);
668 Origin.Y := Int32'Max (Origin.Y, 0);
669
670 Registers.Write
671 (Register => Controller.PLANE_2_CTL,
Nico Huberf7a644b2020-10-20 15:26:01 +0200672 Value => PLANE_CTL_PLANE_ENABLE or
673 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
674 PLANE_CTL_KEY_ENABLE_SOURCE or
675 PLANE_CTL_TILED_SURFACE (FB.Tiling) or
Nico Huber5903f922020-10-05 14:15:57 +0200676 PLANE_CTL_PLANE_ROTATION (FB.Rotation) or
677 (if not Config.Has_Plane_Color_Control
678 then PLANE_CTL_PLANE_GAMMA_DISABLE or
679 PLANE_CTL_ALPHA_MODE_SW_PREMULTIPLY
680 else 0),
681 Verbose => False);
682 Registers.Write
683 (Register => Controller.PLANE_2_OFFSET,
684 Value => Shift_Left (Offset_Y, 16) or Offset_X,
685 Verbose => False);
686 Registers.Write
687 (Register => Controller.PLANE_2_SIZE,
688 Value => Encode_Size (Visible_Width, Visible_Height),
689 Verbose => False);
690 Registers.Write
691 (Register => Controller.PLANE_2_STRIDE,
692 Value => Word32 (FB_Pitch (Width, FB)),
693 Verbose => False);
694 end;
695 end if;
696
697 Registers.Write
698 (Register => Controller.PLANE_2_POS,
699 Value => Shift_Left (Word32 (Origin.Y), 16) or Word32 (Origin.X),
700 Verbose => False);
701 Registers.Write -- arming
702 (Register => Controller.PLANE_2_SURF,
703 Value => Shift_Left (Word32 (Cursor.GTT_Offset), 12),
704 Verbose => False);
705 else
706 -- off-screen cursor needs special care
707 if not Visible or
708 Origin.X > Config.Maximum_Cursor_X or
709 Origin.Y > Config.Maximum_Cursor_Y
710 then
711 Origin.X := -Width;
712 Origin.Y := -Width;
713 end if;
714 Registers.Write
715 (Register => Cursors (Pipe).POS,
716 Value => CUR_POS_Y (Origin.Y) or CUR_POS_X (Origin.X),
717 Verbose => False);
718 -- write to CUR_BASE always arms other CUR_* registers
719 Registers.Write
720 (Register => Cursors (Pipe).BASE,
721 Value => Shift_Left (Word32 (Cursor.GTT_Offset), 12),
722 Verbose => False);
Nico Huber4dc4c612018-01-10 15:55:09 +0100723 end if;
Nico Huber4dc4c612018-01-10 15:55:09 +0100724 end Place_Cursor;
725
726 ----------------------------------------------------------------------------
727
Nico Huber4916e342016-11-04 14:37:53 +0100728 procedure Scale_Keep_Aspect
Nico Huberc5c767a2018-06-03 01:09:04 +0200729 (Width : out Width_Type;
730 Height : out Height_Type;
731 Max_Width : in Width_Type;
732 Max_Height : in Height_Type;
Nico Huber4916e342016-11-04 14:37:53 +0100733 Framebuffer : in Framebuffer_Type)
734 with
735 Pre =>
Nico Hubera7e1cd32026-07-03 09:23:24 +0000736 Source_Width (Framebuffer) <= Max_Width and
737 Source_Height (Framebuffer) <= Max_Height,
Nico Huber4916e342016-11-04 14:37:53 +0100738 Post =>
739 Width <= Max_Width and Height <= Max_Height
740 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000741 Src_Width : constant Width_Type := Source_Width (Framebuffer);
742 Src_Height : constant Height_Type := Source_Height (Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100743 begin
Nico Huberda1185e2018-06-03 01:07:46 +0200744 case Scaling_Type (Src_Width, Src_Height, Max_Width, Max_Height) is
745 when Letterbox =>
Nico Huber99200fe2026-04-14 16:37:45 +0200746 Height := (Src_Height * Max_Width) / Src_Width;
747 pragma Assert (Height <= Max_Height);
Nico Huberda1185e2018-06-03 01:07:46 +0200748 Width := Max_Width;
Nico Huberda1185e2018-06-03 01:07:46 +0200749 when Pillarbox =>
Nico Huber99200fe2026-04-14 16:37:45 +0200750 Width := (Src_Width * Max_Height) / Src_Height;
751 pragma Assert (Max_Height * Src_Width < Max_Width * Src_Height);
752 pragma Assert ((Max_Height * Src_Width) / Src_Height < Max_Width);
753 pragma Assert (Width <= Max_Width);
Nico Huberda1185e2018-06-03 01:07:46 +0200754 Height := Max_Height;
755 when Uniform =>
756 Width := Max_Width;
757 Height := Max_Height;
758 end case;
Nico Huber4916e342016-11-04 14:37:53 +0100759 end Scale_Keep_Aspect;
760
Nico Huberba84df22026-06-23 13:29:29 +0000761 procedure Scale
762 (Width : out Width_Type;
763 Height : out Height_Type;
764 Scaling : in GMA.Scaling;
765 Max_Width : in Width_Type;
766 Max_Height : in Height_Type;
767 Framebuffer : in Framebuffer_Type)
768 with
769 Pre =>
Nico Hubera7e1cd32026-07-03 09:23:24 +0000770 Source_Width (Framebuffer) <= Max_Width and
771 Source_Height (Framebuffer) <= Max_Height,
Nico Huberba84df22026-06-23 13:29:29 +0000772 Post =>
773 Width <= Max_Width and Height <= Max_Height
774 is
775 begin
776 case Scaling is
777 when None =>
Nico Hubera7e1cd32026-07-03 09:23:24 +0000778 Width := Source_Width (Framebuffer);
779 Height := Source_Height (Framebuffer);
Nico Huberba84df22026-06-23 13:29:29 +0000780 when Fit =>
781 Scale_Keep_Aspect (Width, Height, Max_Width, Max_Height, Framebuffer);
782 when Stretch =>
783 Width := Max_Width;
784 Height := Max_Height;
785 end case;
786 end Scale;
787
788 procedure Align_Framebuffer
789 (Pos_X : out Position_Type;
790 Pos_Y : out Position_Type;
791 Align : in Alignment;
792 Width : in Width_Type;
793 Height : in Height_Type;
794 Mode : in Mode_Type)
795 with
796 Pre => Width <= Mode.H_Visible and Height <= Mode.V_Visible
797 is
798 Gap_X : constant Position_Type := Mode.H_Visible - Width;
799 Gap_Y : constant Position_Type := Mode.V_Visible - Height;
800 begin
801 case Align is
802 when Top_Left => Pos_X := 0; Pos_Y := 0;
803 when Top => Pos_X := Gap_X / 2; Pos_Y := 0;
804 when Top_Right => Pos_X := Gap_X; Pos_Y := 0;
805 when Left => Pos_X := 0; Pos_Y := Gap_Y / 2;
806 when Center => Pos_X := Gap_X / 2; Pos_Y := Gap_Y / 2;
807 when Right => Pos_X := Gap_X; Pos_Y := Gap_Y / 2;
808 when Bottom_Left => Pos_X := 0; Pos_Y := Gap_Y;
809 when Bottom => Pos_X := Gap_X / 2; Pos_Y := Gap_Y;
810 when Bottom_Right => Pos_X := Gap_X; Pos_Y := Gap_Y;
811 end case;
812 end Align_Framebuffer;
813
Nico Huberfb6dbad2026-04-10 16:23:39 +0000814 type Pipe_Scaler_Limit_Config is record
815 Control : Word32;
816 Horizontal : Pos32;
817 Vertical : Pos32;
818 end record;
819
820 function Skylake_Scaler_Limits
821 (Controller : Controller_Type;
822 Width : Width_Type;
823 Height : Height_Type)
824 return Pipe_Scaler_Limit_Config
825 with
826 Post => Skylake_Scaler_Limits'Result.Horizontal >= Width
827 and Skylake_Scaler_Limits'Result.Vertical >= Height
828 is
829 use type Registers.Registers_Invalid_Index;
830
831 -- Enable 7x5 extended mode where possible:
832 Scaler_Mode : constant Word32 :=
833 (if Controller.PS_CTRL_2 /= Registers.Invalid_Register then
834 PS_CTRL_SCALER_MODE_7X5_EXTENDED else 0);
835
836 -- We can scale up to 2.99x horizontally:
837 Horizontal_Limit : constant Pos32 := (Width * 299) / 100;
838 -- The third scaler is limited to 1.99x
839 -- vertical scaling for source widths > 2048:
840 Vertical_Limit : constant Pos32 :=
841 (Height *
842 (if Controller.PS_CTRL_2 = Registers.Invalid_Register and
843 Width > 2048
844 then
845 199
846 else
847 299)) / 100;
848 begin
849 return (Scaler_Mode, Horizontal_Limit, Vertical_Limit);
850 end Skylake_Scaler_Limits;
851
852 function Tigerlake_Scaler_Limits
853 (Width : Width_Type;
854 Height : Height_Type)
855 return Pipe_Scaler_Limit_Config
856 with
857 Post => Tigerlake_Scaler_Limits'Result.Horizontal >= Width
858 and Tigerlake_Scaler_Limits'Result.Vertical >= Height
859 is
860 Scaling : constant := 32_000; -- PRM says: Scaling * 2**15 >= 1.0
861 -- so virtually unlimited
862 begin
863 return (Control => 0, Horizontal => Width * Scaling, Vertical => Height * Scaling);
864 end Tigerlake_Scaler_Limits;
865
Nico Huber4916e342016-11-04 14:37:53 +0100866 procedure Setup_Skylake_Pipe_Scaler
867 (Controller : in Controller_Type;
Nico Huber4d592b42026-06-23 12:21:37 +0000868 Pipe_Cfg : in Pipe_Config;
869 Mode : in HW.GFX.Mode_Type)
Nico Huber4916e342016-11-04 14:37:53 +0100870 with
871 Pre =>
Nico Huber4d592b42026-06-23 12:21:37 +0000872 Rotated_Width (Pipe_Cfg.Framebuffer) <= Mode.H_Visible and
873 Rotated_Height (Pipe_Cfg.Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100874 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000875 Width_In : constant Width_Type := Source_Width (Pipe_Cfg.Framebuffer);
876 Height_In : constant Height_Type := Source_Height (Pipe_Cfg.Framebuffer);
Nico Huberfb6dbad2026-04-10 16:23:39 +0000877 Limits : constant Pipe_Scaler_Limit_Config :=
878 (if Config.Has_Skylake_Scaler_Limits then
879 Skylake_Scaler_Limits (Controller, Width_In, Height_In)
880 else
881 Tigerlake_Scaler_Limits (Width_In, Height_In));
Nico Huber4916e342016-11-04 14:37:53 +0100882
Nico Huberc5c767a2018-06-03 01:09:04 +0200883 Width : Width_Type;
884 Height : Height_Type;
Nico Huberba84df22026-06-23 13:29:29 +0000885 Pos_X, Pos_Y : Position_Type;
Nico Huber4916e342016-11-04 14:37:53 +0100886 begin
887 -- Writes to WIN_SZ arm the PS registers.
888
Nico Huberba84df22026-06-23 13:29:29 +0000889 Scale
Nico Huber4916e342016-11-04 14:37:53 +0100890 (Width => Width,
891 Height => Height,
Nico Huberba84df22026-06-23 13:29:29 +0000892 Scaling => Pipe_Cfg.Scaling,
Nico Huberfb6dbad2026-04-10 16:23:39 +0000893 Max_Width => Pos32'Min (Limits.Horizontal, Mode.H_Visible),
894 Max_Height => Pos32'Min (Limits.Vertical, Mode.V_Visible),
Nico Huber4d592b42026-06-23 12:21:37 +0000895 Framebuffer => Pipe_Cfg.Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100896
Nico Huberba84df22026-06-23 13:29:29 +0000897 Align_Framebuffer
898 (Pos_X => Pos_X,
899 Pos_Y => Pos_Y,
900 Align => Pipe_Cfg.Alignment,
901 Width => Width,
902 Height => Height,
903 Mode => Mode);
904
Nico Huber4916e342016-11-04 14:37:53 +0100905 Registers.Write
906 (Register => Controller.PS_CTRL_1,
Nico Huberfb6dbad2026-04-10 16:23:39 +0000907 Value => PS_CTRL_ENABLE_SCALER or Limits.Control);
Nico Huber4916e342016-11-04 14:37:53 +0100908 Registers.Write
909 (Register => Controller.PS_WIN_POS_1,
Nico Huberba84df22026-06-23 13:29:29 +0000910 Value => Shift_Left (Word32 (Pos_X), 16) or Word32 (Pos_Y));
Nico Huber4916e342016-11-04 14:37:53 +0100911 Registers.Write
912 (Register => Controller.PS_WIN_SZ_1,
913 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
914 end Setup_Skylake_Pipe_Scaler;
915
916 procedure Setup_Ironlake_Panel_Fitter
917 (Controller : in Controller_Type;
Nico Huber4d592b42026-06-23 12:21:37 +0000918 Pipe_Cfg : in Pipe_Config;
919 Mode : in HW.GFX.Mode_Type)
Nico Huber4916e342016-11-04 14:37:53 +0100920 with
921 Pre =>
Nico Huber4d592b42026-06-23 12:21:37 +0000922 Rotated_Width (Pipe_Cfg.Framebuffer) <= Mode.H_Visible and
923 Rotated_Height (Pipe_Cfg.Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100924 is
925 -- Force 1:1 mapping of panel fitter:pipe
926 PF_Ctrl_Pipe_Sel : constant Word32 :=
927 (if Config.Has_PF_Pipe_Select then
928 (case Controller.PF_CTRL is
929 when Registers.PFA_CTL_1 => 0 * 2 ** 29,
930 when Registers.PFB_CTL_1 => 1 * 2 ** 29,
931 when Registers.PFC_CTL_1 => 2 * 2 ** 29,
932 when others => 0) else 0);
933
Nico Huberc5c767a2018-06-03 01:09:04 +0200934 Width : Width_Type;
935 Height : Height_Type;
Nico Huberba84df22026-06-23 13:29:29 +0000936 Pos_X, Pos_Y : Position_Type;
Nico Huber4916e342016-11-04 14:37:53 +0100937 begin
938 -- Writes to WIN_SZ arm the PF registers.
939
Nico Huberba84df22026-06-23 13:29:29 +0000940 Scale
Nico Huber4916e342016-11-04 14:37:53 +0100941 (Width => Width,
942 Height => Height,
Nico Huberba84df22026-06-23 13:29:29 +0000943 Scaling => Pipe_Cfg.Scaling,
Nico Huberc5c767a2018-06-03 01:09:04 +0200944 Max_Width => Mode.H_Visible,
945 Max_Height => Mode.V_Visible,
Nico Huber4d592b42026-06-23 12:21:37 +0000946 Framebuffer => Pipe_Cfg.Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100947
Nico Huberfdb0df12018-02-07 14:30:34 +0100948 -- Do not scale to odd width (at least Haswell has trouble with this).
Nico Huberc5c767a2018-06-03 01:09:04 +0200949 if Width < Mode.H_Visible and Width mod 2 = 1 then
Nico Huberfdb0df12018-02-07 14:30:34 +0100950 Width := Width + 1;
951 end if;
Nico Huberb3b9fa32018-06-18 16:16:41 +0200952 -- Do not scale to odd height (at least Sandy Bridge makes trouble).
953 if Height < Mode.V_Visible and Height mod 2 = 1 then
954 Height := Height + 1;
955 end if;
Nico Huberfdb0df12018-02-07 14:30:34 +0100956
Nico Huberba84df22026-06-23 13:29:29 +0000957 Align_Framebuffer
958 (Pos_X => Pos_X,
959 Pos_Y => Pos_Y,
960 Align => Pipe_Cfg.Alignment,
961 Width => Width,
962 Height => Height,
963 Mode => Mode);
Nico Huberfdb0df12018-02-07 14:30:34 +0100964
965 -- Hardware is picky about minimal horizontal gaps.
Nico Huberc5c767a2018-06-03 01:09:04 +0200966 if Mode.H_Visible - Width <= 3 then
967 Width := Mode.H_Visible;
Nico Huberba84df22026-06-23 13:29:29 +0000968 Pos_X := 0;
Nico Huberfdb0df12018-02-07 14:30:34 +0100969 end if;
970
Nico Huber4916e342016-11-04 14:37:53 +0100971 Registers.Write
972 (Register => Controller.PF_CTRL,
973 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_CTRL_FILTER_MED);
974 Registers.Write
975 (Register => Controller.PF_WIN_POS,
Nico Huberba84df22026-06-23 13:29:29 +0000976 Value => Shift_Left (Word32 (Pos_X), 16) or Word32 (Pos_Y));
Nico Huber4916e342016-11-04 14:37:53 +0100977 Registers.Write
978 (Register => Controller.PF_WIN_SZ,
979 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
980 end Setup_Ironlake_Panel_Fitter;
981
Arthur Heymansd5198442018-03-28 17:05:12 +0200982 procedure Setup_Gmch_Panel_Fitter
Nico Huber958c5642018-06-02 16:59:31 +0200983 (Controller : in Controller_Type;
984 Mode : in HW.GFX.Mode_Type;
985 Framebuffer : in HW.GFX.Framebuffer_Type)
Arthur Heymansd5198442018-03-28 17:05:12 +0200986 is
987 PF_Ctrl_Pipe_Sel : constant Word32 :=
988 (case Controller.Pipe is
989 when Primary => GMCH_PFIT_CONTROL_SELECT_PIPE_A,
990 when Secondary => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
991 when others => 0);
Nico Huber958c5642018-06-02 16:59:31 +0200992
Arthur Heymansf70edda2018-08-21 18:37:00 +0200993 -- Work around a quirk:
994 -- In legacy VGA mode Pillarbox fails to display anything so just force
995 -- 'auto' mode on all displays, which will the output stretched to
996 -- fullscreen .
Nico Huber958c5642018-06-02 16:59:31 +0200997 PF_Ctrl_Scaling : constant Word32 :=
Arthur Heymansf70edda2018-08-21 18:37:00 +0200998 (if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
999 GMCH_PFIT_CONTROL_SCALING (Uniform)
1000 else
1001 GMCH_PFIT_CONTROL_SCALING (Scaling_Type (Framebuffer, Mode)));
Nico Huber958c5642018-06-02 16:59:31 +02001002
Arthur Heymansd5198442018-03-28 17:05:12 +02001003 In_Use : Boolean;
1004 begin
1005 Registers.Is_Set_Mask
1006 (Register => Registers.GMCH_PFIT_CONTROL,
1007 Mask => PF_CTRL_ENABLE,
1008 Result => In_Use);
1009
1010 if not In_Use then
1011 Registers.Write
1012 (Register => Registers.GMCH_PFIT_CONTROL,
Nico Huber958c5642018-06-02 16:59:31 +02001013 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_Ctrl_Scaling);
Arthur Heymansd5198442018-03-28 17:05:12 +02001014 else
Nico Huber7ba7bd62018-06-06 12:27:09 +02001015 pragma Debug (Debug.Put_Line
1016 ("GMCH Pannel fitter already in use, skipping..."));
Arthur Heymansd5198442018-03-28 17:05:12 +02001017 end if;
1018 end Setup_Gmch_Panel_Fitter;
1019
Nico Huberf361ec82018-06-02 18:01:45 +02001020 procedure Gmch_Panel_Fitter_Pipe (Pipe : out Pipe_Index)
1021 is
1022 Used_For_Secondary : Boolean;
1023 begin
Arthur Heymans960e2392026-03-03 19:45:24 +01001024 if Config.Gen_I945 then
1025 -- Gen3: panel fitter is hardwired to Pipe B (Secondary).
1026 -- The PFIT_PIPE field (bits 30:29) does not exist on Gen3.
1027 Pipe := Secondary;
1028 else
1029 Registers.Is_Set_Mask
1030 (Register => Registers.GMCH_PFIT_CONTROL,
1031 Mask => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
1032 Result => Used_For_Secondary);
1033 Pipe := (if Used_For_Secondary then Secondary else Primary);
1034 end if;
Nico Huberac2a1412026-07-02 10:41:59 +02001035 end Gmch_Panel_Fitter_Pipe;
Nico Huberf361ec82018-06-02 18:01:45 +02001036
Nico Huberb4b72792018-01-02 13:45:41 +01001037 procedure Panel_Fitter_Off (Controller : Controller_Type)
1038 is
1039 use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
Nico Huberf361ec82018-06-02 18:01:45 +02001040 Pipe_Using_PF : Pipe_Index;
Nico Huberb4b72792018-01-02 13:45:41 +01001041 begin
1042 -- Writes to WIN_SZ arm the PS/PF registers.
1043 if Config.Has_Plane_Control then
1044 Registers.Unset_Mask (Controller.PS_CTRL_1, PS_CTRL_ENABLE_SCALER);
1045 Registers.Write (Controller.PS_WIN_SZ_1, 16#0000_0000#);
1046 if Controller.PS_CTRL_2 /= Registers.Invalid_Register and
1047 Controller.PS_WIN_SZ_2 /= Registers.Invalid_Register
1048 then
1049 Registers.Unset_Mask (Controller.PS_CTRL_2, PS_CTRL_ENABLE_SCALER);
1050 Registers.Write (Controller.PS_WIN_SZ_2, 16#0000_0000#);
1051 end if;
Arthur Heymansd5198442018-03-28 17:05:12 +02001052 elsif Config.Has_GMCH_PFIT_CONTROL then
Nico Huberf361ec82018-06-02 18:01:45 +02001053 Gmch_Panel_Fitter_Pipe (Pipe_Using_PF);
1054 if Pipe_Using_PF = Controller.Pipe then
Arthur Heymans960e2392026-03-03 19:45:24 +01001055 -- Write 0 to clear all bits (enable, scaling mode, auto-scale,
1056 -- interpolation). Just clearing the enable bit can leave stale
1057 -- Gen3 auto-scale bits that confuse the hardware.
1058 Registers.Write (Registers.GMCH_PFIT_CONTROL, 16#0000_0000#);
Arthur Heymansd5198442018-03-28 17:05:12 +02001059 end if;
Nico Huberb4b72792018-01-02 13:45:41 +01001060 else
1061 Registers.Unset_Mask (Controller.PF_CTRL, PF_CTRL_ENABLE);
1062 Registers.Write (Controller.PF_WIN_SZ, 16#0000_0000#);
1063 end if;
1064 end Panel_Fitter_Off;
1065
Nico Huber4916e342016-11-04 14:37:53 +01001066 procedure Setup_Scaling
1067 (Controller : in Controller_Type;
Nico Huber4d592b42026-06-23 12:21:37 +00001068 Pipe_Cfg : in Pipe_Config;
1069 Mode : in HW.GFX.Mode_Type)
Nico Huber4916e342016-11-04 14:37:53 +01001070 with
1071 Pre =>
Nico Huber4d592b42026-06-23 12:21:37 +00001072 Rotated_Width (Pipe_Cfg.Framebuffer) <= Mode.H_Visible and
1073 Rotated_Height (Pipe_Cfg.Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +01001074 is
1075 begin
Nico Huber4d592b42026-06-23 12:21:37 +00001076 if Requires_Scaling (Pipe_Cfg.Framebuffer, Mode) then
Nico Huber4916e342016-11-04 14:37:53 +01001077 if Config.Has_Plane_Control then
Nico Huber4d592b42026-06-23 12:21:37 +00001078 Setup_Skylake_Pipe_Scaler (Controller, Pipe_Cfg, Mode);
Arthur Heymansd5198442018-03-28 17:05:12 +02001079 elsif Config.Has_GMCH_PFIT_CONTROL then
Nico Huber4d592b42026-06-23 12:21:37 +00001080 Setup_Gmch_Panel_Fitter (Controller, Mode, Pipe_Cfg.Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +01001081 else
Nico Huber4d592b42026-06-23 12:21:37 +00001082 Setup_Ironlake_Panel_Fitter (Controller, Pipe_Cfg, Mode);
Nico Huber4916e342016-11-04 14:37:53 +01001083 end if;
Nico Huberb4b72792018-01-02 13:45:41 +01001084 else
1085 Panel_Fitter_Off (Controller);
Nico Huber4916e342016-11-04 14:37:53 +01001086 end if;
1087 end Setup_Scaling;
1088
Nico Huber9a4c4c32019-09-16 22:05:11 +02001089 procedure Reserve_Scaler
1090 (Success : out Boolean;
1091 Reservation : in out Scaler_Reservation;
1092 Pipe : in Pipe_Index)
Nico Huberf361ec82018-06-02 18:01:45 +02001093 is
1094 Pipe_Using_PF : Pipe_Index := Pipe_Index'First;
1095 PF_Enabled : Boolean;
1096 begin
1097 if Config.Has_GMCH_PFIT_CONTROL then
Nico Huber9a4c4c32019-09-16 22:05:11 +02001098 if Reservation.Reserved then
1099 Success := Reservation.Pipe = Pipe;
1100 return;
1101 end if;
1102
Nico Huberf361ec82018-06-02 18:01:45 +02001103 Registers.Is_Set_Mask
1104 (Register => Registers.GMCH_PFIT_CONTROL,
1105 Mask => PF_CTRL_ENABLE,
1106 Result => PF_Enabled);
1107 if PF_Enabled then
1108 Gmch_Panel_Fitter_Pipe (Pipe_Using_PF);
1109 end if;
1110
Nico Huber9a4c4c32019-09-16 22:05:11 +02001111 Success := not PF_Enabled or Pipe_Using_PF = Pipe;
1112 if Success then
1113 Reservation.Reserved := True;
1114 Reservation.Pipe := Pipe;
1115 end if;
Nico Huberf361ec82018-06-02 18:01:45 +02001116 else
Nico Huber9a4c4c32019-09-16 22:05:11 +02001117 Success := True;
Nico Huberf361ec82018-06-02 18:01:45 +02001118 end if;
Nico Huber9a4c4c32019-09-16 22:05:11 +02001119 end Reserve_Scaler;
Nico Huberf361ec82018-06-02 18:01:45 +02001120
Nico Huber4916e342016-11-04 14:37:53 +01001121 ----------------------------------------------------------------------------
1122
Nico Huberf7f537e2018-01-02 14:15:43 +01001123 procedure Setup_FB
1124 (Pipe : Pipe_Index;
Nico Huber4d592b42026-06-23 12:21:37 +00001125 Pipe_Cfg : Pipe_Config;
1126 Mode : Mode_Type)
Nico Huberf7f537e2018-01-02 14:15:43 +01001127 is
1128 -- Enable dithering if framebuffer BPC differs from port BPC,
1129 -- as smooth gradients look really bad without.
Nico Huber4d592b42026-06-23 12:21:37 +00001130 Dither : constant Boolean := Pipe_Cfg.Framebuffer.BPC /= Mode.BPC;
Nico Huberf7f537e2018-01-02 14:15:43 +01001131 begin
1132 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
1133
Nico Huber4dc4c612018-01-10 15:55:09 +01001134 -- Disable the cursor first.
Nico Huber4d592b42026-06-23 12:21:37 +00001135 Update_Cursor (Pipe, Pipe_Cfg.Framebuffer, Default_Cursor);
Nico Huber4dc4c612018-01-10 15:55:09 +01001136
Nico Huber4d592b42026-06-23 12:21:37 +00001137 Setup_Display (Controllers (Pipe), Pipe_Cfg.Framebuffer, Mode.BPC, Dither);
1138 Setup_Scaling (Controllers (Pipe), Pipe_Cfg, Mode);
Nico Huberf7f537e2018-01-02 14:15:43 +01001139 end Setup_FB;
1140
Nico Huber83693c82016-10-08 22:17:55 +02001141 procedure On
Nico Huberf3e23662016-12-05 21:33:03 +01001142 (Pipe : Pipe_Index;
Nico Huber4d592b42026-06-23 12:21:37 +00001143 Pipe_Cfg : Pipe_Config;
1144 Port_Cfg : Port_Config)
Nico Huber83693c82016-10-08 22:17:55 +02001145 is
1146 begin
1147 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
1148
Nico Huber7ad2d652016-12-07 15:19:32 +01001149 Transcoder.Setup (Pipe, Port_Cfg);
Nico Huber83693c82016-10-08 22:17:55 +02001150
Nico Huber4d592b42026-06-23 12:21:37 +00001151 Setup_FB (Pipe, Pipe_Cfg, Port_Cfg.Mode);
1152 Update_Cursor (Pipe, Pipe_Cfg.Framebuffer, Pipe_Cfg.Cursor);
Nico Huber83693c82016-10-08 22:17:55 +02001153
Nico Huberabb16d92018-05-29 01:44:26 +02001154 Transcoder.On
1155 (Pipe => Pipe,
1156 Port_Cfg => Port_Cfg,
Nico Huber4d592b42026-06-23 12:21:37 +00001157 Dither => Pipe_Cfg.Framebuffer.BPC /= Port_Cfg.Mode.BPC,
1158 Scale => Requires_Scaling (Pipe_Cfg.Framebuffer, Port_Cfg.Mode));
Nico Huber83693c82016-10-08 22:17:55 +02001159 end On;
1160
1161 ----------------------------------------------------------------------------
1162
Nico Huber75a707f2018-06-18 16:28:33 +02001163 procedure Planes_Off (Controller : Controller_Type; CUR : Cursor_Regs)
1164 is
1165 use type Registers.Registers_Invalid_Index;
Nico Huber83693c82016-10-08 22:17:55 +02001166 begin
Nico Huber75a707f2018-06-18 16:28:33 +02001167 Registers.Write (CUR.CTL, 16#0000_0000#);
1168 if CUR.FBC_CTL /= Registers.Invalid_Register then
1169 Registers.Write (CUR.FBC_CTL, 16#0000_0000#);
Nico Huber4dc4c612018-01-10 15:55:09 +01001170 end if;
Nico Huber07aab5a2020-10-01 15:06:53 +02001171 Registers.Unset_Mask (Controller.PLANE_2_CTL, DSPCNTR_ENABLE);
Nico Huber83693c82016-10-08 22:17:55 +02001172 if Config.Has_Plane_Control then
1173 Clear_Watermarks (Controller);
1174 Registers.Unset_Mask (Controller.PLANE_CTL, PLANE_CTL_PLANE_ENABLE);
1175 Registers.Write (Controller.PLANE_SURF, 16#0000_0000#);
1176 else
1177 Registers.Unset_Mask (Controller.DSPCNTR, DSPCNTR_ENABLE);
1178 end if;
1179 end Planes_Off;
1180
Nico Huber7ad2d652016-12-07 15:19:32 +01001181 procedure Off (Pipe : Pipe_Index)
Nico Huberf3e23662016-12-05 21:33:03 +01001182 is
Nico Huber83693c82016-10-08 22:17:55 +02001183 begin
1184 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
1185
Nico Huber75a707f2018-06-18 16:28:33 +02001186 Planes_Off (Controllers (Pipe), Cursors (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +01001187 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +01001188 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +01001189 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +02001190 end Off;
1191
Nico Huber33912aa2016-12-06 20:36:23 +01001192 procedure Legacy_VGA_Off
1193 is
1194 use type HW.Word8;
1195 Reg8 : Word8;
1196 begin
1197 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
1198 Port_IO.InB (Reg8, VGA_SR_DATA);
1199 Port_IO.OutB (VGA_SR_DATA, Reg8 or VGA_SR01_SCREEN_OFF);
1200 Time.U_Delay (100); -- PRM says 100us, Linux does 300
Arthur Heymansdfcdd772018-03-28 16:42:50 +02001201 Registers.Set_Mask (VGACNTRL_REG, VGA_CONTROL_VGA_DISPLAY_DISABLE);
Nico Huber33912aa2016-12-06 20:36:23 +01001202 end Legacy_VGA_Off;
1203
Nico Huber83693c82016-10-08 22:17:55 +02001204 procedure All_Off
1205 is
Nico Huber83693c82016-10-08 22:17:55 +02001206 begin
1207 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
1208
Nico Huber33912aa2016-12-06 20:36:23 +01001209 Legacy_VGA_Off;
1210
Arthur Heymans960e2392026-03-03 19:45:24 +01001211 for Pipe in Pipe_Index range Pipe_Index'First .. Config.Max_Pipe loop
Nico Huber75a707f2018-06-18 16:28:33 +02001212 Planes_Off (Controllers (Pipe), Cursors (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +01001213 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +01001214 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +01001215 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +02001216 end loop;
Nico Huber83693c82016-10-08 22:17:55 +02001217 end All_Off;
1218
Nico Huber83693c82016-10-08 22:17:55 +02001219end HW.GFX.GMA.Pipe_Setup;