blob: d0fc75017092d55879d9bb6a3143b751c25744b4 [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
18with HW.GFX.GMA.Config;
Nico Huber7ad2d652016-12-07 15:19:32 +010019with HW.GFX.GMA.Transcoder;
Nico Huber83693c82016-10-08 22:17:55 +020020
21package body HW.GFX.GMA.Pipe_Setup is
22
Nico Huberfbb42202016-11-07 15:08:26 +010023 ILK_DISPLAY_CHICKEN1_VGA_MASK : constant := 7 * 2 ** 29;
24 ILK_DISPLAY_CHICKEN1_VGA_ENABLE : constant := 5 * 2 ** 29;
25 ILK_DISPLAY_CHICKEN2_VGA_MASK : constant := 1 * 2 ** 25;
26 ILK_DISPLAY_CHICKEN2_VGA_ENABLE : constant := 0 * 2 ** 25;
27
Nico Huber7ad2d652016-12-07 15:19:32 +010028 DSPCNTR_ENABLE : constant := 1 * 2 ** 31;
29 DSPCNTR_GAMMA_CORRECTION : constant := 1 * 2 ** 30;
30 DSPCNTR_DISABLE_TRICKLE_FEED : constant := 1 * 2 ** 14;
31 DSPCNTR_FORMAT_MASK : constant := 15 * 2 ** 26;
Nico Huber83693c82016-10-08 22:17:55 +020032
33 DSPCNTR_MASK : constant Word32 :=
34 DSPCNTR_ENABLE or
35 DSPCNTR_GAMMA_CORRECTION or
36 DSPCNTR_FORMAT_MASK or
37 DSPCNTR_DISABLE_TRICKLE_FEED;
38
39 PLANE_CTL_PLANE_ENABLE : constant := 1 * 2 ** 31;
40 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 : constant := 4 * 2 ** 24;
41 PLANE_CTL_PLANE_GAMMA_DISABLE : constant := 1 * 2 ** 13;
Nico Huber0164b022017-08-24 15:12:51 +020042 PLANE_CTL_TILED_SURFACE_MASK : constant := 7 * 2 ** 10;
43 PLANE_CTL_TILED_SURFACE_LINEAR : constant := 0 * 2 ** 10;
44 PLANE_CTL_TILED_SURFACE_X_TILED : constant := 1 * 2 ** 10;
45 PLANE_CTL_TILED_SURFACE_Y_TILED : constant := 4 * 2 ** 10;
46 PLANE_CTL_TILED_SURFACE_YF_TILED : constant := 5 * 2 ** 10;
47
48 PLANE_CTL_TILED_SURFACE : constant array (Tiling_Type) of Word32 :=
49 (Linear => PLANE_CTL_TILED_SURFACE_LINEAR,
50 X_Tiled => PLANE_CTL_TILED_SURFACE_X_TILED,
51 Y_Tiled => PLANE_CTL_TILED_SURFACE_Y_TILED);
Nico Huber83693c82016-10-08 22:17:55 +020052
Nico Huber9b479412017-08-27 11:55:56 +020053 PLANE_CTL_PLANE_ROTATION_MASK : constant := 3 * 2 ** 0;
54 PLANE_CTL_PLANE_ROTATION : constant array (Rotation_Type) of Word32 :=
55 (No_Rotation => 0 * 2 ** 0,
56 Rotated_90 => 1 * 2 ** 0,
57 Rotated_180 => 2 * 2 ** 0,
58 Rotated_270 => 3 * 2 ** 0);
59
Nico Huber83693c82016-10-08 22:17:55 +020060 PLANE_WM_ENABLE : constant := 1 * 2 ** 31;
61 PLANE_WM_LINES_SHIFT : constant := 14;
62 PLANE_WM_LINES_MASK : constant := 16#001f# * 2 ** 14;
63 PLANE_WM_BLOCKS_MASK : constant := 16#03ff# * 2 ** 0;
64
Nico Huber33912aa2016-12-06 20:36:23 +010065 VGA_SR_INDEX : constant := 16#03c4#;
66 VGA_SR_DATA : constant := 16#03c5#;
67 VGA_SR01 : constant := 16#01#;
68 VGA_SR01_SCREEN_OFF : constant := 1 * 2 ** 5;
Nico Huber3675db52016-11-04 16:27:29 +010069
70 VGA_CONTROL_VGA_DISPLAY_DISABLE : constant := 1 * 2 ** 31;
71 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK : constant := 16#0003# * 2 ** 6;
72 VGA_CONTROL_BLINK_DUTY_CYCLE_50 : constant := 2 * 2 ** 6;
73 VGA_CONTROL_VSYNC_BLINK_RATE_MASK : constant := 16#003f# * 2 ** 0;
74
Nico Huber4dc4c612018-01-10 15:55:09 +010075 CUR_CTL_PIPE_SELECT : constant array (Pipe_Index) of Word32 :=
76 (Primary => 0 * 2 ** 28,
77 Secondary => 1 * 2 ** 28,
78 Tertiary => 2 * 2 ** 28);
79 CUR_CTL_MODE : constant array (Cursor_Mode, Cursor_Size) of Word32 :=
80 (No_Cursor => (others => 16#00#),
81 ARGB_Cursor =>
82 (Cursor_64x64 => 16#27#,
83 Cursor_128x128 => 16#22#,
84 Cursor_256x256 => 16#23#));
85
86 function CUR_POS_Y (Y : Int32) return Word32 is
87 ((if Y >= 0 then 0 else 1 * 2 ** 31) or Shift_Left (Word32 (abs Y), 16))
88 with
89 Pre => Y > Int32'First;
90 function CUR_POS_X (X : Int32) return Word32 is
91 ((if X >= 0 then 0 else 1 * 2 ** 15) or Word32 (abs X))
92 with
93 Pre => X > Int32'First;
94
Nico Huber3675db52016-11-04 16:27:29 +010095 subtype VGA_Cycle_Count is Pos32 range 2 .. 128;
96 function VGA_CONTROL_VSYNC_BLINK_RATE
97 (Cycles : VGA_Cycle_Count)
98 return Word32
99 is
100 begin
101 return Word32 (Cycles) / 2 - 1;
102 end VGA_CONTROL_VSYNC_BLINK_RATE;
103
Nico Huber7ad2d652016-12-07 15:19:32 +0100104 PF_CTRL_ENABLE : constant := 1 * 2 ** 31;
105 PF_CTRL_PIPE_SELECT_MASK : constant := 3 * 2 ** 29;
106 PF_CTRL_FILTER_MED : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200107
Nico Huber7ad2d652016-12-07 15:19:32 +0100108 PS_CTRL_ENABLE_SCALER : constant := 1 * 2 ** 31;
109 PS_CTRL_SCALER_MODE_7X5_EXTENDED : constant := 1 * 2 ** 28;
110 PS_CTRL_FILTER_SELECT_MEDIUM_2 : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200111
Arthur Heymansd5198442018-03-28 17:05:12 +0200112 GMCH_PFIT_CONTROL_SELECT_MASK : constant := 3 * 2 ** 29;
113 GMCH_PFIT_CONTROL_SELECT_PIPE_A : constant := 0 * 2 ** 29;
114 GMCH_PFIT_CONTROL_SELECT_PIPE_B : constant := 1 * 2 ** 29;
115
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200116 VGACNTRL_REG : constant Registers.Registers_Index :=
117 (if Config.Has_GMCH_VGACNTRL then
118 Registers.GMCH_VGACNTRL
119 else Registers.CPU_VGACNTRL);
120
Nico Huber83693c82016-10-08 22:17:55 +0200121 ---------------------------------------------------------------------------
122
Nico Huber83693c82016-10-08 22:17:55 +0200123 function PLANE_WM_LINES (Lines : Natural) return Word32 is
124 begin
125 return Shift_Left (Word32 (Lines), PLANE_WM_LINES_SHIFT)
126 and PLANE_WM_LINES_MASK;
127 end PLANE_WM_LINES;
128
129 function PLANE_WM_BLOCKS (Blocks : Natural) return Word32 is
130 begin
131 return Word32 (Blocks) and PLANE_WM_BLOCKS_MASK;
132 end PLANE_WM_BLOCKS;
133
134 ---------------------------------------------------------------------------
135
136 function Encode (LSW, MSW : Pos16) return Word32 is
137 begin
Nico Huber7ad2d652016-12-07 15:19:32 +0100138 return Shift_Left (Word32 (MSW) - 1, 16) or (Word32 (LSW) - 1);
Nico Huber83693c82016-10-08 22:17:55 +0200139 end Encode;
140
141 ----------------------------------------------------------------------------
142
Nico Huber83693c82016-10-08 22:17:55 +0200143 procedure Clear_Watermarks (Controller : Controller_Type) is
144 begin
Nico Huber4dc4c612018-01-10 15:55:09 +0100145 Registers.Write (Controller.CUR_BUF_CFG, 16#0000_0000#);
146 for Level in WM_Levels loop
147 Registers.Write (Controller.CUR_WM (Level), 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200148 end loop;
Nico Huber4dc4c612018-01-10 15:55:09 +0100149 Registers.Write (Controller.PLANE_BUF_CFG, 16#0000_0000#);
150 for Level in WM_Levels loop
151 Registers.Write (Controller.PLANE_WM (Level), 16#0000_0000#);
152 end loop;
153 Registers.Write (Controller.WM_LINETIME, 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200154 end Clear_Watermarks;
155
156 procedure Setup_Watermarks (Controller : Controller_Type)
157 is
Nico Huberf3e23662016-12-05 21:33:03 +0100158 type Per_Plane_Buffer_Range is array (Pipe_Index) of Word32;
Nico Huber4dc4c612018-01-10 15:55:09 +0100159 Cur_Buffer_Range : constant Per_Plane_Buffer_Range :=
160 (Primary => Shift_Left ( 7, 16) or 0,
161 Secondary => Shift_Left (167, 16) or 160,
162 Tertiary => Shift_Left (327, 16) or 320);
163 Plane_Buffer_Range : constant Per_Plane_Buffer_Range :=
164 (Primary => Shift_Left (159, 16) or 8,
165 Secondary => Shift_Left (319, 16) or 168,
166 Tertiary => Shift_Left (479, 16) or 328);
Nico Huber83693c82016-10-08 22:17:55 +0200167 begin
168 Registers.Write
169 (Register => Controller.PLANE_BUF_CFG,
Nico Huber4dc4c612018-01-10 15:55:09 +0100170 Value => Plane_Buffer_Range (Controller.Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200171 Registers.Write
172 (Register => Controller.PLANE_WM (0),
173 Value => PLANE_WM_ENABLE or
174 PLANE_WM_LINES (2) or
Nico Huber4dc4c612018-01-10 15:55:09 +0100175 PLANE_WM_BLOCKS (152));
176 Registers.Write
177 (Register => Controller.CUR_BUF_CFG,
178 Value => Cur_Buffer_Range (Controller.Pipe));
179 Registers.Write
180 (Register => Controller.CUR_WM (0),
181 Value => PLANE_WM_ENABLE or
182 PLANE_WM_LINES (2) or
183 PLANE_WM_BLOCKS (8));
Nico Huber83693c82016-10-08 22:17:55 +0200184 end Setup_Watermarks;
185
186 ----------------------------------------------------------------------------
187
Nico Huber3675db52016-11-04 16:27:29 +0100188 procedure Setup_Hires_Plane
Nico Huber6a4dfc82016-11-04 15:50:58 +0100189 (Controller : Controller_Type;
Nico Huber0164b022017-08-24 15:12:51 +0200190 FB : HW.GFX.Framebuffer_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200191 with
192 Global => (In_Out => Registers.Register_State),
193 Depends =>
194 (Registers.Register_State
195 =>+
196 (Registers.Register_State,
197 Controller,
Nico Huber9b479412017-08-27 11:55:56 +0200198 FB)),
Nico Huber5ef4d602017-12-13 13:56:47 +0100199 Pre => FB.Height + FB.Start_Y <= FB.V_Stride
Nico Huber83693c82016-10-08 22:17:55 +0200200 is
201 -- FIXME: setup correct format, based on framebuffer RGB format
202 Format : constant Word32 := 6 * 2 ** 26;
203 PRI : Word32 := DSPCNTR_ENABLE or Format;
Nico Huber83693c82016-10-08 22:17:55 +0200204 begin
205 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
206
Nico Huber83693c82016-10-08 22:17:55 +0200207 if Config.Has_Plane_Control then
Nico Huber9b479412017-08-27 11:55:56 +0200208 declare
Nico Huber34be6542017-12-13 09:26:24 +0100209 Stride, Offset : Word32;
Nico Huber9b479412017-08-27 11:55:56 +0200210 Width : constant Pos16 := Rotated_Width (FB);
211 Height : constant Pos16 := Rotated_Height (FB);
212 begin
213 if Rotation_90 (FB) then
Nico Huber5ef4d602017-12-13 13:56:47 +0100214 Stride := Word32 (FB_Pitch (FB.V_Stride, FB));
215 Offset := Shift_Left (Word32 (FB.Start_X), 16) or
216 Word32 (FB.V_Stride - FB.Height - FB.Start_Y);
Nico Huber9b479412017-08-27 11:55:56 +0200217 else
Nico Huber5ef4d602017-12-13 13:56:47 +0100218 Stride := Word32 (FB_Pitch (FB.Stride, FB));
219 Offset := Shift_Left (Word32 (FB.Start_Y), 16) or
220 Word32 (FB.Start_X);
Nico Huber9b479412017-08-27 11:55:56 +0200221 end if;
222 Registers.Write
223 (Register => Controller.PLANE_CTL,
224 Value => PLANE_CTL_PLANE_ENABLE or
225 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
226 PLANE_CTL_PLANE_GAMMA_DISABLE or
227 PLANE_CTL_TILED_SURFACE (FB.Tiling) or
228 PLANE_CTL_PLANE_ROTATION (FB.Rotation));
229 Registers.Write (Controller.PLANE_OFFSET, Offset);
230 Registers.Write (Controller.PLANE_SIZE, Encode (Width, Height));
231 Registers.Write (Controller.PLANE_STRIDE, Stride);
232 Registers.Write (Controller.PLANE_POS, 16#0000_0000#);
Nico Huber34be6542017-12-13 09:26:24 +0100233 Registers.Write (Controller.PLANE_SURF, FB.Offset and 16#ffff_f000#);
Nico Huber9b479412017-08-27 11:55:56 +0200234 end;
Nico Huber83693c82016-10-08 22:17:55 +0200235 else
236 if Config.Disable_Trickle_Feed then
237 PRI := PRI or DSPCNTR_DISABLE_TRICKLE_FEED;
238 end if;
239 -- for now, just disable gamma LUT (can't do anything
240 -- useful without colorimetry information from display)
241 Registers.Unset_And_Set_Mask
242 (Register => Controller.DSPCNTR,
243 Mask_Unset => DSPCNTR_MASK,
244 Mask_Set => PRI);
245
Nico Huber0164b022017-08-24 15:12:51 +0200246 Registers.Write
247 (Controller.DSPSTRIDE, Word32 (Pixel_To_Bytes (FB.Stride, FB)));
Nico Huber83693c82016-10-08 22:17:55 +0200248 if Config.Has_DSP_Linoff then
Nico Huber5ef4d602017-12-13 13:56:47 +0100249 Registers.Write
250 (Register => Controller.DSPLINOFF,
251 Value => Word32 (Pixel_To_Bytes
252 (FB.Start_Y * FB.Stride + FB.Start_X, FB)));
253 Registers.Write (Controller.DSPTILEOFF, 0);
254 else
255 Registers.Write
256 (Register => Controller.DSPTILEOFF,
257 Value => Shift_Left (Word32 (FB.Start_Y), 16) or
258 Word32 (FB.Start_X));
Nico Huber83693c82016-10-08 22:17:55 +0200259 end if;
Nico Huber8fd92a12018-01-02 14:02:59 +0100260 Registers.Write (Controller.DSPSURF, FB.Offset and 16#ffff_f000#);
Nico Huber83693c82016-10-08 22:17:55 +0200261 end if;
Nico Huber3675db52016-11-04 16:27:29 +0100262 end Setup_Hires_Plane;
263
264 procedure Setup_Display
Nico Huber113a14b2016-12-06 21:59:15 +0100265 (Controller : Controller_Type;
266 Framebuffer : Framebuffer_Type;
267 Dither_BPC : BPC_Type;
268 Dither : Boolean)
Nico Huber3675db52016-11-04 16:27:29 +0100269 with
270 Global => (In_Out => (Registers.Register_State, Port_IO.State)),
271 Depends =>
272 (Registers.Register_State
273 =>+
274 (Registers.Register_State,
275 Controller,
Nico Huber113a14b2016-12-06 21:59:15 +0100276 Framebuffer,
277 Dither_BPC,
278 Dither),
Nico Huber3675db52016-11-04 16:27:29 +0100279 Port_IO.State
280 =>+
Nico Huber9b479412017-08-27 11:55:56 +0200281 (Framebuffer)),
282 Pre =>
283 Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
Nico Huber5ef4d602017-12-13 13:56:47 +0100284 Framebuffer.Height + Framebuffer.Start_Y <= Framebuffer.V_Stride
Nico Huber3675db52016-11-04 16:27:29 +0100285 is
286 use type Word8;
287
288 Reg8 : Word8;
289 begin
290 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
291
292 if Config.Has_Plane_Control then
293 Setup_Watermarks (Controller);
294 end if;
295
296 if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
Nico Huberfbb42202016-11-07 15:08:26 +0100297 if Config.VGA_Plane_Workaround then
298 Registers.Unset_And_Set_Mask
299 (Register => Registers.ILK_DISPLAY_CHICKEN1,
300 Mask_Unset => ILK_DISPLAY_CHICKEN1_VGA_MASK,
301 Mask_Set => ILK_DISPLAY_CHICKEN1_VGA_ENABLE);
302 Registers.Unset_And_Set_Mask
303 (Register => Registers.ILK_DISPLAY_CHICKEN2,
304 Mask_Unset => ILK_DISPLAY_CHICKEN2_VGA_MASK,
305 Mask_Set => ILK_DISPLAY_CHICKEN2_VGA_ENABLE);
306 end if;
307
Nico Huber3675db52016-11-04 16:27:29 +0100308 Registers.Unset_And_Set_Mask
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200309 (Register => VGACNTRL_REG,
Nico Huber3675db52016-11-04 16:27:29 +0100310 Mask_Unset => VGA_CONTROL_VGA_DISPLAY_DISABLE or
311 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK or
312 VGA_CONTROL_VSYNC_BLINK_RATE_MASK,
313 Mask_Set => VGA_CONTROL_BLINK_DUTY_CYCLE_50 or
314 VGA_CONTROL_VSYNC_BLINK_RATE (30));
315
316 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
317 Port_IO.InB (Reg8, VGA_SR_DATA);
318 Port_IO.OutB (VGA_SR_DATA, Reg8 and not (VGA_SR01_SCREEN_OFF));
319 else
Nico Huber6a4dfc82016-11-04 15:50:58 +0100320 Setup_Hires_Plane (Controller, Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100321 end if;
322
323 Registers.Write
324 (Register => Controller.PIPESRC,
325 Value => Encode
Nico Huber9b479412017-08-27 11:55:56 +0200326 (Rotated_Height (Framebuffer), Rotated_Width (Framebuffer)));
Nico Huber83693c82016-10-08 22:17:55 +0200327
Nico Huber113a14b2016-12-06 21:59:15 +0100328 if Config.Has_Pipeconf_Misc then
329 Registers.Write
330 (Register => Controller.PIPEMISC,
Nico Huber7ad2d652016-12-07 15:19:32 +0100331 Value => Transcoder.BPC_Conf (Dither_BPC, Dither));
Nico Huber113a14b2016-12-06 21:59:15 +0100332 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200333 end Setup_Display;
334
335 ----------------------------------------------------------------------------
336
Nico Huber4dc4c612018-01-10 15:55:09 +0100337 procedure Update_Cursor
338 (Pipe : Pipe_Index;
339 FB : Framebuffer_Type;
340 Cursor : Cursor_Type)
341 is
342 begin
343 -- on some platforms writing CUR_CTL disables self-arming of CUR_POS
344 -- so keep it first
345 Registers.Write
346 (Register => Controllers (Pipe).CUR_CTL,
347 Value => CUR_CTL_PIPE_SELECT (Pipe) or
348 CUR_CTL_MODE (Cursor.Mode, Cursor.Size));
349 Place_Cursor (Pipe, FB, Cursor);
350 end Update_Cursor;
351
352 procedure Place_Cursor
353 (Pipe : Pipe_Index;
354 FB : Framebuffer_Type;
355 Cursor : Cursor_Type)
356 is
357 Width : constant Width_Type := Cursor_Width (Cursor.Size);
358 X : Int32 := Cursor.Center_X - Width / 2;
359 Y : Int32 := Cursor.Center_Y - Width / 2;
360 begin
361 -- off-screen cursor needs special care
362 if X <= -Width or Y <= -Width or
363 X >= Int32 (Rotated_Width (FB)) or Y >= Int32 (Rotated_Height (FB)) or
364 X > Config.Maximum_Cursor_X or Y > Config.Maximum_Cursor_Y
365 then
366 X := -Width;
367 Y := -Width;
368 end if;
369 Registers.Write
370 (Register => Controllers (Pipe).CUR_POS,
371 Value => CUR_POS_Y (Y) or CUR_POS_X (X));
372 -- write to CUR_BASE always arms other CUR_* registers
373 Registers.Write
374 (Register => Controllers (Pipe).CUR_BASE,
375 Value => Shift_Left (Word32 (Cursor.GTT_Offset), 12));
376 end Place_Cursor;
377
378 ----------------------------------------------------------------------------
379
Nico Huber4916e342016-11-04 14:37:53 +0100380 procedure Scale_Keep_Aspect
381 (Width : out Pos32;
382 Height : out Pos32;
383 Max_Width : in Pos32;
384 Max_Height : in Pos32;
385 Framebuffer : in Framebuffer_Type)
386 with
387 Pre =>
388 Max_Width <= Pos32 (Pos16'Last) and
389 Max_Height <= Pos32 (Pos16'Last) and
Nico Huber9b479412017-08-27 11:55:56 +0200390 Pos32 (Rotated_Width (Framebuffer)) <= Max_Width and
391 Pos32 (Rotated_Height (Framebuffer)) <= Max_Height,
Nico Huber4916e342016-11-04 14:37:53 +0100392 Post =>
393 Width <= Max_Width and Height <= Max_Height
394 is
Nico Huber9b479412017-08-27 11:55:56 +0200395 Src_Width : constant Pos32 := Pos32 (Rotated_Width (Framebuffer));
396 Src_Height : constant Pos32 := Pos32 (Rotated_Height (Framebuffer));
Nico Huber4916e342016-11-04 14:37:53 +0100397 begin
Nico Huber9b479412017-08-27 11:55:56 +0200398 if (Max_Width * Src_Height) / Src_Width <= Max_Height then
Nico Huber4916e342016-11-04 14:37:53 +0100399 Width := Max_Width;
Nico Huber9b479412017-08-27 11:55:56 +0200400 Height := (Max_Width * Src_Height) / Src_Width;
Nico Huber4916e342016-11-04 14:37:53 +0100401 else
402 Height := Max_Height;
403 Width := Pos32'Min (Max_Width, -- could prove, it's <= Max_Width
Nico Huber9b479412017-08-27 11:55:56 +0200404 (Max_Height * Src_Width) / Src_Height);
Nico Huber4916e342016-11-04 14:37:53 +0100405 end if;
406 end Scale_Keep_Aspect;
407
408 procedure Setup_Skylake_Pipe_Scaler
409 (Controller : in Controller_Type;
410 Mode : in HW.GFX.Mode_Type;
411 Framebuffer : in HW.GFX.Framebuffer_Type)
412 with
413 Pre =>
Nico Huber9b479412017-08-27 11:55:56 +0200414 Rotated_Width (Framebuffer) <= Mode.H_Visible and
415 Rotated_Height (Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100416 is
Nico Huber7ad2d652016-12-07 15:19:32 +0100417 use type Registers.Registers_Invalid_Index;
418
Nico Huber4916e342016-11-04 14:37:53 +0100419 -- Enable 7x5 extended mode where possible:
420 Scaler_Mode : constant Word32 :=
421 (if Controller.PS_CTRL_2 /= Registers.Invalid_Register then
422 PS_CTRL_SCALER_MODE_7X5_EXTENDED else 0);
423
Nico Huber9b479412017-08-27 11:55:56 +0200424 Width_In : constant Pos32 := Pos32 (Rotated_Width (Framebuffer));
425 Height_In : constant Pos32 := Pos32 (Rotated_Height (Framebuffer));
426
Nico Huber4916e342016-11-04 14:37:53 +0100427 -- We can scale up to 2.99x horizontally:
Nico Huber9b479412017-08-27 11:55:56 +0200428 Horizontal_Limit : constant Pos32 := (Width_In * 299) / 100;
Nico Huber4916e342016-11-04 14:37:53 +0100429 -- The third scaler is limited to 1.99x
430 -- vertical scaling for source widths > 2048:
431 Vertical_Limit : constant Pos32 :=
Nico Huber9b479412017-08-27 11:55:56 +0200432 (Height_In *
Nico Huber4916e342016-11-04 14:37:53 +0100433 (if Controller.PS_CTRL_2 = Registers.Invalid_Register and
Nico Huber9b479412017-08-27 11:55:56 +0200434 Width_In > 2048
Nico Huber4916e342016-11-04 14:37:53 +0100435 then
436 199
437 else
438 299)) / 100;
439
440 Width, Height : Pos32;
441 begin
442 -- Writes to WIN_SZ arm the PS registers.
443
444 Scale_Keep_Aspect
445 (Width => Width,
446 Height => Height,
447 Max_Width => Pos32'Min (Horizontal_Limit, Pos32 (Mode.H_Visible)),
448 Max_Height => Pos32'Min (Vertical_Limit, Pos32 (Mode.V_Visible)),
449 Framebuffer => Framebuffer);
450
451 Registers.Write
452 (Register => Controller.PS_CTRL_1,
453 Value => PS_CTRL_ENABLE_SCALER or Scaler_Mode);
454 Registers.Write
455 (Register => Controller.PS_WIN_POS_1,
456 Value =>
457 Shift_Left (Word32 (Pos32 (Mode.H_Visible) - Width) / 2, 16) or
458 Word32 (Pos32 (Mode.V_Visible) - Height) / 2);
459 Registers.Write
460 (Register => Controller.PS_WIN_SZ_1,
461 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
462 end Setup_Skylake_Pipe_Scaler;
463
464 procedure Setup_Ironlake_Panel_Fitter
465 (Controller : in Controller_Type;
466 Mode : in HW.GFX.Mode_Type;
467 Framebuffer : in HW.GFX.Framebuffer_Type)
468 with
469 Pre =>
Nico Huber9b479412017-08-27 11:55:56 +0200470 Rotated_Width (Framebuffer) <= Mode.H_Visible and
471 Rotated_Height (Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100472 is
473 -- Force 1:1 mapping of panel fitter:pipe
474 PF_Ctrl_Pipe_Sel : constant Word32 :=
475 (if Config.Has_PF_Pipe_Select then
476 (case Controller.PF_CTRL is
477 when Registers.PFA_CTL_1 => 0 * 2 ** 29,
478 when Registers.PFB_CTL_1 => 1 * 2 ** 29,
479 when Registers.PFC_CTL_1 => 2 * 2 ** 29,
480 when others => 0) else 0);
481
482 Width, Height : Pos32;
Nico Huberfdb0df12018-02-07 14:30:34 +0100483 X, Y : Int32;
Nico Huber4916e342016-11-04 14:37:53 +0100484 begin
485 -- Writes to WIN_SZ arm the PF registers.
486
487 Scale_Keep_Aspect
488 (Width => Width,
489 Height => Height,
490 Max_Width => Pos32 (Mode.H_Visible),
491 Max_Height => Pos32 (Mode.V_Visible),
492 Framebuffer => Framebuffer);
493
Nico Huberfdb0df12018-02-07 14:30:34 +0100494 -- Do not scale to odd width (at least Haswell has trouble with this).
495 if Width < Pos32 (Mode.H_Visible) and Width mod 2 = 1 then
496 Width := Width + 1;
497 end if;
498
499 X := (Int32 (Mode.H_Visible) - Width) / 2;
500 Y := (Int32 (Mode.V_Visible) - Height) / 2;
501
502 -- Hardware is picky about minimal horizontal gaps.
503 if Pos32 (Mode.H_Visible) - Width <= 3 then
504 Width := Pos32(Mode.H_Visible);
505 X := 0;
506 end if;
507
Nico Huber4916e342016-11-04 14:37:53 +0100508 Registers.Write
509 (Register => Controller.PF_CTRL,
510 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_CTRL_FILTER_MED);
511 Registers.Write
512 (Register => Controller.PF_WIN_POS,
Nico Huberfdb0df12018-02-07 14:30:34 +0100513 Value => Shift_Left (Word32 (X), 16) or Word32 (Y));
Nico Huber4916e342016-11-04 14:37:53 +0100514 Registers.Write
515 (Register => Controller.PF_WIN_SZ,
516 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
517 end Setup_Ironlake_Panel_Fitter;
518
Arthur Heymansd5198442018-03-28 17:05:12 +0200519 -- TODO the panel fitter can only be set for one pipe
520 -- If this causes problems:
521 -- Check in Enable_Output if panel fitter has already been enabled
522 -- Pass this information to Validate_Config
523 procedure Setup_Gmch_Panel_Fitter
524 (Controller : in Controller_Type)
525 is
526 PF_Ctrl_Pipe_Sel : constant Word32 :=
527 (case Controller.Pipe is
528 when Primary => GMCH_PFIT_CONTROL_SELECT_PIPE_A,
529 when Secondary => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
530 when others => 0);
531 In_Use : Boolean;
532 begin
533 Registers.Is_Set_Mask
534 (Register => Registers.GMCH_PFIT_CONTROL,
535 Mask => PF_CTRL_ENABLE,
536 Result => In_Use);
537
538 if not In_Use then
539 Registers.Write
540 (Register => Registers.GMCH_PFIT_CONTROL,
541 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel);
542 else
543 Debug.Put_Line ("GMCH Pannel fitter already in use, skipping...");
544 end if;
545 end Setup_Gmch_Panel_Fitter;
546
Nico Huberb4b72792018-01-02 13:45:41 +0100547 procedure Panel_Fitter_Off (Controller : Controller_Type)
548 is
549 use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
Arthur Heymansd5198442018-03-28 17:05:12 +0200550 Used_For_Secondary : Boolean;
Nico Huberb4b72792018-01-02 13:45:41 +0100551 begin
552 -- Writes to WIN_SZ arm the PS/PF registers.
553 if Config.Has_Plane_Control then
554 Registers.Unset_Mask (Controller.PS_CTRL_1, PS_CTRL_ENABLE_SCALER);
555 Registers.Write (Controller.PS_WIN_SZ_1, 16#0000_0000#);
556 if Controller.PS_CTRL_2 /= Registers.Invalid_Register and
557 Controller.PS_WIN_SZ_2 /= Registers.Invalid_Register
558 then
559 Registers.Unset_Mask (Controller.PS_CTRL_2, PS_CTRL_ENABLE_SCALER);
560 Registers.Write (Controller.PS_WIN_SZ_2, 16#0000_0000#);
561 end if;
Arthur Heymansd5198442018-03-28 17:05:12 +0200562 elsif Config.Has_GMCH_PFIT_CONTROL then
563 Registers.Is_Set_Mask
564 (Register => Registers.GMCH_PFIT_CONTROL,
565 Mask => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
566 Result => Used_For_Secondary);
567 if (Controller.Pipe = Primary and not Used_For_Secondary) or
568 (Controller.Pipe = Secondary and Used_For_Secondary)
569 then
570 Registers.Unset_Mask
571 (Register => Registers.GMCH_PFIT_CONTROL,
572 Mask => PF_CTRL_ENABLE);
573 end if;
Nico Huberb4b72792018-01-02 13:45:41 +0100574 else
575 Registers.Unset_Mask (Controller.PF_CTRL, PF_CTRL_ENABLE);
576 Registers.Write (Controller.PF_WIN_SZ, 16#0000_0000#);
577 end if;
578 end Panel_Fitter_Off;
579
Nico Huber4916e342016-11-04 14:37:53 +0100580 procedure Setup_Scaling
581 (Controller : in Controller_Type;
582 Mode : in HW.GFX.Mode_Type;
583 Framebuffer : in HW.GFX.Framebuffer_Type)
584 with
585 Pre =>
Nico Huber9b479412017-08-27 11:55:56 +0200586 Rotated_Width (Framebuffer) <= Mode.H_Visible and
587 Rotated_Height (Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100588 is
589 begin
Nico Huber3d06de82018-05-29 01:35:04 +0200590 if Requires_Scaling (Framebuffer, Mode) then
Nico Huber4916e342016-11-04 14:37:53 +0100591 if Config.Has_Plane_Control then
592 Setup_Skylake_Pipe_Scaler (Controller, Mode, Framebuffer);
Arthur Heymansd5198442018-03-28 17:05:12 +0200593 elsif Config.Has_GMCH_PFIT_CONTROL then
594 Setup_Gmch_Panel_Fitter (Controller);
Nico Huber4916e342016-11-04 14:37:53 +0100595 else
596 Setup_Ironlake_Panel_Fitter (Controller, Mode, Framebuffer);
597 end if;
Nico Huberb4b72792018-01-02 13:45:41 +0100598 else
599 Panel_Fitter_Off (Controller);
Nico Huber4916e342016-11-04 14:37:53 +0100600 end if;
601 end Setup_Scaling;
602
603 ----------------------------------------------------------------------------
604
Nico Huberf7f537e2018-01-02 14:15:43 +0100605 procedure Setup_FB
606 (Pipe : Pipe_Index;
607 Mode : Mode_Type;
608 Framebuffer : Framebuffer_Type)
609 is
610 -- Enable dithering if framebuffer BPC differs from port BPC,
611 -- as smooth gradients look really bad without.
612 Dither : constant Boolean := Framebuffer.BPC /= Mode.BPC;
613 begin
614 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
615
Nico Huber4dc4c612018-01-10 15:55:09 +0100616 -- Disable the cursor first.
617 Update_Cursor (Pipe, Framebuffer, Default_Cursor);
618
Nico Huberf7f537e2018-01-02 14:15:43 +0100619 Setup_Display (Controllers (Pipe), Framebuffer, Mode.BPC, Dither);
620 Setup_Scaling (Controllers (Pipe), Mode, Framebuffer);
621 end Setup_FB;
622
Nico Huber83693c82016-10-08 22:17:55 +0200623 procedure On
Nico Huberf3e23662016-12-05 21:33:03 +0100624 (Pipe : Pipe_Index;
Nico Huber83693c82016-10-08 22:17:55 +0200625 Port_Cfg : Port_Config;
Nico Huber4dc4c612018-01-10 15:55:09 +0100626 Framebuffer : Framebuffer_Type;
627 Cursor : Cursor_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200628 is
629 begin
630 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
631
Nico Huber7ad2d652016-12-07 15:19:32 +0100632 Transcoder.Setup (Pipe, Port_Cfg);
Nico Huber83693c82016-10-08 22:17:55 +0200633
Nico Huberf7f537e2018-01-02 14:15:43 +0100634 Setup_FB (Pipe, Port_Cfg.Mode, Framebuffer);
Nico Huber4dc4c612018-01-10 15:55:09 +0100635 Update_Cursor (Pipe, Framebuffer, Cursor);
Nico Huber83693c82016-10-08 22:17:55 +0200636
Nico Huberabb16d92018-05-29 01:44:26 +0200637 Transcoder.On
638 (Pipe => Pipe,
639 Port_Cfg => Port_Cfg,
640 Dither => Framebuffer.BPC /= Port_Cfg.Mode.BPC,
641 Scale => Requires_Scaling (Framebuffer, Port_Cfg.Mode));
Nico Huber83693c82016-10-08 22:17:55 +0200642 end On;
643
644 ----------------------------------------------------------------------------
645
646 procedure Planes_Off (Controller : Controller_Type) is
647 begin
Nico Huber4dc4c612018-01-10 15:55:09 +0100648 Registers.Write (Controller.CUR_CTL, 16#0000_0000#);
649 if Config.Has_Cursor_FBC_Control then
650 Registers.Write (Controller.CUR_FBC_CTL, 16#0000_0000#);
651 end if;
Nico Huber7ad2d652016-12-07 15:19:32 +0100652 Registers.Unset_Mask (Controller.SPCNTR, DSPCNTR_ENABLE);
Nico Huber83693c82016-10-08 22:17:55 +0200653 if Config.Has_Plane_Control then
654 Clear_Watermarks (Controller);
655 Registers.Unset_Mask (Controller.PLANE_CTL, PLANE_CTL_PLANE_ENABLE);
656 Registers.Write (Controller.PLANE_SURF, 16#0000_0000#);
657 else
658 Registers.Unset_Mask (Controller.DSPCNTR, DSPCNTR_ENABLE);
659 end if;
660 end Planes_Off;
661
Nico Huber7ad2d652016-12-07 15:19:32 +0100662 procedure Off (Pipe : Pipe_Index)
Nico Huberf3e23662016-12-05 21:33:03 +0100663 is
Nico Huber83693c82016-10-08 22:17:55 +0200664 begin
665 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
666
Nico Huberf3e23662016-12-05 21:33:03 +0100667 Planes_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100668 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +0100669 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100670 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +0200671 end Off;
672
Nico Huber33912aa2016-12-06 20:36:23 +0100673 procedure Legacy_VGA_Off
674 is
675 use type HW.Word8;
676 Reg8 : Word8;
677 begin
678 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
679 Port_IO.InB (Reg8, VGA_SR_DATA);
680 Port_IO.OutB (VGA_SR_DATA, Reg8 or VGA_SR01_SCREEN_OFF);
681 Time.U_Delay (100); -- PRM says 100us, Linux does 300
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200682 Registers.Set_Mask (VGACNTRL_REG, VGA_CONTROL_VGA_DISPLAY_DISABLE);
Nico Huber33912aa2016-12-06 20:36:23 +0100683 end Legacy_VGA_Off;
684
Nico Huber83693c82016-10-08 22:17:55 +0200685 procedure All_Off
686 is
Nico Huber83693c82016-10-08 22:17:55 +0200687 begin
688 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
689
Nico Huber33912aa2016-12-06 20:36:23 +0100690 Legacy_VGA_Off;
691
Nico Huberf3e23662016-12-05 21:33:03 +0100692 for Pipe in Pipe_Index loop
693 Planes_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100694 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +0100695 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100696 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +0200697 end loop;
Nico Huber83693c82016-10-08 22:17:55 +0200698 end All_Off;
699
Nico Huber83693c82016-10-08 22:17:55 +0200700end HW.GFX.GMA.Pipe_Setup;