blob: f49d6c03ce2ea923845bbe43e889ae9b488e9523 [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;
57 PLANE_CTL_PLANE_GAMMA_DISABLE : constant := 1 * 2 ** 13;
Nico Huber0164b022017-08-24 15:12:51 +020058 PLANE_CTL_TILED_SURFACE_MASK : constant := 7 * 2 ** 10;
59 PLANE_CTL_TILED_SURFACE_LINEAR : constant := 0 * 2 ** 10;
60 PLANE_CTL_TILED_SURFACE_X_TILED : constant := 1 * 2 ** 10;
61 PLANE_CTL_TILED_SURFACE_Y_TILED : constant := 4 * 2 ** 10;
62 PLANE_CTL_TILED_SURFACE_YF_TILED : constant := 5 * 2 ** 10;
Nico Huber5903f922020-10-05 14:15:57 +020063 PLANE_CTL_ALPHA_MODE_MASK : constant := 3 * 2 ** 4;
64 PLANE_CTL_ALPHA_MODE_SW_PREMULTIPLY : constant := 2 * 2 ** 4;
Nico Huber0164b022017-08-24 15:12:51 +020065
66 PLANE_CTL_TILED_SURFACE : constant array (Tiling_Type) of Word32 :=
67 (Linear => PLANE_CTL_TILED_SURFACE_LINEAR,
68 X_Tiled => PLANE_CTL_TILED_SURFACE_X_TILED,
69 Y_Tiled => PLANE_CTL_TILED_SURFACE_Y_TILED);
Nico Huber83693c82016-10-08 22:17:55 +020070
Nico Huber9b479412017-08-27 11:55:56 +020071 PLANE_CTL_PLANE_ROTATION_MASK : constant := 3 * 2 ** 0;
72 PLANE_CTL_PLANE_ROTATION : constant array (Rotation_Type) of Word32 :=
73 (No_Rotation => 0 * 2 ** 0,
74 Rotated_90 => 1 * 2 ** 0,
75 Rotated_180 => 2 * 2 ** 0,
76 Rotated_270 => 3 * 2 ** 0);
77
Nico Huber83693c82016-10-08 22:17:55 +020078 PLANE_WM_ENABLE : constant := 1 * 2 ** 31;
79 PLANE_WM_LINES_SHIFT : constant := 14;
80 PLANE_WM_LINES_MASK : constant := 16#001f# * 2 ** 14;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -060081 PLANE_WM_BLOCKS_MASK : constant :=
82 (if Config.Has_Wide_Watermarks then 16#7ff# else 16#3ff#);
83
84 PIPEMISC_HDR_MODE_PRECISION : constant := 1 * 2 ** 23;
85 PIPEMISC_PIXEL_ROUNDING_TRUNC : constant := 1 * 2 ** 8;
Nico Huber83693c82016-10-08 22:17:55 +020086
Nico Huber33912aa2016-12-06 20:36:23 +010087 VGA_SR_INDEX : constant := 16#03c4#;
88 VGA_SR_DATA : constant := 16#03c5#;
89 VGA_SR01 : constant := 16#01#;
90 VGA_SR01_SCREEN_OFF : constant := 1 * 2 ** 5;
Nico Huber3675db52016-11-04 16:27:29 +010091
92 VGA_CONTROL_VGA_DISPLAY_DISABLE : constant := 1 * 2 ** 31;
93 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK : constant := 16#0003# * 2 ** 6;
94 VGA_CONTROL_BLINK_DUTY_CYCLE_50 : constant := 2 * 2 ** 6;
95 VGA_CONTROL_VSYNC_BLINK_RATE_MASK : constant := 16#003f# * 2 ** 0;
96
Nico Huber4dc4c612018-01-10 15:55:09 +010097 CUR_CTL_PIPE_SELECT : constant array (Pipe_Index) of Word32 :=
98 (Primary => 0 * 2 ** 28,
99 Secondary => 1 * 2 ** 28,
100 Tertiary => 2 * 2 ** 28);
101 CUR_CTL_MODE : constant array (Cursor_Mode, Cursor_Size) of Word32 :=
102 (No_Cursor => (others => 16#00#),
103 ARGB_Cursor =>
104 (Cursor_64x64 => 16#27#,
105 Cursor_128x128 => 16#22#,
106 Cursor_256x256 => 16#23#));
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600107 subtype ARB_Slots is Natural range 0 .. 7;
108 function MCURSOR_ARB_SLOTS (N : ARB_Slots) return Word32 is
109 (Shift_Left (Word32 (N), 28));
Nico Huber4dc4c612018-01-10 15:55:09 +0100110
111 function CUR_POS_Y (Y : Int32) return Word32 is
112 ((if Y >= 0 then 0 else 1 * 2 ** 31) or Shift_Left (Word32 (abs Y), 16))
113 with
114 Pre => Y > Int32'First;
115 function CUR_POS_X (X : Int32) return Word32 is
116 ((if X >= 0 then 0 else 1 * 2 ** 15) or Word32 (abs X))
117 with
118 Pre => X > Int32'First;
119
Nico Huber3675db52016-11-04 16:27:29 +0100120 subtype VGA_Cycle_Count is Pos32 range 2 .. 128;
121 function VGA_CONTROL_VSYNC_BLINK_RATE
122 (Cycles : VGA_Cycle_Count)
123 return Word32
124 is
125 begin
126 return Word32 (Cycles) / 2 - 1;
127 end VGA_CONTROL_VSYNC_BLINK_RATE;
128
Nico Huber7ad2d652016-12-07 15:19:32 +0100129 PF_CTRL_ENABLE : constant := 1 * 2 ** 31;
130 PF_CTRL_PIPE_SELECT_MASK : constant := 3 * 2 ** 29;
131 PF_CTRL_FILTER_MED : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200132
Nico Huber7ad2d652016-12-07 15:19:32 +0100133 PS_CTRL_ENABLE_SCALER : constant := 1 * 2 ** 31;
134 PS_CTRL_SCALER_MODE_7X5_EXTENDED : constant := 1 * 2 ** 28;
135 PS_CTRL_FILTER_SELECT_MEDIUM_2 : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200136
Arthur Heymansd5198442018-03-28 17:05:12 +0200137 GMCH_PFIT_CONTROL_SELECT_MASK : constant := 3 * 2 ** 29;
138 GMCH_PFIT_CONTROL_SELECT_PIPE_A : constant := 0 * 2 ** 29;
139 GMCH_PFIT_CONTROL_SELECT_PIPE_B : constant := 1 * 2 ** 29;
Nico Huber958c5642018-06-02 16:59:31 +0200140 GMCH_PFIT_CONTROL_SCALING_MASK : constant := 3 * 2 ** 26;
141 GMCH_PFIT_CONTROL_SCALING : constant array (Scaling_Aspect) of Word32 :=
142 (Uniform => 0 * 2 ** 26,
143 Pillarbox => 2 * 2 ** 26,
144 Letterbox => 3 * 2 ** 26);
Arthur Heymansd5198442018-03-28 17:05:12 +0200145
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200146 VGACNTRL_REG : constant Registers.Registers_Index :=
147 (if Config.Has_GMCH_VGACNTRL then
148 Registers.GMCH_VGACNTRL
149 else Registers.CPU_VGACNTRL);
150
Nico Huber83693c82016-10-08 22:17:55 +0200151 ---------------------------------------------------------------------------
152
Nico Huber83693c82016-10-08 22:17:55 +0200153 function PLANE_WM_LINES (Lines : Natural) return Word32 is
154 begin
155 return Shift_Left (Word32 (Lines), PLANE_WM_LINES_SHIFT)
156 and PLANE_WM_LINES_MASK;
157 end PLANE_WM_LINES;
158
159 function PLANE_WM_BLOCKS (Blocks : Natural) return Word32 is
160 begin
161 return Word32 (Blocks) and PLANE_WM_BLOCKS_MASK;
162 end PLANE_WM_BLOCKS;
163
164 ---------------------------------------------------------------------------
165
Nico Hubera7e1cd32026-07-03 09:23:24 +0000166 subtype Source_Size is Width_Type;
Nico Huberfb6dbad2026-04-10 16:23:39 +0000167
Nico Hubera7e1cd32026-07-03 09:23:24 +0000168 function Encode_Size (LSW, MSW : Source_Size) return Word32
Nico Huberfb6dbad2026-04-10 16:23:39 +0000169 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000170 (Shift_Left (Word32 (MSW) - 1, 16) or (Word32 (LSW) - 1));
171
172 function Source_Width (FB : Framebuffer_Type) return Source_Size
173 is
174 (if Config.Needs_Even_Source_Width and then Rotated_Width (FB) > 2 then
175 Rotated_Width (FB) - Rotated_Width (FB) mod 2
Nico Huberfb6dbad2026-04-10 16:23:39 +0000176 else
Nico Hubera7e1cd32026-07-03 09:23:24 +0000177 Rotated_Width (FB));
Nico Huberfb6dbad2026-04-10 16:23:39 +0000178
Nico Hubera7e1cd32026-07-03 09:23:24 +0000179 function Source_Height (FB : Framebuffer_Type) return Source_Size
Nico Huberfb6dbad2026-04-10 16:23:39 +0000180 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000181 (Rotated_Height (FB));
Nico Huber83693c82016-10-08 22:17:55 +0200182
183 ----------------------------------------------------------------------------
184
Nico Huber83693c82016-10-08 22:17:55 +0200185 procedure Clear_Watermarks (Controller : Controller_Type) is
186 begin
Nico Huber4dc4c612018-01-10 15:55:09 +0100187 Registers.Write (Controller.CUR_BUF_CFG, 16#0000_0000#);
188 for Level in WM_Levels loop
189 Registers.Write (Controller.CUR_WM (Level), 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200190 end loop;
Nico Huber9e78dda2020-10-01 15:30:54 +0200191 Registers.Write (Controller.PLANE_2_BUF_CFG, 16#0000_0000#);
192 for Level in WM_Levels loop
193 Registers.Write (Controller.PLANE_2_WM (Level), 16#0000_0000#);
194 end loop;
Nico Huber4dc4c612018-01-10 15:55:09 +0100195 Registers.Write (Controller.PLANE_BUF_CFG, 16#0000_0000#);
196 for Level in WM_Levels loop
197 Registers.Write (Controller.PLANE_WM (Level), 16#0000_0000#);
198 end loop;
199 Registers.Write (Controller.WM_LINETIME, 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200200 end Clear_Watermarks;
201
202 procedure Setup_Watermarks (Controller : Controller_Type)
203 is
Nico Huber9e78dda2020-10-01 15:30:54 +0200204 subtype Buffer_Count is Natural range 1 .. 508;
205 subtype Buffer_Index is Natural range 0 .. Buffer_Count'Last - 1;
206
207 function Encode_Buffers (Start : Buffer_Index; Count : Buffer_Count)
208 return Word32
209 is
210 (Shift_Left (Word32 (Start + Count - 1), 16) or Word32 (Start));
211
Nico Huberf3e23662016-12-05 21:33:03 +0100212 type Per_Plane_Buffer_Range is array (Pipe_Index) of Word32;
Nico Huber9e78dda2020-10-01 15:30:54 +0200213 Plane_1_Buffer_Range : constant Per_Plane_Buffer_Range :=
214 (Primary => Encode_Buffers ( 0, 150),
215 Secondary => Encode_Buffers (169, 150),
216 Tertiary => Encode_Buffers (338, 150));
217 Plane_2_Buffer_Range : constant Per_Plane_Buffer_Range :=
218 (Primary => Encode_Buffers (150, 11),
219 Secondary => Encode_Buffers (319, 11),
220 Tertiary => Encode_Buffers (488, 11));
Nico Huber4dc4c612018-01-10 15:55:09 +0100221 Cur_Buffer_Range : constant Per_Plane_Buffer_Range :=
Nico Huber9e78dda2020-10-01 15:30:54 +0200222 (Primary => Encode_Buffers (161, 8),
223 Secondary => Encode_Buffers (330, 8),
224 Tertiary => Encode_Buffers (499, 8));
Nico Huber83693c82016-10-08 22:17:55 +0200225 begin
226 Registers.Write
227 (Register => Controller.PLANE_BUF_CFG,
Nico Huber9e78dda2020-10-01 15:30:54 +0200228 Value => Plane_1_Buffer_Range (Controller.Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200229 Registers.Write
230 (Register => Controller.PLANE_WM (0),
231 Value => PLANE_WM_ENABLE or
232 PLANE_WM_LINES (2) or
Nico Huber9e78dda2020-10-01 15:30:54 +0200233 PLANE_WM_BLOCKS (150));
234 Registers.Write
235 (Register => Controller.PLANE_2_BUF_CFG,
236 Value => Plane_2_Buffer_Range (Controller.Pipe));
237 Registers.Write
238 (Register => Controller.PLANE_2_WM (0),
239 Value => PLANE_WM_ENABLE or
240 PLANE_WM_LINES (2) or
241 PLANE_WM_BLOCKS (11));
Nico Huber4dc4c612018-01-10 15:55:09 +0100242 Registers.Write
243 (Register => Controller.CUR_BUF_CFG,
244 Value => Cur_Buffer_Range (Controller.Pipe));
245 Registers.Write
246 (Register => Controller.CUR_WM (0),
247 Value => PLANE_WM_ENABLE or
248 PLANE_WM_LINES (2) or
249 PLANE_WM_BLOCKS (8));
Nico Huber83693c82016-10-08 22:17:55 +0200250 end Setup_Watermarks;
251
252 ----------------------------------------------------------------------------
253
Nico Huber3675db52016-11-04 16:27:29 +0100254 procedure Setup_Hires_Plane
Nico Huber6a4dfc82016-11-04 15:50:58 +0100255 (Controller : Controller_Type;
Nico Huber0164b022017-08-24 15:12:51 +0200256 FB : HW.GFX.Framebuffer_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200257 with
Nico Huber5ef4d602017-12-13 13:56:47 +0100258 Pre => FB.Height + FB.Start_Y <= FB.V_Stride
Nico Huber83693c82016-10-08 22:17:55 +0200259 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000260 Width : constant Source_Size := Source_Width (FB);
261 Height : constant Source_Size := Source_Height (FB);
Nico Huberfb6dbad2026-04-10 16:23:39 +0000262
Nico Huber83693c82016-10-08 22:17:55 +0200263 -- FIXME: setup correct format, based on framebuffer RGB format
264 Format : constant Word32 := 6 * 2 ** 26;
Arthur Heymans960e2392026-03-03 19:45:24 +0100265 PRI : Word32 := Format;
Nico Huber83693c82016-10-08 22:17:55 +0200266 begin
267 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
268
Nico Huber83693c82016-10-08 22:17:55 +0200269 if Config.Has_Plane_Control then
Nico Huber9b479412017-08-27 11:55:56 +0200270 declare
Nico Huber34be6542017-12-13 09:26:24 +0100271 Stride, Offset : Word32;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600272
273 function PLANE_CTL_ARB_SLOTS (N : Word32) return Word32 is
274 (if Config.Need_Pipe_Arb_Slots then Shift_Left (N, 28) else 0);
275
276 -- TODO: Hard coded format and arbitration slots for now,
277 -- for 4B-per-pixel XRGB, just like `Format` above.
278 -- ARB_SLOTS(1) matches the 4B per pixel.
279 Plane_Ctl : constant Word32 :=
280 PLANE_CTL_PLANE_ENABLE or
281 PLANE_CTL_TILED_SURFACE (FB.Tiling) or
282 PLANE_CTL_PLANE_ROTATION (FB.Rotation) or
283 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
284 PLANE_CTL_ARB_SLOTS (1) or
285 (if not Config.Has_Plane_Color_Control
286 then PLANE_CTL_PLANE_GAMMA_DISABLE
287 else 0);
Nico Huber9b479412017-08-27 11:55:56 +0200288 begin
289 if Rotation_90 (FB) then
Nico Huber5ef4d602017-12-13 13:56:47 +0100290 Stride := Word32 (FB_Pitch (FB.V_Stride, FB));
291 Offset := Shift_Left (Word32 (FB.Start_X), 16) or
292 Word32 (FB.V_Stride - FB.Height - FB.Start_Y);
Nico Huber9b479412017-08-27 11:55:56 +0200293 else
Nico Huber5ef4d602017-12-13 13:56:47 +0100294 Stride := Word32 (FB_Pitch (FB.Stride, FB));
295 Offset := Shift_Left (Word32 (FB.Start_Y), 16) or
296 Word32 (FB.Start_X);
Nico Huber9b479412017-08-27 11:55:56 +0200297 end if;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600298
299 if Config.Has_Plane_Color_Control then
300 Registers.Write
301 (Register => Controller.PLANE_COLOR_CTL,
302 Value => PLANE_COLOR_CTL_PLANE_GAMMA_DISABLE);
303 end if;
304 Registers.Write (Controller.PLANE_AUX_DIST, 0);
305 Registers.Write (Controller.PLANE_CTL, Plane_Ctl);
Nico Huber9b479412017-08-27 11:55:56 +0200306 Registers.Write (Controller.PLANE_OFFSET, Offset);
Nico Huberfb6dbad2026-04-10 16:23:39 +0000307 Registers.Write (Controller.PLANE_SIZE, Encode_Size (Width, Height));
Nico Huber9b479412017-08-27 11:55:56 +0200308 Registers.Write (Controller.PLANE_STRIDE, Stride);
309 Registers.Write (Controller.PLANE_POS, 16#0000_0000#);
Nico Huber34be6542017-12-13 09:26:24 +0100310 Registers.Write (Controller.PLANE_SURF, FB.Offset and 16#ffff_f000#);
Nico Huber9b479412017-08-27 11:55:56 +0200311 end;
Nico Huber83693c82016-10-08 22:17:55 +0200312 else
Arthur Heymans960e2392026-03-03 19:45:24 +0100313 if Config.Has_DSPCNTR_Pipe_Select then
314 PRI := PRI or DSPCNTR_PIPE_SEL (Controller.Pipe);
315 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200316 if Config.Disable_Trickle_Feed then
317 PRI := PRI or DSPCNTR_DISABLE_TRICKLE_FEED;
318 end if;
Arthur Heymans960e2392026-03-03 19:45:24 +0100319
320 -- Write DSPCNTR *without* the enable bit first. On pre-SKL
321 -- hardware the control register self-arms when the plane
322 -- transitions from disabled to enabled, latching whatever
323 -- stride/size/offset values happen to be in the registers at
324 -- that moment. Programming format, pipe-select, and trickle-
325 -- feed now avoids a glitch with stale geometry values.
Nico Huber83693c82016-10-08 22:17:55 +0200326 Registers.Unset_And_Set_Mask
327 (Register => Controller.DSPCNTR,
328 Mask_Unset => DSPCNTR_MASK,
Nico Huberab69e362018-05-29 21:20:30 +0200329 Mask_Set => PRI or DSPCNTR_TILED_SURFACE (FB.Tiling));
Nico Huber83693c82016-10-08 22:17:55 +0200330
Nico Huber0164b022017-08-24 15:12:51 +0200331 Registers.Write
332 (Controller.DSPSTRIDE, Word32 (Pixel_To_Bytes (FB.Stride, FB)));
Arthur Heymans960e2392026-03-03 19:45:24 +0100333
334 -- Gen3 (i945): program DSPSIZE and DSPPOS before the surface
335 -- address write that arms the double-buffered plane registers.
336 if Config.Gen_I945 then
Nico Huberfb6dbad2026-04-10 16:23:39 +0000337 Registers.Write (Controller.DSPSIZE, Encode_Size (Width, Height));
Arthur Heymans960e2392026-03-03 19:45:24 +0100338 Registers.Write (Controller.DSPPOS, 16#0000_0000#);
339 end if;
340
Nico Huberab69e362018-05-29 21:20:30 +0200341 if Config.Has_DSP_Linoff and then FB.Tiling = Linear then
Arthur Heymans3f37cce2026-03-03 18:52:12 +0100342 pragma Assert_And_Cut
343 (FB.Start_Y * FB.Stride + FB.Start_X in Pixel_Type);
Nico Huberd49b56b2018-06-18 17:19:15 +0200344 declare
345 Linear_Offset : constant Pixel_Type :=
346 FB.Start_Y * FB.Stride + FB.Start_X;
347 begin
348 Registers.Write
349 (Register => Controller.DSPLINOFF,
Arthur Heymans960e2392026-03-03 19:45:24 +0100350 Value => (if Config.Has_DSPSURF
351 then Word32 (Pixel_To_Bytes (Linear_Offset, FB))
352 else (FB.Offset and 16#ffff_f000#) or
353 Word32 (Pixel_To_Bytes (Linear_Offset, FB))));
Nico Huberd49b56b2018-06-18 17:19:15 +0200354 Registers.Write (Controller.DSPTILEOFF, 0);
355 end;
Nico Huber5ef4d602017-12-13 13:56:47 +0100356 else
Nico Huberab69e362018-05-29 21:20:30 +0200357 if Config.Has_DSP_Linoff then
Arthur Heymans960e2392026-03-03 19:45:24 +0100358 Registers.Write (Controller.DSPLINOFF,
359 (if Config.Has_DSPSURF then 0
360 else FB.Offset and 16#ffff_f000#));
Nico Huberab69e362018-05-29 21:20:30 +0200361 end if;
Nico Huber5ef4d602017-12-13 13:56:47 +0100362 Registers.Write
363 (Register => Controller.DSPTILEOFF,
364 Value => Shift_Left (Word32 (FB.Start_Y), 16) or
365 Word32 (FB.Start_X));
Nico Huber83693c82016-10-08 22:17:55 +0200366 end if;
Arthur Heymans960e2392026-03-03 19:45:24 +0100367 if Config.Has_DSPSURF then
368 Registers.Write (Controller.DSPSURF, FB.Offset and 16#ffff_f000#);
369 end if;
370
371 -- Now enable the plane. All geometry registers are in place,
372 -- so the self-arm latches correct values.
373 Registers.Write
374 (Register => Controller.DSPCNTR,
375 Value => DSPCNTR_ENABLE or PRI or
376 DSPCNTR_TILED_SURFACE (FB.Tiling));
Nico Huber83693c82016-10-08 22:17:55 +0200377 end if;
Nico Huber3675db52016-11-04 16:27:29 +0100378 end Setup_Hires_Plane;
379
380 procedure Setup_Display
Nico Huber113a14b2016-12-06 21:59:15 +0100381 (Controller : Controller_Type;
382 Framebuffer : Framebuffer_Type;
383 Dither_BPC : BPC_Type;
384 Dither : Boolean)
Nico Huber3675db52016-11-04 16:27:29 +0100385 with
Nico Huber9b479412017-08-27 11:55:56 +0200386 Pre =>
387 Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
Nico Huber5ef4d602017-12-13 13:56:47 +0100388 Framebuffer.Height + Framebuffer.Start_Y <= Framebuffer.V_Stride
Nico Huber3675db52016-11-04 16:27:29 +0100389 is
390 use type Word8;
391
392 Reg8 : Word8;
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600393
394 type BW_Credit is new Natural range 0 .. 3;
395 function MBUS_DBOX_BW_CREDIT (C : BW_Credit) return Word32 is
396 (Shift_Left (Word32 (C), 14));
397
398 type B_Credit is new Natural range 0 .. 31;
399 function MBUS_DBOX_B_CREDIT (C : B_Credit) return Word32 is
400 (Shift_Left (Word32 (C), 8));
401
402 type A_Credit is new Natural range 0 .. 15;
403 function MBUS_DBOX_A_CREDIT (C : A_Credit) return Word32 is
404 (Word32 (C));
405
406 type B2B_Trans_Max is new Natural range 0 .. 31;
407 function MBUS_DBOX_B2B_TRANSACTIONS_MAX (B : B2B_Trans_Max) return Word32 is
408 (Shift_Left (Word32 (B), 20));
409
410 type B2B_Trans_Delay is new Natural range 0 .. 7;
411 function MBUS_DBOX_B2B_TRANSACTIONS_DELAY (B : B2B_Trans_Delay) return Word32 is
412 (Shift_Left (Word32 (B), 17));
413 MBUS_DBOX_REGULATE_B2B_TRANSACTIONS_EN : constant := 1 * 2 ** 16;
414
415 procedure Program_Mbus_Dbox_Credits is
416 Tmp : Word32;
417 begin
418 Tmp := MBUS_DBOX_B2B_TRANSACTIONS_MAX (16) or
419 MBUS_DBOX_B2B_TRANSACTIONS_DELAY (1) or
420 MBUS_DBOX_REGULATE_B2B_TRANSACTIONS_EN;
421
422 if Config.Has_New_Mbus_Dbox_Credits then
423 Tmp := Tmp or MBUS_DBOX_BW_CREDIT (2) or
424 MBUS_DBOX_B_CREDIT (8) or
425 MBUS_DBOX_A_CREDIT (4); -- No joined MBus support,
426 -- hence always use 4 for now.
427 else
428 Tmp := Tmp or MBUS_DBOX_BW_CREDIT (2) or
429 MBUS_DBOX_B_CREDIT (12) or
430 MBUS_DBOX_A_CREDIT (2);
431 end if;
432
433 Registers.Write
434 (Register => Controller.MBUS_DBOX_CTL,
435 Value => Tmp);
436 end Program_Mbus_Dbox_Credits;
437
438 -- Display WA # 1605353570: icl
439 -- Set the pixel rounding bit to 1 for allowing
440 -- passthrough of Frame buffer pixels unmodified
441 -- across pipe
442 PIXEL_ROUNDING_TRUNC_FB_PASSTHRU : constant := 1 * 2 ** 15;
443
444 -- Display WA #1153: icl
445 -- enable hardware to bypass the alpha math
446 -- and rounding for per-pixel values 00 and 0xff
447 PER_PIXEL_ALPHA_BYPASS_EN : constant := 1 * 2 ** 7;
448
449 -- ADL_P requires that we disable underrun recovery when
450 -- downscaling (or using the scaler for YUV420 pipe output),
451 -- using DSC, or using PSR2.
452 -- i915 always disables underrun recovery for gen 13+.
453 UNDERRUN_RECOVERY_DISABLE : constant := 1 * 2 ** 30;
Nico Huberfb6dbad2026-04-10 16:23:39 +0000454
Nico Hubera7e1cd32026-07-03 09:23:24 +0000455 Width : constant Source_Size := Source_Width (Framebuffer);
456 Height : constant Source_Size := Source_Height (Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100457 begin
458 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
459
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600460 if Config.Has_Type_C_Ports then
461 Registers.Set_Mask
462 (Register => Controller.PIPE_CHICKEN,
463 Mask => PER_PIXEL_ALPHA_BYPASS_EN or
464 PIXEL_ROUNDING_TRUNC_FB_PASSTHRU or
465 (if Config.Need_Underrun_Rec_Disable
466 then UNDERRUN_RECOVERY_DISABLE
467 else 0));
468 end if;
469
Nico Huber3675db52016-11-04 16:27:29 +0100470 if Config.Has_Plane_Control then
471 Setup_Watermarks (Controller);
472 end if;
473
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600474 if Config.Has_Mbus_Dbox_Credits then
475 Program_Mbus_Dbox_Credits;
476 end if;
477
Nico Huber3675db52016-11-04 16:27:29 +0100478 if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
Nico Huberfbb42202016-11-07 15:08:26 +0100479 if Config.VGA_Plane_Workaround then
480 Registers.Unset_And_Set_Mask
481 (Register => Registers.ILK_DISPLAY_CHICKEN1,
482 Mask_Unset => ILK_DISPLAY_CHICKEN1_VGA_MASK,
483 Mask_Set => ILK_DISPLAY_CHICKEN1_VGA_ENABLE);
484 Registers.Unset_And_Set_Mask
485 (Register => Registers.ILK_DISPLAY_CHICKEN2,
486 Mask_Unset => ILK_DISPLAY_CHICKEN2_VGA_MASK,
487 Mask_Set => ILK_DISPLAY_CHICKEN2_VGA_ENABLE);
488 end if;
489
Nico Huber3675db52016-11-04 16:27:29 +0100490 Registers.Unset_And_Set_Mask
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200491 (Register => VGACNTRL_REG,
Nico Huber3675db52016-11-04 16:27:29 +0100492 Mask_Unset => VGA_CONTROL_VGA_DISPLAY_DISABLE or
493 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK or
494 VGA_CONTROL_VSYNC_BLINK_RATE_MASK,
495 Mask_Set => VGA_CONTROL_BLINK_DUTY_CYCLE_50 or
496 VGA_CONTROL_VSYNC_BLINK_RATE (30));
497
498 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
499 Port_IO.InB (Reg8, VGA_SR_DATA);
500 Port_IO.OutB (VGA_SR_DATA, Reg8 and not (VGA_SR01_SCREEN_OFF));
501 else
Nico Huber6a4dfc82016-11-04 15:50:58 +0100502 Setup_Hires_Plane (Controller, Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100503 end if;
504
505 Registers.Write
506 (Register => Controller.PIPESRC,
Nico Huberfb6dbad2026-04-10 16:23:39 +0000507 Value => Encode_Size (Height, Width));
Nico Huber83693c82016-10-08 22:17:55 +0200508
Nico Huber113a14b2016-12-06 21:59:15 +0100509 if Config.Has_Pipeconf_Misc then
510 Registers.Write
511 (Register => Controller.PIPEMISC,
Tim Wawrzynczak0da761a2022-09-09 10:42:36 -0600512 Value => Transcoder.BPC_Conf (Dither_BPC, Dither) or
513 -- FIXME: Should we set these at all?
514 (if Config.Has_Plane_Color_Control then
515 (PIPEMISC_PIXEL_ROUNDING_TRUNC or PIPEMISC_HDR_MODE_PRECISION) else 0));
Nico Huber113a14b2016-12-06 21:59:15 +0100516 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200517 end Setup_Display;
518
519 ----------------------------------------------------------------------------
520
Nico Huber5903f922020-10-05 14:15:57 +0200521 function Use_Plane_For_Cursor (FB : Framebuffer_Type) return Boolean is
522 (Config.Has_Plane_Control and then FB.Tiling = Y_Tiled);
523
Nico Huber4dc4c612018-01-10 15:55:09 +0100524 procedure Update_Cursor
525 (Pipe : Pipe_Index;
526 FB : Framebuffer_Type;
527 Cursor : Cursor_Type)
528 is
Nico Huber5903f922020-10-05 14:15:57 +0200529 Controller : Controller_Type renames Controllers (Pipe);
Nico Huber4dc4c612018-01-10 15:55:09 +0100530 begin
Nico Huber5903f922020-10-05 14:15:57 +0200531 if Use_Plane_For_Cursor (FB) then
532 if Config.Has_Plane_Color_Control then
533 Registers.Write
534 (Register => Controller.PLANE_2_COLOR_CTL,
535 Value => PLANE_COLOR_CTL_PLANE_GAMMA_DISABLE or
536 PLANE_COLOR_CTL_ALPHA_MODE_SW_PREMUL);
537 end if;
538 else
539 -- on some platforms writing CUR_CTL disables self-arming of CUR_POS
540 -- so keep it first
541 Registers.Write
542 (Register => Cursors (Pipe).CTL,
543 Value => CUR_CTL_MODE (Cursor.Mode, Cursor.Size) or
544 (if Config.Need_Pipe_Arb_Slots
545 then MCURSOR_ARB_SLOTS (1)
546 else CUR_CTL_PIPE_SELECT (Pipe)));
547 end if;
548 Place_Cursor (Pipe, FB, Cursor, (Cursor.Center_X, Cursor.Center_Y), Update => True);
Nico Huber4dc4c612018-01-10 15:55:09 +0100549 end Update_Cursor;
550
551 procedure Place_Cursor
552 (Pipe : Pipe_Index;
553 FB : Framebuffer_Type;
Nico Huber1dae2202020-10-05 13:31:25 +0200554 Cursor : Cursor_Type;
Nico Huber5903f922020-10-05 14:15:57 +0200555 Center : Cursor_Coord;
556 Update : Boolean := False)
Nico Huber4dc4c612018-01-10 15:55:09 +0100557 is
Nico Huber5903f922020-10-05 14:15:57 +0200558 Controller : Controller_Type renames Controllers (Pipe);
559
Nico Huber4dc4c612018-01-10 15:55:09 +0100560 Width : constant Width_Type := Cursor_Width (Cursor.Size);
Nico Huber5903f922020-10-05 14:15:57 +0200561 Surface_Width : constant Width_Type := Source_Width (FB);
562 Surface_Height : constant Height_Type := Source_Height (FB);
Nico Huber3d7c33f2020-10-01 15:14:38 +0200563
Nico Huber902d8032020-10-05 14:14:16 +0200564 -- Like `Cursor_Pos`/`Cursor_Coord` but allowing wider range for proof.
565 subtype Relaxed_Pos is Int32 range
566 Cursor_Pos'First - Width_Type'Last .. Cursor_Pos'Last + Width_Type'Last;
567 type Relaxed_Coord is record
568 X : Relaxed_Pos;
569 Y : Relaxed_Pos;
570 end record;
571
Nico Huber3d7c33f2020-10-01 15:14:38 +0200572 -- The cursor's coordinates are on the framebuffer surface
573 -- but we need to place it on the physical screen:
Nico Huber902d8032020-10-05 14:14:16 +0200574 function Rotate (Center : Cursor_Coord) return Relaxed_Coord is
575 (X =>
576 (case FB.Rotation is
577 when No_Rotation => Center.X,
578 when Rotated_90 => FB.Height - 1 - Center.Y,
579 when Rotated_180 => FB.Width - 1 - Center.X,
580 when Rotated_270 => Center.Y),
581 Y =>
582 (case FB.Rotation is
583 when No_Rotation => Center.Y,
584 when Rotated_90 => Center.X,
585 when Rotated_180 => FB.Height - 1 - Center.Y,
586 when Rotated_270 => FB.Width - 1 - Center.X));
Nico Huber3d7c33f2020-10-01 15:14:38 +0200587
Nico Huber902d8032020-10-05 14:14:16 +0200588 -- Calculates the coordinates of the cursor plane's
589 -- upper-left corner on the bigger screen (pipe input).
590 function Phys_Origin (Center : Cursor_Coord) return Relaxed_Coord is
591 (X => Rotate (Center).X - Width / 2,
592 Y => Rotate (Center).Y - Width / 2);
593
Nico Huber5903f922020-10-05 14:15:57 +0200594 function Fully_Visible (Origin : Relaxed_Coord) return Boolean is
595 (Origin.X in 0 .. Surface_Width - Width - 1 and
596 Origin.Y in 0 .. Surface_Height - Width - 1);
597
Nico Huber902d8032020-10-05 14:14:16 +0200598 Origin : Relaxed_Coord := Phys_Origin (Center);
Nico Huber5903f922020-10-05 14:15:57 +0200599
600 Visible : constant Boolean :=
601 Origin.X in -Width + 1 .. Surface_Width - 1 and
602 Origin.Y in -Width + 1 .. Surface_Height - 1;
Nico Huber4dc4c612018-01-10 15:55:09 +0100603 begin
Nico Huber5903f922020-10-05 14:15:57 +0200604 if Use_Plane_For_Cursor (FB) and then
605 ((Update and Cursor.Mode /= ARGB_Cursor) or not Visible)
Nico Huber4dc4c612018-01-10 15:55:09 +0100606 then
Nico Huber5903f922020-10-05 14:15:57 +0200607 Registers.Write
608 (Register => Controller.PLANE_2_CTL,
609 Value => 0,
610 Verbose => False);
611 Registers.Write -- arming
612 (Register => Controller.PLANE_2_SURF,
613 Value => 0,
614 Verbose => False);
615 elsif Use_Plane_For_Cursor (FB) then
616 -- we may have to configure all registers
617 if Update or
618 not Fully_Visible (Phys_Origin ((Cursor.Center_X, Cursor.Center_Y))) or
619 not Fully_Visible (Origin)
620 then
621 declare
622 Visible_Width : Width_Type := Width;
623 Visible_Height : Height_Type := Width;
624 Offset_X : Word32;
625 Offset_Y : Word32;
626
627 -- Calculates where to start reading from the cursor plane's
628 -- framebuffer, iow. gives the first visible pixel of the
629 -- cursor (e.g. for an unrotated cursor whose upper-left
630 -- corner left the screen).
631 function Offset (Pos : Relaxed_Pos; Visible : Int32) return Word32
632 is
633 (if (Pos < 0 and FB.Rotation <= Rotated_90) or
634 (Pos >= 0 and FB.Rotation >= Rotated_180)
635 then Word32 (Width - Visible) else 0)
636 with
637 Pre => Visible in 0 .. Width;
638 begin
639 -- The hardware does neither support negative positions nor
640 -- clipping. So if the cursor should be clipped at an edge
641 -- of the framebuffer, we need to make these calculations
642 -- manually:
643
644 if Origin.X < 0 then
645 Visible_Width := Visible_Width + Origin.X;
646 elsif Origin.X > Surface_Width - Width then
647 Visible_Width := Surface_Width - Origin.X;
648 end if;
649 Offset_X := Offset (Origin.X, Visible_Width);
650 Origin.X := Int32'Max (Origin.X, 0);
651
652 if Origin.Y < 0 then
653 Visible_Height := Visible_Height + Origin.Y;
654 elsif Origin.Y > Surface_Height - Width then
655 Visible_Height := Surface_Height - Origin.Y;
656 end if;
657 Offset_Y := Offset (Origin.Y, Visible_Height);
658 Origin.Y := Int32'Max (Origin.Y, 0);
659
660 Registers.Write
661 (Register => Controller.PLANE_2_CTL,
662 Value => PLANE_CTL_PLANE_ENABLE or
663 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
664 PLANE_CTL_TILED_SURFACE (FB.Tiling) or
665 PLANE_CTL_PLANE_ROTATION (FB.Rotation) or
666 (if not Config.Has_Plane_Color_Control
667 then PLANE_CTL_PLANE_GAMMA_DISABLE or
668 PLANE_CTL_ALPHA_MODE_SW_PREMULTIPLY
669 else 0),
670 Verbose => False);
671 Registers.Write
672 (Register => Controller.PLANE_2_OFFSET,
673 Value => Shift_Left (Offset_Y, 16) or Offset_X,
674 Verbose => False);
675 Registers.Write
676 (Register => Controller.PLANE_2_SIZE,
677 Value => Encode_Size (Visible_Width, Visible_Height),
678 Verbose => False);
679 Registers.Write
680 (Register => Controller.PLANE_2_STRIDE,
681 Value => Word32 (FB_Pitch (Width, FB)),
682 Verbose => False);
683 end;
684 end if;
685
686 Registers.Write
687 (Register => Controller.PLANE_2_POS,
688 Value => Shift_Left (Word32 (Origin.Y), 16) or Word32 (Origin.X),
689 Verbose => False);
690 Registers.Write -- arming
691 (Register => Controller.PLANE_2_SURF,
692 Value => Shift_Left (Word32 (Cursor.GTT_Offset), 12),
693 Verbose => False);
694 else
695 -- off-screen cursor needs special care
696 if not Visible or
697 Origin.X > Config.Maximum_Cursor_X or
698 Origin.Y > Config.Maximum_Cursor_Y
699 then
700 Origin.X := -Width;
701 Origin.Y := -Width;
702 end if;
703 Registers.Write
704 (Register => Cursors (Pipe).POS,
705 Value => CUR_POS_Y (Origin.Y) or CUR_POS_X (Origin.X),
706 Verbose => False);
707 -- write to CUR_BASE always arms other CUR_* registers
708 Registers.Write
709 (Register => Cursors (Pipe).BASE,
710 Value => Shift_Left (Word32 (Cursor.GTT_Offset), 12),
711 Verbose => False);
Nico Huber4dc4c612018-01-10 15:55:09 +0100712 end if;
Nico Huber4dc4c612018-01-10 15:55:09 +0100713 end Place_Cursor;
714
715 ----------------------------------------------------------------------------
716
Nico Huber4916e342016-11-04 14:37:53 +0100717 procedure Scale_Keep_Aspect
Nico Huberc5c767a2018-06-03 01:09:04 +0200718 (Width : out Width_Type;
719 Height : out Height_Type;
720 Max_Width : in Width_Type;
721 Max_Height : in Height_Type;
Nico Huber4916e342016-11-04 14:37:53 +0100722 Framebuffer : in Framebuffer_Type)
723 with
724 Pre =>
Nico Hubera7e1cd32026-07-03 09:23:24 +0000725 Source_Width (Framebuffer) <= Max_Width and
726 Source_Height (Framebuffer) <= Max_Height,
Nico Huber4916e342016-11-04 14:37:53 +0100727 Post =>
728 Width <= Max_Width and Height <= Max_Height
729 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000730 Src_Width : constant Width_Type := Source_Width (Framebuffer);
731 Src_Height : constant Height_Type := Source_Height (Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100732 begin
Nico Huberda1185e2018-06-03 01:07:46 +0200733 case Scaling_Type (Src_Width, Src_Height, Max_Width, Max_Height) is
734 when Letterbox =>
Nico Huber99200fe2026-04-14 16:37:45 +0200735 Height := (Src_Height * Max_Width) / Src_Width;
736 pragma Assert (Height <= Max_Height);
Nico Huberda1185e2018-06-03 01:07:46 +0200737 Width := Max_Width;
Nico Huberda1185e2018-06-03 01:07:46 +0200738 when Pillarbox =>
Nico Huber99200fe2026-04-14 16:37:45 +0200739 Width := (Src_Width * Max_Height) / Src_Height;
740 pragma Assert (Max_Height * Src_Width < Max_Width * Src_Height);
741 pragma Assert ((Max_Height * Src_Width) / Src_Height < Max_Width);
742 pragma Assert (Width <= Max_Width);
Nico Huberda1185e2018-06-03 01:07:46 +0200743 Height := Max_Height;
744 when Uniform =>
745 Width := Max_Width;
746 Height := Max_Height;
747 end case;
Nico Huber4916e342016-11-04 14:37:53 +0100748 end Scale_Keep_Aspect;
749
Nico Huberba84df22026-06-23 13:29:29 +0000750 procedure Scale
751 (Width : out Width_Type;
752 Height : out Height_Type;
753 Scaling : in GMA.Scaling;
754 Max_Width : in Width_Type;
755 Max_Height : in Height_Type;
756 Framebuffer : in Framebuffer_Type)
757 with
758 Pre =>
Nico Hubera7e1cd32026-07-03 09:23:24 +0000759 Source_Width (Framebuffer) <= Max_Width and
760 Source_Height (Framebuffer) <= Max_Height,
Nico Huberba84df22026-06-23 13:29:29 +0000761 Post =>
762 Width <= Max_Width and Height <= Max_Height
763 is
764 begin
765 case Scaling is
766 when None =>
Nico Hubera7e1cd32026-07-03 09:23:24 +0000767 Width := Source_Width (Framebuffer);
768 Height := Source_Height (Framebuffer);
Nico Huberba84df22026-06-23 13:29:29 +0000769 when Fit =>
770 Scale_Keep_Aspect (Width, Height, Max_Width, Max_Height, Framebuffer);
771 when Stretch =>
772 Width := Max_Width;
773 Height := Max_Height;
774 end case;
775 end Scale;
776
777 procedure Align_Framebuffer
778 (Pos_X : out Position_Type;
779 Pos_Y : out Position_Type;
780 Align : in Alignment;
781 Width : in Width_Type;
782 Height : in Height_Type;
783 Mode : in Mode_Type)
784 with
785 Pre => Width <= Mode.H_Visible and Height <= Mode.V_Visible
786 is
787 Gap_X : constant Position_Type := Mode.H_Visible - Width;
788 Gap_Y : constant Position_Type := Mode.V_Visible - Height;
789 begin
790 case Align is
791 when Top_Left => Pos_X := 0; Pos_Y := 0;
792 when Top => Pos_X := Gap_X / 2; Pos_Y := 0;
793 when Top_Right => Pos_X := Gap_X; Pos_Y := 0;
794 when Left => Pos_X := 0; Pos_Y := Gap_Y / 2;
795 when Center => Pos_X := Gap_X / 2; Pos_Y := Gap_Y / 2;
796 when Right => Pos_X := Gap_X; Pos_Y := Gap_Y / 2;
797 when Bottom_Left => Pos_X := 0; Pos_Y := Gap_Y;
798 when Bottom => Pos_X := Gap_X / 2; Pos_Y := Gap_Y;
799 when Bottom_Right => Pos_X := Gap_X; Pos_Y := Gap_Y;
800 end case;
801 end Align_Framebuffer;
802
Nico Huberfb6dbad2026-04-10 16:23:39 +0000803 type Pipe_Scaler_Limit_Config is record
804 Control : Word32;
805 Horizontal : Pos32;
806 Vertical : Pos32;
807 end record;
808
809 function Skylake_Scaler_Limits
810 (Controller : Controller_Type;
811 Width : Width_Type;
812 Height : Height_Type)
813 return Pipe_Scaler_Limit_Config
814 with
815 Post => Skylake_Scaler_Limits'Result.Horizontal >= Width
816 and Skylake_Scaler_Limits'Result.Vertical >= Height
817 is
818 use type Registers.Registers_Invalid_Index;
819
820 -- Enable 7x5 extended mode where possible:
821 Scaler_Mode : constant Word32 :=
822 (if Controller.PS_CTRL_2 /= Registers.Invalid_Register then
823 PS_CTRL_SCALER_MODE_7X5_EXTENDED else 0);
824
825 -- We can scale up to 2.99x horizontally:
826 Horizontal_Limit : constant Pos32 := (Width * 299) / 100;
827 -- The third scaler is limited to 1.99x
828 -- vertical scaling for source widths > 2048:
829 Vertical_Limit : constant Pos32 :=
830 (Height *
831 (if Controller.PS_CTRL_2 = Registers.Invalid_Register and
832 Width > 2048
833 then
834 199
835 else
836 299)) / 100;
837 begin
838 return (Scaler_Mode, Horizontal_Limit, Vertical_Limit);
839 end Skylake_Scaler_Limits;
840
841 function Tigerlake_Scaler_Limits
842 (Width : Width_Type;
843 Height : Height_Type)
844 return Pipe_Scaler_Limit_Config
845 with
846 Post => Tigerlake_Scaler_Limits'Result.Horizontal >= Width
847 and Tigerlake_Scaler_Limits'Result.Vertical >= Height
848 is
849 Scaling : constant := 32_000; -- PRM says: Scaling * 2**15 >= 1.0
850 -- so virtually unlimited
851 begin
852 return (Control => 0, Horizontal => Width * Scaling, Vertical => Height * Scaling);
853 end Tigerlake_Scaler_Limits;
854
Nico Huber4916e342016-11-04 14:37:53 +0100855 procedure Setup_Skylake_Pipe_Scaler
856 (Controller : in Controller_Type;
Nico Huber4d592b42026-06-23 12:21:37 +0000857 Pipe_Cfg : in Pipe_Config;
858 Mode : in HW.GFX.Mode_Type)
Nico Huber4916e342016-11-04 14:37:53 +0100859 with
860 Pre =>
Nico Huber4d592b42026-06-23 12:21:37 +0000861 Rotated_Width (Pipe_Cfg.Framebuffer) <= Mode.H_Visible and
862 Rotated_Height (Pipe_Cfg.Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100863 is
Nico Hubera7e1cd32026-07-03 09:23:24 +0000864 Width_In : constant Width_Type := Source_Width (Pipe_Cfg.Framebuffer);
865 Height_In : constant Height_Type := Source_Height (Pipe_Cfg.Framebuffer);
Nico Huberfb6dbad2026-04-10 16:23:39 +0000866 Limits : constant Pipe_Scaler_Limit_Config :=
867 (if Config.Has_Skylake_Scaler_Limits then
868 Skylake_Scaler_Limits (Controller, Width_In, Height_In)
869 else
870 Tigerlake_Scaler_Limits (Width_In, Height_In));
Nico Huber4916e342016-11-04 14:37:53 +0100871
Nico Huberc5c767a2018-06-03 01:09:04 +0200872 Width : Width_Type;
873 Height : Height_Type;
Nico Huberba84df22026-06-23 13:29:29 +0000874 Pos_X, Pos_Y : Position_Type;
Nico Huber4916e342016-11-04 14:37:53 +0100875 begin
876 -- Writes to WIN_SZ arm the PS registers.
877
Nico Huberba84df22026-06-23 13:29:29 +0000878 Scale
Nico Huber4916e342016-11-04 14:37:53 +0100879 (Width => Width,
880 Height => Height,
Nico Huberba84df22026-06-23 13:29:29 +0000881 Scaling => Pipe_Cfg.Scaling,
Nico Huberfb6dbad2026-04-10 16:23:39 +0000882 Max_Width => Pos32'Min (Limits.Horizontal, Mode.H_Visible),
883 Max_Height => Pos32'Min (Limits.Vertical, Mode.V_Visible),
Nico Huber4d592b42026-06-23 12:21:37 +0000884 Framebuffer => Pipe_Cfg.Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100885
Nico Huberba84df22026-06-23 13:29:29 +0000886 Align_Framebuffer
887 (Pos_X => Pos_X,
888 Pos_Y => Pos_Y,
889 Align => Pipe_Cfg.Alignment,
890 Width => Width,
891 Height => Height,
892 Mode => Mode);
893
Nico Huber4916e342016-11-04 14:37:53 +0100894 Registers.Write
895 (Register => Controller.PS_CTRL_1,
Nico Huberfb6dbad2026-04-10 16:23:39 +0000896 Value => PS_CTRL_ENABLE_SCALER or Limits.Control);
Nico Huber4916e342016-11-04 14:37:53 +0100897 Registers.Write
898 (Register => Controller.PS_WIN_POS_1,
Nico Huberba84df22026-06-23 13:29:29 +0000899 Value => Shift_Left (Word32 (Pos_X), 16) or Word32 (Pos_Y));
Nico Huber4916e342016-11-04 14:37:53 +0100900 Registers.Write
901 (Register => Controller.PS_WIN_SZ_1,
902 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
903 end Setup_Skylake_Pipe_Scaler;
904
905 procedure Setup_Ironlake_Panel_Fitter
906 (Controller : in Controller_Type;
Nico Huber4d592b42026-06-23 12:21:37 +0000907 Pipe_Cfg : in Pipe_Config;
908 Mode : in HW.GFX.Mode_Type)
Nico Huber4916e342016-11-04 14:37:53 +0100909 with
910 Pre =>
Nico Huber4d592b42026-06-23 12:21:37 +0000911 Rotated_Width (Pipe_Cfg.Framebuffer) <= Mode.H_Visible and
912 Rotated_Height (Pipe_Cfg.Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100913 is
914 -- Force 1:1 mapping of panel fitter:pipe
915 PF_Ctrl_Pipe_Sel : constant Word32 :=
916 (if Config.Has_PF_Pipe_Select then
917 (case Controller.PF_CTRL is
918 when Registers.PFA_CTL_1 => 0 * 2 ** 29,
919 when Registers.PFB_CTL_1 => 1 * 2 ** 29,
920 when Registers.PFC_CTL_1 => 2 * 2 ** 29,
921 when others => 0) else 0);
922
Nico Huberc5c767a2018-06-03 01:09:04 +0200923 Width : Width_Type;
924 Height : Height_Type;
Nico Huberba84df22026-06-23 13:29:29 +0000925 Pos_X, Pos_Y : Position_Type;
Nico Huber4916e342016-11-04 14:37:53 +0100926 begin
927 -- Writes to WIN_SZ arm the PF registers.
928
Nico Huberba84df22026-06-23 13:29:29 +0000929 Scale
Nico Huber4916e342016-11-04 14:37:53 +0100930 (Width => Width,
931 Height => Height,
Nico Huberba84df22026-06-23 13:29:29 +0000932 Scaling => Pipe_Cfg.Scaling,
Nico Huberc5c767a2018-06-03 01:09:04 +0200933 Max_Width => Mode.H_Visible,
934 Max_Height => Mode.V_Visible,
Nico Huber4d592b42026-06-23 12:21:37 +0000935 Framebuffer => Pipe_Cfg.Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100936
Nico Huberfdb0df12018-02-07 14:30:34 +0100937 -- Do not scale to odd width (at least Haswell has trouble with this).
Nico Huberc5c767a2018-06-03 01:09:04 +0200938 if Width < Mode.H_Visible and Width mod 2 = 1 then
Nico Huberfdb0df12018-02-07 14:30:34 +0100939 Width := Width + 1;
940 end if;
Nico Huberb3b9fa32018-06-18 16:16:41 +0200941 -- Do not scale to odd height (at least Sandy Bridge makes trouble).
942 if Height < Mode.V_Visible and Height mod 2 = 1 then
943 Height := Height + 1;
944 end if;
Nico Huberfdb0df12018-02-07 14:30:34 +0100945
Nico Huberba84df22026-06-23 13:29:29 +0000946 Align_Framebuffer
947 (Pos_X => Pos_X,
948 Pos_Y => Pos_Y,
949 Align => Pipe_Cfg.Alignment,
950 Width => Width,
951 Height => Height,
952 Mode => Mode);
Nico Huberfdb0df12018-02-07 14:30:34 +0100953
954 -- Hardware is picky about minimal horizontal gaps.
Nico Huberc5c767a2018-06-03 01:09:04 +0200955 if Mode.H_Visible - Width <= 3 then
956 Width := Mode.H_Visible;
Nico Huberba84df22026-06-23 13:29:29 +0000957 Pos_X := 0;
Nico Huberfdb0df12018-02-07 14:30:34 +0100958 end if;
959
Nico Huber4916e342016-11-04 14:37:53 +0100960 Registers.Write
961 (Register => Controller.PF_CTRL,
962 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_CTRL_FILTER_MED);
963 Registers.Write
964 (Register => Controller.PF_WIN_POS,
Nico Huberba84df22026-06-23 13:29:29 +0000965 Value => Shift_Left (Word32 (Pos_X), 16) or Word32 (Pos_Y));
Nico Huber4916e342016-11-04 14:37:53 +0100966 Registers.Write
967 (Register => Controller.PF_WIN_SZ,
968 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
969 end Setup_Ironlake_Panel_Fitter;
970
Arthur Heymansd5198442018-03-28 17:05:12 +0200971 procedure Setup_Gmch_Panel_Fitter
Nico Huber958c5642018-06-02 16:59:31 +0200972 (Controller : in Controller_Type;
973 Mode : in HW.GFX.Mode_Type;
974 Framebuffer : in HW.GFX.Framebuffer_Type)
Arthur Heymansd5198442018-03-28 17:05:12 +0200975 is
976 PF_Ctrl_Pipe_Sel : constant Word32 :=
977 (case Controller.Pipe is
978 when Primary => GMCH_PFIT_CONTROL_SELECT_PIPE_A,
979 when Secondary => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
980 when others => 0);
Nico Huber958c5642018-06-02 16:59:31 +0200981
Arthur Heymansf70edda2018-08-21 18:37:00 +0200982 -- Work around a quirk:
983 -- In legacy VGA mode Pillarbox fails to display anything so just force
984 -- 'auto' mode on all displays, which will the output stretched to
985 -- fullscreen .
Nico Huber958c5642018-06-02 16:59:31 +0200986 PF_Ctrl_Scaling : constant Word32 :=
Arthur Heymansf70edda2018-08-21 18:37:00 +0200987 (if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
988 GMCH_PFIT_CONTROL_SCALING (Uniform)
989 else
990 GMCH_PFIT_CONTROL_SCALING (Scaling_Type (Framebuffer, Mode)));
Nico Huber958c5642018-06-02 16:59:31 +0200991
Arthur Heymansd5198442018-03-28 17:05:12 +0200992 In_Use : Boolean;
993 begin
994 Registers.Is_Set_Mask
995 (Register => Registers.GMCH_PFIT_CONTROL,
996 Mask => PF_CTRL_ENABLE,
997 Result => In_Use);
998
999 if not In_Use then
1000 Registers.Write
1001 (Register => Registers.GMCH_PFIT_CONTROL,
Nico Huber958c5642018-06-02 16:59:31 +02001002 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_Ctrl_Scaling);
Arthur Heymansd5198442018-03-28 17:05:12 +02001003 else
Nico Huber7ba7bd62018-06-06 12:27:09 +02001004 pragma Debug (Debug.Put_Line
1005 ("GMCH Pannel fitter already in use, skipping..."));
Arthur Heymansd5198442018-03-28 17:05:12 +02001006 end if;
1007 end Setup_Gmch_Panel_Fitter;
1008
Nico Huberf361ec82018-06-02 18:01:45 +02001009 procedure Gmch_Panel_Fitter_Pipe (Pipe : out Pipe_Index)
1010 is
1011 Used_For_Secondary : Boolean;
1012 begin
Arthur Heymans960e2392026-03-03 19:45:24 +01001013 if Config.Gen_I945 then
1014 -- Gen3: panel fitter is hardwired to Pipe B (Secondary).
1015 -- The PFIT_PIPE field (bits 30:29) does not exist on Gen3.
1016 Pipe := Secondary;
1017 else
1018 Registers.Is_Set_Mask
1019 (Register => Registers.GMCH_PFIT_CONTROL,
1020 Mask => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
1021 Result => Used_For_Secondary);
1022 Pipe := (if Used_For_Secondary then Secondary else Primary);
1023 end if;
Nico Huberac2a1412026-07-02 10:41:59 +02001024 end Gmch_Panel_Fitter_Pipe;
Nico Huberf361ec82018-06-02 18:01:45 +02001025
Nico Huberb4b72792018-01-02 13:45:41 +01001026 procedure Panel_Fitter_Off (Controller : Controller_Type)
1027 is
1028 use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
Nico Huberf361ec82018-06-02 18:01:45 +02001029 Pipe_Using_PF : Pipe_Index;
Nico Huberb4b72792018-01-02 13:45:41 +01001030 begin
1031 -- Writes to WIN_SZ arm the PS/PF registers.
1032 if Config.Has_Plane_Control then
1033 Registers.Unset_Mask (Controller.PS_CTRL_1, PS_CTRL_ENABLE_SCALER);
1034 Registers.Write (Controller.PS_WIN_SZ_1, 16#0000_0000#);
1035 if Controller.PS_CTRL_2 /= Registers.Invalid_Register and
1036 Controller.PS_WIN_SZ_2 /= Registers.Invalid_Register
1037 then
1038 Registers.Unset_Mask (Controller.PS_CTRL_2, PS_CTRL_ENABLE_SCALER);
1039 Registers.Write (Controller.PS_WIN_SZ_2, 16#0000_0000#);
1040 end if;
Arthur Heymansd5198442018-03-28 17:05:12 +02001041 elsif Config.Has_GMCH_PFIT_CONTROL then
Nico Huberf361ec82018-06-02 18:01:45 +02001042 Gmch_Panel_Fitter_Pipe (Pipe_Using_PF);
1043 if Pipe_Using_PF = Controller.Pipe then
Arthur Heymans960e2392026-03-03 19:45:24 +01001044 -- Write 0 to clear all bits (enable, scaling mode, auto-scale,
1045 -- interpolation). Just clearing the enable bit can leave stale
1046 -- Gen3 auto-scale bits that confuse the hardware.
1047 Registers.Write (Registers.GMCH_PFIT_CONTROL, 16#0000_0000#);
Arthur Heymansd5198442018-03-28 17:05:12 +02001048 end if;
Nico Huberb4b72792018-01-02 13:45:41 +01001049 else
1050 Registers.Unset_Mask (Controller.PF_CTRL, PF_CTRL_ENABLE);
1051 Registers.Write (Controller.PF_WIN_SZ, 16#0000_0000#);
1052 end if;
1053 end Panel_Fitter_Off;
1054
Nico Huber4916e342016-11-04 14:37:53 +01001055 procedure Setup_Scaling
1056 (Controller : in Controller_Type;
Nico Huber4d592b42026-06-23 12:21:37 +00001057 Pipe_Cfg : in Pipe_Config;
1058 Mode : in HW.GFX.Mode_Type)
Nico Huber4916e342016-11-04 14:37:53 +01001059 with
1060 Pre =>
Nico Huber4d592b42026-06-23 12:21:37 +00001061 Rotated_Width (Pipe_Cfg.Framebuffer) <= Mode.H_Visible and
1062 Rotated_Height (Pipe_Cfg.Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +01001063 is
1064 begin
Nico Huber4d592b42026-06-23 12:21:37 +00001065 if Requires_Scaling (Pipe_Cfg.Framebuffer, Mode) then
Nico Huber4916e342016-11-04 14:37:53 +01001066 if Config.Has_Plane_Control then
Nico Huber4d592b42026-06-23 12:21:37 +00001067 Setup_Skylake_Pipe_Scaler (Controller, Pipe_Cfg, Mode);
Arthur Heymansd5198442018-03-28 17:05:12 +02001068 elsif Config.Has_GMCH_PFIT_CONTROL then
Nico Huber4d592b42026-06-23 12:21:37 +00001069 Setup_Gmch_Panel_Fitter (Controller, Mode, Pipe_Cfg.Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +01001070 else
Nico Huber4d592b42026-06-23 12:21:37 +00001071 Setup_Ironlake_Panel_Fitter (Controller, Pipe_Cfg, Mode);
Nico Huber4916e342016-11-04 14:37:53 +01001072 end if;
Nico Huberb4b72792018-01-02 13:45:41 +01001073 else
1074 Panel_Fitter_Off (Controller);
Nico Huber4916e342016-11-04 14:37:53 +01001075 end if;
1076 end Setup_Scaling;
1077
Nico Huber9a4c4c32019-09-16 22:05:11 +02001078 procedure Reserve_Scaler
1079 (Success : out Boolean;
1080 Reservation : in out Scaler_Reservation;
1081 Pipe : in Pipe_Index)
Nico Huberf361ec82018-06-02 18:01:45 +02001082 is
1083 Pipe_Using_PF : Pipe_Index := Pipe_Index'First;
1084 PF_Enabled : Boolean;
1085 begin
1086 if Config.Has_GMCH_PFIT_CONTROL then
Nico Huber9a4c4c32019-09-16 22:05:11 +02001087 if Reservation.Reserved then
1088 Success := Reservation.Pipe = Pipe;
1089 return;
1090 end if;
1091
Nico Huberf361ec82018-06-02 18:01:45 +02001092 Registers.Is_Set_Mask
1093 (Register => Registers.GMCH_PFIT_CONTROL,
1094 Mask => PF_CTRL_ENABLE,
1095 Result => PF_Enabled);
1096 if PF_Enabled then
1097 Gmch_Panel_Fitter_Pipe (Pipe_Using_PF);
1098 end if;
1099
Nico Huber9a4c4c32019-09-16 22:05:11 +02001100 Success := not PF_Enabled or Pipe_Using_PF = Pipe;
1101 if Success then
1102 Reservation.Reserved := True;
1103 Reservation.Pipe := Pipe;
1104 end if;
Nico Huberf361ec82018-06-02 18:01:45 +02001105 else
Nico Huber9a4c4c32019-09-16 22:05:11 +02001106 Success := True;
Nico Huberf361ec82018-06-02 18:01:45 +02001107 end if;
Nico Huber9a4c4c32019-09-16 22:05:11 +02001108 end Reserve_Scaler;
Nico Huberf361ec82018-06-02 18:01:45 +02001109
Nico Huber4916e342016-11-04 14:37:53 +01001110 ----------------------------------------------------------------------------
1111
Nico Huberf7f537e2018-01-02 14:15:43 +01001112 procedure Setup_FB
1113 (Pipe : Pipe_Index;
Nico Huber4d592b42026-06-23 12:21:37 +00001114 Pipe_Cfg : Pipe_Config;
1115 Mode : Mode_Type)
Nico Huberf7f537e2018-01-02 14:15:43 +01001116 is
1117 -- Enable dithering if framebuffer BPC differs from port BPC,
1118 -- as smooth gradients look really bad without.
Nico Huber4d592b42026-06-23 12:21:37 +00001119 Dither : constant Boolean := Pipe_Cfg.Framebuffer.BPC /= Mode.BPC;
Nico Huberf7f537e2018-01-02 14:15:43 +01001120 begin
1121 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
1122
Nico Huber4dc4c612018-01-10 15:55:09 +01001123 -- Disable the cursor first.
Nico Huber4d592b42026-06-23 12:21:37 +00001124 Update_Cursor (Pipe, Pipe_Cfg.Framebuffer, Default_Cursor);
Nico Huber4dc4c612018-01-10 15:55:09 +01001125
Nico Huber4d592b42026-06-23 12:21:37 +00001126 Setup_Display (Controllers (Pipe), Pipe_Cfg.Framebuffer, Mode.BPC, Dither);
1127 Setup_Scaling (Controllers (Pipe), Pipe_Cfg, Mode);
Nico Huberf7f537e2018-01-02 14:15:43 +01001128 end Setup_FB;
1129
Nico Huber83693c82016-10-08 22:17:55 +02001130 procedure On
Nico Huberf3e23662016-12-05 21:33:03 +01001131 (Pipe : Pipe_Index;
Nico Huber4d592b42026-06-23 12:21:37 +00001132 Pipe_Cfg : Pipe_Config;
1133 Port_Cfg : Port_Config)
Nico Huber83693c82016-10-08 22:17:55 +02001134 is
1135 begin
1136 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
1137
Nico Huber7ad2d652016-12-07 15:19:32 +01001138 Transcoder.Setup (Pipe, Port_Cfg);
Nico Huber83693c82016-10-08 22:17:55 +02001139
Nico Huber4d592b42026-06-23 12:21:37 +00001140 Setup_FB (Pipe, Pipe_Cfg, Port_Cfg.Mode);
1141 Update_Cursor (Pipe, Pipe_Cfg.Framebuffer, Pipe_Cfg.Cursor);
Nico Huber83693c82016-10-08 22:17:55 +02001142
Nico Huberabb16d92018-05-29 01:44:26 +02001143 Transcoder.On
1144 (Pipe => Pipe,
1145 Port_Cfg => Port_Cfg,
Nico Huber4d592b42026-06-23 12:21:37 +00001146 Dither => Pipe_Cfg.Framebuffer.BPC /= Port_Cfg.Mode.BPC,
1147 Scale => Requires_Scaling (Pipe_Cfg.Framebuffer, Port_Cfg.Mode));
Nico Huber83693c82016-10-08 22:17:55 +02001148 end On;
1149
1150 ----------------------------------------------------------------------------
1151
Nico Huber75a707f2018-06-18 16:28:33 +02001152 procedure Planes_Off (Controller : Controller_Type; CUR : Cursor_Regs)
1153 is
1154 use type Registers.Registers_Invalid_Index;
Nico Huber83693c82016-10-08 22:17:55 +02001155 begin
Nico Huber75a707f2018-06-18 16:28:33 +02001156 Registers.Write (CUR.CTL, 16#0000_0000#);
1157 if CUR.FBC_CTL /= Registers.Invalid_Register then
1158 Registers.Write (CUR.FBC_CTL, 16#0000_0000#);
Nico Huber4dc4c612018-01-10 15:55:09 +01001159 end if;
Nico Huber07aab5a2020-10-01 15:06:53 +02001160 Registers.Unset_Mask (Controller.PLANE_2_CTL, DSPCNTR_ENABLE);
Nico Huber83693c82016-10-08 22:17:55 +02001161 if Config.Has_Plane_Control then
1162 Clear_Watermarks (Controller);
1163 Registers.Unset_Mask (Controller.PLANE_CTL, PLANE_CTL_PLANE_ENABLE);
1164 Registers.Write (Controller.PLANE_SURF, 16#0000_0000#);
1165 else
1166 Registers.Unset_Mask (Controller.DSPCNTR, DSPCNTR_ENABLE);
1167 end if;
1168 end Planes_Off;
1169
Nico Huber7ad2d652016-12-07 15:19:32 +01001170 procedure Off (Pipe : Pipe_Index)
Nico Huberf3e23662016-12-05 21:33:03 +01001171 is
Nico Huber83693c82016-10-08 22:17:55 +02001172 begin
1173 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
1174
Nico Huber75a707f2018-06-18 16:28:33 +02001175 Planes_Off (Controllers (Pipe), Cursors (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +01001176 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +01001177 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +01001178 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +02001179 end Off;
1180
Nico Huber33912aa2016-12-06 20:36:23 +01001181 procedure Legacy_VGA_Off
1182 is
1183 use type HW.Word8;
1184 Reg8 : Word8;
1185 begin
1186 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
1187 Port_IO.InB (Reg8, VGA_SR_DATA);
1188 Port_IO.OutB (VGA_SR_DATA, Reg8 or VGA_SR01_SCREEN_OFF);
1189 Time.U_Delay (100); -- PRM says 100us, Linux does 300
Arthur Heymansdfcdd772018-03-28 16:42:50 +02001190 Registers.Set_Mask (VGACNTRL_REG, VGA_CONTROL_VGA_DISPLAY_DISABLE);
Nico Huber33912aa2016-12-06 20:36:23 +01001191 end Legacy_VGA_Off;
1192
Nico Huber83693c82016-10-08 22:17:55 +02001193 procedure All_Off
1194 is
Nico Huber83693c82016-10-08 22:17:55 +02001195 begin
1196 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
1197
Nico Huber33912aa2016-12-06 20:36:23 +01001198 Legacy_VGA_Off;
1199
Arthur Heymans960e2392026-03-03 19:45:24 +01001200 for Pipe in Pipe_Index range Pipe_Index'First .. Config.Max_Pipe loop
Nico Huber75a707f2018-06-18 16:28:33 +02001201 Planes_Off (Controllers (Pipe), Cursors (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +01001202 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +01001203 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +01001204 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +02001205 end loop;
Nico Huber83693c82016-10-08 22:17:55 +02001206 end All_Off;
1207
Nico Huber83693c82016-10-08 22:17:55 +02001208end HW.GFX.GMA.Pipe_Setup;