blob: bb7b989e9b425ee1f657fc4713fa206907367dfe [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;
Nico Huber7ad2d652016-12-07 15:19:32 +010030 DSPCNTR_FORMAT_MASK : constant := 15 * 2 ** 26;
Nico Huberab69e362018-05-29 21:20:30 +020031 DSPCNTR_DISABLE_TRICKLE_FEED : constant := 1 * 2 ** 14;
32 DSPCNTR_TILED_SURFACE_LINEAR : constant := 0 * 2 ** 10;
33 DSPCNTR_TILED_SURFACE_X_TILED : constant := 1 * 2 ** 10;
34
35 DSPCNTR_TILED_SURFACE : constant array (Tiling_Type) of Word32 :=
36 (Linear => DSPCNTR_TILED_SURFACE_LINEAR,
37 X_Tiled => DSPCNTR_TILED_SURFACE_X_TILED,
38 Y_Tiled => 0); -- unsupported
Nico Huber83693c82016-10-08 22:17:55 +020039
40 DSPCNTR_MASK : constant Word32 :=
41 DSPCNTR_ENABLE or
42 DSPCNTR_GAMMA_CORRECTION or
43 DSPCNTR_FORMAT_MASK or
Nico Huberab69e362018-05-29 21:20:30 +020044 DSPCNTR_DISABLE_TRICKLE_FEED or
45 DSPCNTR_TILED_SURFACE_X_TILED;
Nico Huber83693c82016-10-08 22:17:55 +020046
47 PLANE_CTL_PLANE_ENABLE : constant := 1 * 2 ** 31;
48 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 : constant := 4 * 2 ** 24;
49 PLANE_CTL_PLANE_GAMMA_DISABLE : constant := 1 * 2 ** 13;
Nico Huber0164b022017-08-24 15:12:51 +020050 PLANE_CTL_TILED_SURFACE_MASK : constant := 7 * 2 ** 10;
51 PLANE_CTL_TILED_SURFACE_LINEAR : constant := 0 * 2 ** 10;
52 PLANE_CTL_TILED_SURFACE_X_TILED : constant := 1 * 2 ** 10;
53 PLANE_CTL_TILED_SURFACE_Y_TILED : constant := 4 * 2 ** 10;
54 PLANE_CTL_TILED_SURFACE_YF_TILED : constant := 5 * 2 ** 10;
55
56 PLANE_CTL_TILED_SURFACE : constant array (Tiling_Type) of Word32 :=
57 (Linear => PLANE_CTL_TILED_SURFACE_LINEAR,
58 X_Tiled => PLANE_CTL_TILED_SURFACE_X_TILED,
59 Y_Tiled => PLANE_CTL_TILED_SURFACE_Y_TILED);
Nico Huber83693c82016-10-08 22:17:55 +020060
Nico Huber9b479412017-08-27 11:55:56 +020061 PLANE_CTL_PLANE_ROTATION_MASK : constant := 3 * 2 ** 0;
62 PLANE_CTL_PLANE_ROTATION : constant array (Rotation_Type) of Word32 :=
63 (No_Rotation => 0 * 2 ** 0,
64 Rotated_90 => 1 * 2 ** 0,
65 Rotated_180 => 2 * 2 ** 0,
66 Rotated_270 => 3 * 2 ** 0);
67
Nico Huber83693c82016-10-08 22:17:55 +020068 PLANE_WM_ENABLE : constant := 1 * 2 ** 31;
69 PLANE_WM_LINES_SHIFT : constant := 14;
70 PLANE_WM_LINES_MASK : constant := 16#001f# * 2 ** 14;
71 PLANE_WM_BLOCKS_MASK : constant := 16#03ff# * 2 ** 0;
72
Nico Huber33912aa2016-12-06 20:36:23 +010073 VGA_SR_INDEX : constant := 16#03c4#;
74 VGA_SR_DATA : constant := 16#03c5#;
75 VGA_SR01 : constant := 16#01#;
76 VGA_SR01_SCREEN_OFF : constant := 1 * 2 ** 5;
Nico Huber3675db52016-11-04 16:27:29 +010077
78 VGA_CONTROL_VGA_DISPLAY_DISABLE : constant := 1 * 2 ** 31;
79 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK : constant := 16#0003# * 2 ** 6;
80 VGA_CONTROL_BLINK_DUTY_CYCLE_50 : constant := 2 * 2 ** 6;
81 VGA_CONTROL_VSYNC_BLINK_RATE_MASK : constant := 16#003f# * 2 ** 0;
82
Nico Huber4dc4c612018-01-10 15:55:09 +010083 CUR_CTL_PIPE_SELECT : constant array (Pipe_Index) of Word32 :=
84 (Primary => 0 * 2 ** 28,
85 Secondary => 1 * 2 ** 28,
86 Tertiary => 2 * 2 ** 28);
87 CUR_CTL_MODE : constant array (Cursor_Mode, Cursor_Size) of Word32 :=
88 (No_Cursor => (others => 16#00#),
89 ARGB_Cursor =>
90 (Cursor_64x64 => 16#27#,
91 Cursor_128x128 => 16#22#,
92 Cursor_256x256 => 16#23#));
93
94 function CUR_POS_Y (Y : Int32) return Word32 is
95 ((if Y >= 0 then 0 else 1 * 2 ** 31) or Shift_Left (Word32 (abs Y), 16))
96 with
97 Pre => Y > Int32'First;
98 function CUR_POS_X (X : Int32) return Word32 is
99 ((if X >= 0 then 0 else 1 * 2 ** 15) or Word32 (abs X))
100 with
101 Pre => X > Int32'First;
102
Nico Huber3675db52016-11-04 16:27:29 +0100103 subtype VGA_Cycle_Count is Pos32 range 2 .. 128;
104 function VGA_CONTROL_VSYNC_BLINK_RATE
105 (Cycles : VGA_Cycle_Count)
106 return Word32
107 is
108 begin
109 return Word32 (Cycles) / 2 - 1;
110 end VGA_CONTROL_VSYNC_BLINK_RATE;
111
Nico Huber7ad2d652016-12-07 15:19:32 +0100112 PF_CTRL_ENABLE : constant := 1 * 2 ** 31;
113 PF_CTRL_PIPE_SELECT_MASK : constant := 3 * 2 ** 29;
114 PF_CTRL_FILTER_MED : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200115
Nico Huber7ad2d652016-12-07 15:19:32 +0100116 PS_CTRL_ENABLE_SCALER : constant := 1 * 2 ** 31;
117 PS_CTRL_SCALER_MODE_7X5_EXTENDED : constant := 1 * 2 ** 28;
118 PS_CTRL_FILTER_SELECT_MEDIUM_2 : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200119
Arthur Heymansd5198442018-03-28 17:05:12 +0200120 GMCH_PFIT_CONTROL_SELECT_MASK : constant := 3 * 2 ** 29;
121 GMCH_PFIT_CONTROL_SELECT_PIPE_A : constant := 0 * 2 ** 29;
122 GMCH_PFIT_CONTROL_SELECT_PIPE_B : constant := 1 * 2 ** 29;
Nico Huber958c5642018-06-02 16:59:31 +0200123 GMCH_PFIT_CONTROL_SCALING_MASK : constant := 3 * 2 ** 26;
124 GMCH_PFIT_CONTROL_SCALING : constant array (Scaling_Aspect) of Word32 :=
125 (Uniform => 0 * 2 ** 26,
126 Pillarbox => 2 * 2 ** 26,
127 Letterbox => 3 * 2 ** 26);
Arthur Heymansd5198442018-03-28 17:05:12 +0200128
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200129 VGACNTRL_REG : constant Registers.Registers_Index :=
130 (if Config.Has_GMCH_VGACNTRL then
131 Registers.GMCH_VGACNTRL
132 else Registers.CPU_VGACNTRL);
133
Nico Huber83693c82016-10-08 22:17:55 +0200134 ---------------------------------------------------------------------------
135
Nico Huber83693c82016-10-08 22:17:55 +0200136 function PLANE_WM_LINES (Lines : Natural) return Word32 is
137 begin
138 return Shift_Left (Word32 (Lines), PLANE_WM_LINES_SHIFT)
139 and PLANE_WM_LINES_MASK;
140 end PLANE_WM_LINES;
141
142 function PLANE_WM_BLOCKS (Blocks : Natural) return Word32 is
143 begin
144 return Word32 (Blocks) and PLANE_WM_BLOCKS_MASK;
145 end PLANE_WM_BLOCKS;
146
147 ---------------------------------------------------------------------------
148
Nico Huberc5c767a2018-06-03 01:09:04 +0200149 function Encode (LSW, MSW : Pos32) return Word32 is
Nico Huber83693c82016-10-08 22:17:55 +0200150 begin
Nico Huber7ad2d652016-12-07 15:19:32 +0100151 return Shift_Left (Word32 (MSW) - 1, 16) or (Word32 (LSW) - 1);
Nico Huber83693c82016-10-08 22:17:55 +0200152 end Encode;
153
154 ----------------------------------------------------------------------------
155
Nico Huber83693c82016-10-08 22:17:55 +0200156 procedure Clear_Watermarks (Controller : Controller_Type) is
157 begin
Nico Huber4dc4c612018-01-10 15:55:09 +0100158 Registers.Write (Controller.CUR_BUF_CFG, 16#0000_0000#);
159 for Level in WM_Levels loop
160 Registers.Write (Controller.CUR_WM (Level), 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200161 end loop;
Nico Huber4dc4c612018-01-10 15:55:09 +0100162 Registers.Write (Controller.PLANE_BUF_CFG, 16#0000_0000#);
163 for Level in WM_Levels loop
164 Registers.Write (Controller.PLANE_WM (Level), 16#0000_0000#);
165 end loop;
166 Registers.Write (Controller.WM_LINETIME, 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200167 end Clear_Watermarks;
168
169 procedure Setup_Watermarks (Controller : Controller_Type)
170 is
Nico Huberf3e23662016-12-05 21:33:03 +0100171 type Per_Plane_Buffer_Range is array (Pipe_Index) of Word32;
Nico Huber4dc4c612018-01-10 15:55:09 +0100172 Cur_Buffer_Range : constant Per_Plane_Buffer_Range :=
173 (Primary => Shift_Left ( 7, 16) or 0,
174 Secondary => Shift_Left (167, 16) or 160,
175 Tertiary => Shift_Left (327, 16) or 320);
176 Plane_Buffer_Range : constant Per_Plane_Buffer_Range :=
177 (Primary => Shift_Left (159, 16) or 8,
178 Secondary => Shift_Left (319, 16) or 168,
179 Tertiary => Shift_Left (479, 16) or 328);
Nico Huber83693c82016-10-08 22:17:55 +0200180 begin
181 Registers.Write
182 (Register => Controller.PLANE_BUF_CFG,
Nico Huber4dc4c612018-01-10 15:55:09 +0100183 Value => Plane_Buffer_Range (Controller.Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200184 Registers.Write
185 (Register => Controller.PLANE_WM (0),
186 Value => PLANE_WM_ENABLE or
187 PLANE_WM_LINES (2) or
Nico Huber4dc4c612018-01-10 15:55:09 +0100188 PLANE_WM_BLOCKS (152));
189 Registers.Write
190 (Register => Controller.CUR_BUF_CFG,
191 Value => Cur_Buffer_Range (Controller.Pipe));
192 Registers.Write
193 (Register => Controller.CUR_WM (0),
194 Value => PLANE_WM_ENABLE or
195 PLANE_WM_LINES (2) or
196 PLANE_WM_BLOCKS (8));
Nico Huber83693c82016-10-08 22:17:55 +0200197 end Setup_Watermarks;
198
199 ----------------------------------------------------------------------------
200
Nico Huber3675db52016-11-04 16:27:29 +0100201 procedure Setup_Hires_Plane
Nico Huber6a4dfc82016-11-04 15:50:58 +0100202 (Controller : Controller_Type;
Nico Huber0164b022017-08-24 15:12:51 +0200203 FB : HW.GFX.Framebuffer_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200204 with
205 Global => (In_Out => Registers.Register_State),
206 Depends =>
207 (Registers.Register_State
208 =>+
209 (Registers.Register_State,
210 Controller,
Nico Huber9b479412017-08-27 11:55:56 +0200211 FB)),
Nico Huber5ef4d602017-12-13 13:56:47 +0100212 Pre => FB.Height + FB.Start_Y <= FB.V_Stride
Nico Huber83693c82016-10-08 22:17:55 +0200213 is
214 -- FIXME: setup correct format, based on framebuffer RGB format
215 Format : constant Word32 := 6 * 2 ** 26;
216 PRI : Word32 := DSPCNTR_ENABLE or Format;
Nico Huber83693c82016-10-08 22:17:55 +0200217 begin
218 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
219
Nico Huber83693c82016-10-08 22:17:55 +0200220 if Config.Has_Plane_Control then
Nico Huber9b479412017-08-27 11:55:56 +0200221 declare
Nico Huber34be6542017-12-13 09:26:24 +0100222 Stride, Offset : Word32;
Nico Huberc5c767a2018-06-03 01:09:04 +0200223 Width : constant Width_Type := Rotated_Width (FB);
224 Height : constant Width_Type := Rotated_Height (FB);
Nico Huber9b479412017-08-27 11:55:56 +0200225 begin
226 if Rotation_90 (FB) then
Nico Huber5ef4d602017-12-13 13:56:47 +0100227 Stride := Word32 (FB_Pitch (FB.V_Stride, FB));
228 Offset := Shift_Left (Word32 (FB.Start_X), 16) or
229 Word32 (FB.V_Stride - FB.Height - FB.Start_Y);
Nico Huber9b479412017-08-27 11:55:56 +0200230 else
Nico Huber5ef4d602017-12-13 13:56:47 +0100231 Stride := Word32 (FB_Pitch (FB.Stride, FB));
232 Offset := Shift_Left (Word32 (FB.Start_Y), 16) or
233 Word32 (FB.Start_X);
Nico Huber9b479412017-08-27 11:55:56 +0200234 end if;
235 Registers.Write
236 (Register => Controller.PLANE_CTL,
237 Value => PLANE_CTL_PLANE_ENABLE or
238 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
239 PLANE_CTL_PLANE_GAMMA_DISABLE or
240 PLANE_CTL_TILED_SURFACE (FB.Tiling) or
241 PLANE_CTL_PLANE_ROTATION (FB.Rotation));
242 Registers.Write (Controller.PLANE_OFFSET, Offset);
243 Registers.Write (Controller.PLANE_SIZE, Encode (Width, Height));
244 Registers.Write (Controller.PLANE_STRIDE, Stride);
245 Registers.Write (Controller.PLANE_POS, 16#0000_0000#);
Nico Huber34be6542017-12-13 09:26:24 +0100246 Registers.Write (Controller.PLANE_SURF, FB.Offset and 16#ffff_f000#);
Nico Huber9b479412017-08-27 11:55:56 +0200247 end;
Nico Huber83693c82016-10-08 22:17:55 +0200248 else
249 if Config.Disable_Trickle_Feed then
250 PRI := PRI or DSPCNTR_DISABLE_TRICKLE_FEED;
251 end if;
252 -- for now, just disable gamma LUT (can't do anything
253 -- useful without colorimetry information from display)
254 Registers.Unset_And_Set_Mask
255 (Register => Controller.DSPCNTR,
256 Mask_Unset => DSPCNTR_MASK,
Nico Huberab69e362018-05-29 21:20:30 +0200257 Mask_Set => PRI or DSPCNTR_TILED_SURFACE (FB.Tiling));
Nico Huber83693c82016-10-08 22:17:55 +0200258
Nico Huber0164b022017-08-24 15:12:51 +0200259 Registers.Write
260 (Controller.DSPSTRIDE, Word32 (Pixel_To_Bytes (FB.Stride, FB)));
Nico Huberab69e362018-05-29 21:20:30 +0200261 if Config.Has_DSP_Linoff and then FB.Tiling = Linear then
Nico Huberd49b56b2018-06-18 17:19:15 +0200262 pragma Assert_And_Cut (True);
263 declare
264 Linear_Offset : constant Pixel_Type :=
265 FB.Start_Y * FB.Stride + FB.Start_X;
266 begin
267 Registers.Write
268 (Register => Controller.DSPLINOFF,
269 Value => Word32 (Pixel_To_Bytes (Linear_Offset, FB)));
270 Registers.Write (Controller.DSPTILEOFF, 0);
271 end;
Nico Huber5ef4d602017-12-13 13:56:47 +0100272 else
Nico Huberab69e362018-05-29 21:20:30 +0200273 if Config.Has_DSP_Linoff then
274 Registers.Write (Controller.DSPLINOFF, 0);
275 end if;
Nico Huber5ef4d602017-12-13 13:56:47 +0100276 Registers.Write
277 (Register => Controller.DSPTILEOFF,
278 Value => Shift_Left (Word32 (FB.Start_Y), 16) or
279 Word32 (FB.Start_X));
Nico Huber83693c82016-10-08 22:17:55 +0200280 end if;
Nico Huber8fd92a12018-01-02 14:02:59 +0100281 Registers.Write (Controller.DSPSURF, FB.Offset and 16#ffff_f000#);
Nico Huber83693c82016-10-08 22:17:55 +0200282 end if;
Nico Huber3675db52016-11-04 16:27:29 +0100283 end Setup_Hires_Plane;
284
285 procedure Setup_Display
Nico Huber113a14b2016-12-06 21:59:15 +0100286 (Controller : Controller_Type;
287 Framebuffer : Framebuffer_Type;
288 Dither_BPC : BPC_Type;
289 Dither : Boolean)
Nico Huber3675db52016-11-04 16:27:29 +0100290 with
Nico Huber9b479412017-08-27 11:55:56 +0200291 Pre =>
292 Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
Nico Huber5ef4d602017-12-13 13:56:47 +0100293 Framebuffer.Height + Framebuffer.Start_Y <= Framebuffer.V_Stride
Nico Huber3675db52016-11-04 16:27:29 +0100294 is
295 use type Word8;
296
297 Reg8 : Word8;
298 begin
299 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
300
301 if Config.Has_Plane_Control then
302 Setup_Watermarks (Controller);
303 end if;
304
305 if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
Nico Huberfbb42202016-11-07 15:08:26 +0100306 if Config.VGA_Plane_Workaround then
307 Registers.Unset_And_Set_Mask
308 (Register => Registers.ILK_DISPLAY_CHICKEN1,
309 Mask_Unset => ILK_DISPLAY_CHICKEN1_VGA_MASK,
310 Mask_Set => ILK_DISPLAY_CHICKEN1_VGA_ENABLE);
311 Registers.Unset_And_Set_Mask
312 (Register => Registers.ILK_DISPLAY_CHICKEN2,
313 Mask_Unset => ILK_DISPLAY_CHICKEN2_VGA_MASK,
314 Mask_Set => ILK_DISPLAY_CHICKEN2_VGA_ENABLE);
315 end if;
316
Nico Huber3675db52016-11-04 16:27:29 +0100317 Registers.Unset_And_Set_Mask
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200318 (Register => VGACNTRL_REG,
Nico Huber3675db52016-11-04 16:27:29 +0100319 Mask_Unset => VGA_CONTROL_VGA_DISPLAY_DISABLE or
320 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK or
321 VGA_CONTROL_VSYNC_BLINK_RATE_MASK,
322 Mask_Set => VGA_CONTROL_BLINK_DUTY_CYCLE_50 or
323 VGA_CONTROL_VSYNC_BLINK_RATE (30));
324
325 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
326 Port_IO.InB (Reg8, VGA_SR_DATA);
327 Port_IO.OutB (VGA_SR_DATA, Reg8 and not (VGA_SR01_SCREEN_OFF));
328 else
Nico Huber6a4dfc82016-11-04 15:50:58 +0100329 Setup_Hires_Plane (Controller, Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100330 end if;
331
332 Registers.Write
333 (Register => Controller.PIPESRC,
334 Value => Encode
Nico Huber9b479412017-08-27 11:55:56 +0200335 (Rotated_Height (Framebuffer), Rotated_Width (Framebuffer)));
Nico Huber83693c82016-10-08 22:17:55 +0200336
Nico Huber113a14b2016-12-06 21:59:15 +0100337 if Config.Has_Pipeconf_Misc then
338 Registers.Write
339 (Register => Controller.PIPEMISC,
Nico Huber7ad2d652016-12-07 15:19:32 +0100340 Value => Transcoder.BPC_Conf (Dither_BPC, Dither));
Nico Huber113a14b2016-12-06 21:59:15 +0100341 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200342 end Setup_Display;
343
344 ----------------------------------------------------------------------------
345
Nico Huber4dc4c612018-01-10 15:55:09 +0100346 procedure Update_Cursor
347 (Pipe : Pipe_Index;
348 FB : Framebuffer_Type;
349 Cursor : Cursor_Type)
350 is
351 begin
352 -- on some platforms writing CUR_CTL disables self-arming of CUR_POS
353 -- so keep it first
354 Registers.Write
355 (Register => Controllers (Pipe).CUR_CTL,
356 Value => CUR_CTL_PIPE_SELECT (Pipe) or
357 CUR_CTL_MODE (Cursor.Mode, Cursor.Size));
358 Place_Cursor (Pipe, FB, Cursor);
359 end Update_Cursor;
360
361 procedure Place_Cursor
362 (Pipe : Pipe_Index;
363 FB : Framebuffer_Type;
364 Cursor : Cursor_Type)
365 is
366 Width : constant Width_Type := Cursor_Width (Cursor.Size);
367 X : Int32 := Cursor.Center_X - Width / 2;
368 Y : Int32 := Cursor.Center_Y - Width / 2;
369 begin
370 -- off-screen cursor needs special care
371 if X <= -Width or Y <= -Width or
Nico Huberc5c767a2018-06-03 01:09:04 +0200372 X >= Rotated_Width (FB) or Y >= Rotated_Height (FB) or
Nico Huber4dc4c612018-01-10 15:55:09 +0100373 X > Config.Maximum_Cursor_X or Y > Config.Maximum_Cursor_Y
374 then
375 X := -Width;
376 Y := -Width;
377 end if;
378 Registers.Write
379 (Register => Controllers (Pipe).CUR_POS,
380 Value => CUR_POS_Y (Y) or CUR_POS_X (X));
381 -- write to CUR_BASE always arms other CUR_* registers
382 Registers.Write
383 (Register => Controllers (Pipe).CUR_BASE,
384 Value => Shift_Left (Word32 (Cursor.GTT_Offset), 12));
385 end Place_Cursor;
386
387 ----------------------------------------------------------------------------
388
Nico Huberc5c767a2018-06-03 01:09:04 +0200389 function Scale (Val, Max, Num, Denom : Width_Type)
390 return Width_Type is ((Val * Num) / Denom)
Nico Huberda1185e2018-06-03 01:07:46 +0200391 with
Nico Huberc5c767a2018-06-03 01:09:04 +0200392 Pre => Denom <= Num and Val * Num < Max * Denom,
Nico Huberda1185e2018-06-03 01:07:46 +0200393 Post => Scale'Result < Max;
394
Nico Huber4916e342016-11-04 14:37:53 +0100395 procedure Scale_Keep_Aspect
Nico Huberc5c767a2018-06-03 01:09:04 +0200396 (Width : out Width_Type;
397 Height : out Height_Type;
398 Max_Width : in Width_Type;
399 Max_Height : in Height_Type;
Nico Huber4916e342016-11-04 14:37:53 +0100400 Framebuffer : in Framebuffer_Type)
401 with
402 Pre =>
Nico Huberc5c767a2018-06-03 01:09:04 +0200403 Rotated_Width (Framebuffer) <= Max_Width and
404 Rotated_Height (Framebuffer) <= Max_Height,
Nico Huber4916e342016-11-04 14:37:53 +0100405 Post =>
406 Width <= Max_Width and Height <= Max_Height
407 is
Nico Huberc5c767a2018-06-03 01:09:04 +0200408 Src_Width : constant Width_Type := Rotated_Width (Framebuffer);
409 Src_Height : constant Height_Type := Rotated_Height (Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100410 begin
Nico Huberda1185e2018-06-03 01:07:46 +0200411 case Scaling_Type (Src_Width, Src_Height, Max_Width, Max_Height) is
412 when Letterbox =>
413 Width := Max_Width;
414 Height := Scale (Src_Height, Max_Height, Max_Width, Src_Width);
415 when Pillarbox =>
416 Width := Scale (Src_Width, Max_Width, Max_Height, Src_Height);
417 Height := Max_Height;
418 when Uniform =>
419 Width := Max_Width;
420 Height := Max_Height;
421 end case;
Nico Huber4916e342016-11-04 14:37:53 +0100422 end Scale_Keep_Aspect;
423
424 procedure Setup_Skylake_Pipe_Scaler
425 (Controller : in Controller_Type;
426 Mode : in HW.GFX.Mode_Type;
427 Framebuffer : in HW.GFX.Framebuffer_Type)
428 with
429 Pre =>
Nico Huber9b479412017-08-27 11:55:56 +0200430 Rotated_Width (Framebuffer) <= Mode.H_Visible and
431 Rotated_Height (Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100432 is
Nico Huber7ad2d652016-12-07 15:19:32 +0100433 use type Registers.Registers_Invalid_Index;
434
Nico Huber4916e342016-11-04 14:37:53 +0100435 -- Enable 7x5 extended mode where possible:
436 Scaler_Mode : constant Word32 :=
437 (if Controller.PS_CTRL_2 /= Registers.Invalid_Register then
438 PS_CTRL_SCALER_MODE_7X5_EXTENDED else 0);
439
Nico Huberc5c767a2018-06-03 01:09:04 +0200440 Width_In : constant Width_Type := Rotated_Width (Framebuffer);
441 Height_In : constant Height_Type := Rotated_Height (Framebuffer);
Nico Huber9b479412017-08-27 11:55:56 +0200442
Nico Huber4916e342016-11-04 14:37:53 +0100443 -- We can scale up to 2.99x horizontally:
Nico Huber9b479412017-08-27 11:55:56 +0200444 Horizontal_Limit : constant Pos32 := (Width_In * 299) / 100;
Nico Huber4916e342016-11-04 14:37:53 +0100445 -- The third scaler is limited to 1.99x
446 -- vertical scaling for source widths > 2048:
447 Vertical_Limit : constant Pos32 :=
Nico Huber9b479412017-08-27 11:55:56 +0200448 (Height_In *
Nico Huber4916e342016-11-04 14:37:53 +0100449 (if Controller.PS_CTRL_2 = Registers.Invalid_Register and
Nico Huber9b479412017-08-27 11:55:56 +0200450 Width_In > 2048
Nico Huber4916e342016-11-04 14:37:53 +0100451 then
452 199
453 else
454 299)) / 100;
455
Nico Huberc5c767a2018-06-03 01:09:04 +0200456 Width : Width_Type;
457 Height : Height_Type;
Nico Huber4916e342016-11-04 14:37:53 +0100458 begin
459 -- Writes to WIN_SZ arm the PS registers.
460
461 Scale_Keep_Aspect
462 (Width => Width,
463 Height => Height,
Nico Huberc5c767a2018-06-03 01:09:04 +0200464 Max_Width => Pos32'Min (Horizontal_Limit, Mode.H_Visible),
465 Max_Height => Pos32'Min (Vertical_Limit, Mode.V_Visible),
Nico Huber4916e342016-11-04 14:37:53 +0100466 Framebuffer => Framebuffer);
467
468 Registers.Write
469 (Register => Controller.PS_CTRL_1,
470 Value => PS_CTRL_ENABLE_SCALER or Scaler_Mode);
471 Registers.Write
472 (Register => Controller.PS_WIN_POS_1,
473 Value =>
Nico Huberc5c767a2018-06-03 01:09:04 +0200474 Shift_Left (Word32 (Mode.H_Visible - Width) / 2, 16) or
475 Word32 (Mode.V_Visible - Height) / 2);
Nico Huber4916e342016-11-04 14:37:53 +0100476 Registers.Write
477 (Register => Controller.PS_WIN_SZ_1,
478 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
479 end Setup_Skylake_Pipe_Scaler;
480
481 procedure Setup_Ironlake_Panel_Fitter
482 (Controller : in Controller_Type;
483 Mode : in HW.GFX.Mode_Type;
484 Framebuffer : in HW.GFX.Framebuffer_Type)
485 with
486 Pre =>
Nico Huber9b479412017-08-27 11:55:56 +0200487 Rotated_Width (Framebuffer) <= Mode.H_Visible and
488 Rotated_Height (Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100489 is
490 -- Force 1:1 mapping of panel fitter:pipe
491 PF_Ctrl_Pipe_Sel : constant Word32 :=
492 (if Config.Has_PF_Pipe_Select then
493 (case Controller.PF_CTRL is
494 when Registers.PFA_CTL_1 => 0 * 2 ** 29,
495 when Registers.PFB_CTL_1 => 1 * 2 ** 29,
496 when Registers.PFC_CTL_1 => 2 * 2 ** 29,
497 when others => 0) else 0);
498
Nico Huberc5c767a2018-06-03 01:09:04 +0200499 Width : Width_Type;
500 Height : Height_Type;
Nico Huberfdb0df12018-02-07 14:30:34 +0100501 X, Y : Int32;
Nico Huber4916e342016-11-04 14:37:53 +0100502 begin
503 -- Writes to WIN_SZ arm the PF registers.
504
505 Scale_Keep_Aspect
506 (Width => Width,
507 Height => Height,
Nico Huberc5c767a2018-06-03 01:09:04 +0200508 Max_Width => Mode.H_Visible,
509 Max_Height => Mode.V_Visible,
Nico Huber4916e342016-11-04 14:37:53 +0100510 Framebuffer => Framebuffer);
511
Nico Huberfdb0df12018-02-07 14:30:34 +0100512 -- Do not scale to odd width (at least Haswell has trouble with this).
Nico Huberc5c767a2018-06-03 01:09:04 +0200513 if Width < Mode.H_Visible and Width mod 2 = 1 then
Nico Huberfdb0df12018-02-07 14:30:34 +0100514 Width := Width + 1;
515 end if;
Nico Huberb3b9fa32018-06-18 16:16:41 +0200516 -- Do not scale to odd height (at least Sandy Bridge makes trouble).
517 if Height < Mode.V_Visible and Height mod 2 = 1 then
518 Height := Height + 1;
519 end if;
Nico Huberfdb0df12018-02-07 14:30:34 +0100520
Nico Huberc5c767a2018-06-03 01:09:04 +0200521 X := (Mode.H_Visible - Width) / 2;
522 Y := (Mode.V_Visible - Height) / 2;
Nico Huberfdb0df12018-02-07 14:30:34 +0100523
524 -- Hardware is picky about minimal horizontal gaps.
Nico Huberc5c767a2018-06-03 01:09:04 +0200525 if Mode.H_Visible - Width <= 3 then
526 Width := Mode.H_Visible;
Nico Huberfdb0df12018-02-07 14:30:34 +0100527 X := 0;
528 end if;
529
Nico Huber4916e342016-11-04 14:37:53 +0100530 Registers.Write
531 (Register => Controller.PF_CTRL,
532 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_CTRL_FILTER_MED);
533 Registers.Write
534 (Register => Controller.PF_WIN_POS,
Nico Huberfdb0df12018-02-07 14:30:34 +0100535 Value => Shift_Left (Word32 (X), 16) or Word32 (Y));
Nico Huber4916e342016-11-04 14:37:53 +0100536 Registers.Write
537 (Register => Controller.PF_WIN_SZ,
538 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
539 end Setup_Ironlake_Panel_Fitter;
540
Arthur Heymansd5198442018-03-28 17:05:12 +0200541 procedure Setup_Gmch_Panel_Fitter
Nico Huber958c5642018-06-02 16:59:31 +0200542 (Controller : in Controller_Type;
543 Mode : in HW.GFX.Mode_Type;
544 Framebuffer : in HW.GFX.Framebuffer_Type)
Arthur Heymansd5198442018-03-28 17:05:12 +0200545 is
546 PF_Ctrl_Pipe_Sel : constant Word32 :=
547 (case Controller.Pipe is
548 when Primary => GMCH_PFIT_CONTROL_SELECT_PIPE_A,
549 when Secondary => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
550 when others => 0);
Nico Huber958c5642018-06-02 16:59:31 +0200551
Arthur Heymansf70edda2018-08-21 18:37:00 +0200552 -- Work around a quirk:
553 -- In legacy VGA mode Pillarbox fails to display anything so just force
554 -- 'auto' mode on all displays, which will the output stretched to
555 -- fullscreen .
Nico Huber958c5642018-06-02 16:59:31 +0200556 PF_Ctrl_Scaling : constant Word32 :=
Arthur Heymansf70edda2018-08-21 18:37:00 +0200557 (if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
558 GMCH_PFIT_CONTROL_SCALING (Uniform)
559 else
560 GMCH_PFIT_CONTROL_SCALING (Scaling_Type (Framebuffer, Mode)));
Nico Huber958c5642018-06-02 16:59:31 +0200561
Arthur Heymansd5198442018-03-28 17:05:12 +0200562 In_Use : Boolean;
563 begin
564 Registers.Is_Set_Mask
565 (Register => Registers.GMCH_PFIT_CONTROL,
566 Mask => PF_CTRL_ENABLE,
567 Result => In_Use);
568
569 if not In_Use then
570 Registers.Write
571 (Register => Registers.GMCH_PFIT_CONTROL,
Nico Huber958c5642018-06-02 16:59:31 +0200572 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_Ctrl_Scaling);
Arthur Heymansd5198442018-03-28 17:05:12 +0200573 else
Nico Huber7ba7bd62018-06-06 12:27:09 +0200574 pragma Debug (Debug.Put_Line
575 ("GMCH Pannel fitter already in use, skipping..."));
Arthur Heymansd5198442018-03-28 17:05:12 +0200576 end if;
577 end Setup_Gmch_Panel_Fitter;
578
Nico Huberf361ec82018-06-02 18:01:45 +0200579 procedure Gmch_Panel_Fitter_Pipe (Pipe : out Pipe_Index)
580 is
581 Used_For_Secondary : Boolean;
582 begin
583 Registers.Is_Set_Mask
584 (Register => Registers.GMCH_PFIT_CONTROL,
585 Mask => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
586 Result => Used_For_Secondary);
587 Pipe := (if Used_For_Secondary then Secondary else Primary);
588 end;
589
Nico Huberb4b72792018-01-02 13:45:41 +0100590 procedure Panel_Fitter_Off (Controller : Controller_Type)
591 is
592 use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
Nico Huberf361ec82018-06-02 18:01:45 +0200593 Pipe_Using_PF : Pipe_Index;
Nico Huberb4b72792018-01-02 13:45:41 +0100594 begin
595 -- Writes to WIN_SZ arm the PS/PF registers.
596 if Config.Has_Plane_Control then
597 Registers.Unset_Mask (Controller.PS_CTRL_1, PS_CTRL_ENABLE_SCALER);
598 Registers.Write (Controller.PS_WIN_SZ_1, 16#0000_0000#);
599 if Controller.PS_CTRL_2 /= Registers.Invalid_Register and
600 Controller.PS_WIN_SZ_2 /= Registers.Invalid_Register
601 then
602 Registers.Unset_Mask (Controller.PS_CTRL_2, PS_CTRL_ENABLE_SCALER);
603 Registers.Write (Controller.PS_WIN_SZ_2, 16#0000_0000#);
604 end if;
Arthur Heymansd5198442018-03-28 17:05:12 +0200605 elsif Config.Has_GMCH_PFIT_CONTROL then
Nico Huberf361ec82018-06-02 18:01:45 +0200606 Gmch_Panel_Fitter_Pipe (Pipe_Using_PF);
607 if Pipe_Using_PF = Controller.Pipe then
608 Registers.Unset_Mask (Registers.GMCH_PFIT_CONTROL, PF_CTRL_ENABLE);
Arthur Heymansd5198442018-03-28 17:05:12 +0200609 end if;
Nico Huberb4b72792018-01-02 13:45:41 +0100610 else
611 Registers.Unset_Mask (Controller.PF_CTRL, PF_CTRL_ENABLE);
612 Registers.Write (Controller.PF_WIN_SZ, 16#0000_0000#);
613 end if;
614 end Panel_Fitter_Off;
615
Nico Huber4916e342016-11-04 14:37:53 +0100616 procedure Setup_Scaling
617 (Controller : in Controller_Type;
618 Mode : in HW.GFX.Mode_Type;
619 Framebuffer : in HW.GFX.Framebuffer_Type)
620 with
621 Pre =>
Nico Huber9b479412017-08-27 11:55:56 +0200622 Rotated_Width (Framebuffer) <= Mode.H_Visible and
623 Rotated_Height (Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100624 is
625 begin
Nico Huber3d06de82018-05-29 01:35:04 +0200626 if Requires_Scaling (Framebuffer, Mode) then
Nico Huber4916e342016-11-04 14:37:53 +0100627 if Config.Has_Plane_Control then
628 Setup_Skylake_Pipe_Scaler (Controller, Mode, Framebuffer);
Arthur Heymansd5198442018-03-28 17:05:12 +0200629 elsif Config.Has_GMCH_PFIT_CONTROL then
Nico Huber958c5642018-06-02 16:59:31 +0200630 Setup_Gmch_Panel_Fitter (Controller, Mode, Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100631 else
632 Setup_Ironlake_Panel_Fitter (Controller, Mode, Framebuffer);
633 end if;
Nico Huberb4b72792018-01-02 13:45:41 +0100634 else
635 Panel_Fitter_Off (Controller);
Nico Huber4916e342016-11-04 14:37:53 +0100636 end if;
637 end Setup_Scaling;
638
Nico Huberf361ec82018-06-02 18:01:45 +0200639 procedure Scaler_Available (Available : out Boolean; Pipe : Pipe_Index)
640 is
641 Pipe_Using_PF : Pipe_Index := Pipe_Index'First;
642 PF_Enabled : Boolean;
643 begin
644 if Config.Has_GMCH_PFIT_CONTROL then
645 Registers.Is_Set_Mask
646 (Register => Registers.GMCH_PFIT_CONTROL,
647 Mask => PF_CTRL_ENABLE,
648 Result => PF_Enabled);
649 if PF_Enabled then
650 Gmch_Panel_Fitter_Pipe (Pipe_Using_PF);
651 end if;
652
653 Available := not PF_Enabled or Pipe_Using_PF = Pipe;
654 else
655 Available := True;
656 end if;
657 end Scaler_Available;
658
Nico Huber4916e342016-11-04 14:37:53 +0100659 ----------------------------------------------------------------------------
660
Nico Huberf7f537e2018-01-02 14:15:43 +0100661 procedure Setup_FB
662 (Pipe : Pipe_Index;
663 Mode : Mode_Type;
664 Framebuffer : Framebuffer_Type)
665 is
666 -- Enable dithering if framebuffer BPC differs from port BPC,
667 -- as smooth gradients look really bad without.
668 Dither : constant Boolean := Framebuffer.BPC /= Mode.BPC;
669 begin
670 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
671
Nico Huber4dc4c612018-01-10 15:55:09 +0100672 -- Disable the cursor first.
673 Update_Cursor (Pipe, Framebuffer, Default_Cursor);
674
Nico Huberf7f537e2018-01-02 14:15:43 +0100675 Setup_Display (Controllers (Pipe), Framebuffer, Mode.BPC, Dither);
676 Setup_Scaling (Controllers (Pipe), Mode, Framebuffer);
677 end Setup_FB;
678
Nico Huber83693c82016-10-08 22:17:55 +0200679 procedure On
Nico Huberf3e23662016-12-05 21:33:03 +0100680 (Pipe : Pipe_Index;
Nico Huber83693c82016-10-08 22:17:55 +0200681 Port_Cfg : Port_Config;
Nico Huber4dc4c612018-01-10 15:55:09 +0100682 Framebuffer : Framebuffer_Type;
683 Cursor : Cursor_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200684 is
685 begin
686 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
687
Nico Huber7ad2d652016-12-07 15:19:32 +0100688 Transcoder.Setup (Pipe, Port_Cfg);
Nico Huber83693c82016-10-08 22:17:55 +0200689
Nico Huberf7f537e2018-01-02 14:15:43 +0100690 Setup_FB (Pipe, Port_Cfg.Mode, Framebuffer);
Nico Huber4dc4c612018-01-10 15:55:09 +0100691 Update_Cursor (Pipe, Framebuffer, Cursor);
Nico Huber83693c82016-10-08 22:17:55 +0200692
Nico Huberabb16d92018-05-29 01:44:26 +0200693 Transcoder.On
694 (Pipe => Pipe,
695 Port_Cfg => Port_Cfg,
696 Dither => Framebuffer.BPC /= Port_Cfg.Mode.BPC,
697 Scale => Requires_Scaling (Framebuffer, Port_Cfg.Mode));
Nico Huber83693c82016-10-08 22:17:55 +0200698 end On;
699
700 ----------------------------------------------------------------------------
701
702 procedure Planes_Off (Controller : Controller_Type) is
703 begin
Nico Huber4dc4c612018-01-10 15:55:09 +0100704 Registers.Write (Controller.CUR_CTL, 16#0000_0000#);
705 if Config.Has_Cursor_FBC_Control then
706 Registers.Write (Controller.CUR_FBC_CTL, 16#0000_0000#);
707 end if;
Nico Huber7ad2d652016-12-07 15:19:32 +0100708 Registers.Unset_Mask (Controller.SPCNTR, DSPCNTR_ENABLE);
Nico Huber83693c82016-10-08 22:17:55 +0200709 if Config.Has_Plane_Control then
710 Clear_Watermarks (Controller);
711 Registers.Unset_Mask (Controller.PLANE_CTL, PLANE_CTL_PLANE_ENABLE);
712 Registers.Write (Controller.PLANE_SURF, 16#0000_0000#);
713 else
714 Registers.Unset_Mask (Controller.DSPCNTR, DSPCNTR_ENABLE);
715 end if;
716 end Planes_Off;
717
Nico Huber7ad2d652016-12-07 15:19:32 +0100718 procedure Off (Pipe : Pipe_Index)
Nico Huberf3e23662016-12-05 21:33:03 +0100719 is
Nico Huber83693c82016-10-08 22:17:55 +0200720 begin
721 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
722
Nico Huberf3e23662016-12-05 21:33:03 +0100723 Planes_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100724 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +0100725 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100726 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +0200727 end Off;
728
Nico Huber33912aa2016-12-06 20:36:23 +0100729 procedure Legacy_VGA_Off
730 is
731 use type HW.Word8;
732 Reg8 : Word8;
733 begin
734 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
735 Port_IO.InB (Reg8, VGA_SR_DATA);
736 Port_IO.OutB (VGA_SR_DATA, Reg8 or VGA_SR01_SCREEN_OFF);
737 Time.U_Delay (100); -- PRM says 100us, Linux does 300
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200738 Registers.Set_Mask (VGACNTRL_REG, VGA_CONTROL_VGA_DISPLAY_DISABLE);
Nico Huber33912aa2016-12-06 20:36:23 +0100739 end Legacy_VGA_Off;
740
Nico Huber83693c82016-10-08 22:17:55 +0200741 procedure All_Off
742 is
Nico Huber83693c82016-10-08 22:17:55 +0200743 begin
744 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
745
Nico Huber33912aa2016-12-06 20:36:23 +0100746 Legacy_VGA_Off;
747
Nico Huberf3e23662016-12-05 21:33:03 +0100748 for Pipe in Pipe_Index loop
749 Planes_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100750 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +0100751 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100752 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +0200753 end loop;
Nico Huber83693c82016-10-08 22:17:55 +0200754 end All_Off;
755
Nico Huber83693c82016-10-08 22:17:55 +0200756end HW.GFX.GMA.Pipe_Setup;