blob: 90e2a8c4be4d92a2df8dd3915f3ee74855b138c4 [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;
123
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200124 VGACNTRL_REG : constant Registers.Registers_Index :=
125 (if Config.Has_GMCH_VGACNTRL then
126 Registers.GMCH_VGACNTRL
127 else Registers.CPU_VGACNTRL);
128
Nico Huber83693c82016-10-08 22:17:55 +0200129 ---------------------------------------------------------------------------
130
Nico Huber83693c82016-10-08 22:17:55 +0200131 function PLANE_WM_LINES (Lines : Natural) return Word32 is
132 begin
133 return Shift_Left (Word32 (Lines), PLANE_WM_LINES_SHIFT)
134 and PLANE_WM_LINES_MASK;
135 end PLANE_WM_LINES;
136
137 function PLANE_WM_BLOCKS (Blocks : Natural) return Word32 is
138 begin
139 return Word32 (Blocks) and PLANE_WM_BLOCKS_MASK;
140 end PLANE_WM_BLOCKS;
141
142 ---------------------------------------------------------------------------
143
144 function Encode (LSW, MSW : Pos16) return Word32 is
145 begin
Nico Huber7ad2d652016-12-07 15:19:32 +0100146 return Shift_Left (Word32 (MSW) - 1, 16) or (Word32 (LSW) - 1);
Nico Huber83693c82016-10-08 22:17:55 +0200147 end Encode;
148
149 ----------------------------------------------------------------------------
150
Nico Huber83693c82016-10-08 22:17:55 +0200151 procedure Clear_Watermarks (Controller : Controller_Type) is
152 begin
Nico Huber4dc4c612018-01-10 15:55:09 +0100153 Registers.Write (Controller.CUR_BUF_CFG, 16#0000_0000#);
154 for Level in WM_Levels loop
155 Registers.Write (Controller.CUR_WM (Level), 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200156 end loop;
Nico Huber4dc4c612018-01-10 15:55:09 +0100157 Registers.Write (Controller.PLANE_BUF_CFG, 16#0000_0000#);
158 for Level in WM_Levels loop
159 Registers.Write (Controller.PLANE_WM (Level), 16#0000_0000#);
160 end loop;
161 Registers.Write (Controller.WM_LINETIME, 16#0000_0000#);
Nico Huber83693c82016-10-08 22:17:55 +0200162 end Clear_Watermarks;
163
164 procedure Setup_Watermarks (Controller : Controller_Type)
165 is
Nico Huberf3e23662016-12-05 21:33:03 +0100166 type Per_Plane_Buffer_Range is array (Pipe_Index) of Word32;
Nico Huber4dc4c612018-01-10 15:55:09 +0100167 Cur_Buffer_Range : constant Per_Plane_Buffer_Range :=
168 (Primary => Shift_Left ( 7, 16) or 0,
169 Secondary => Shift_Left (167, 16) or 160,
170 Tertiary => Shift_Left (327, 16) or 320);
171 Plane_Buffer_Range : constant Per_Plane_Buffer_Range :=
172 (Primary => Shift_Left (159, 16) or 8,
173 Secondary => Shift_Left (319, 16) or 168,
174 Tertiary => Shift_Left (479, 16) or 328);
Nico Huber83693c82016-10-08 22:17:55 +0200175 begin
176 Registers.Write
177 (Register => Controller.PLANE_BUF_CFG,
Nico Huber4dc4c612018-01-10 15:55:09 +0100178 Value => Plane_Buffer_Range (Controller.Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200179 Registers.Write
180 (Register => Controller.PLANE_WM (0),
181 Value => PLANE_WM_ENABLE or
182 PLANE_WM_LINES (2) or
Nico Huber4dc4c612018-01-10 15:55:09 +0100183 PLANE_WM_BLOCKS (152));
184 Registers.Write
185 (Register => Controller.CUR_BUF_CFG,
186 Value => Cur_Buffer_Range (Controller.Pipe));
187 Registers.Write
188 (Register => Controller.CUR_WM (0),
189 Value => PLANE_WM_ENABLE or
190 PLANE_WM_LINES (2) or
191 PLANE_WM_BLOCKS (8));
Nico Huber83693c82016-10-08 22:17:55 +0200192 end Setup_Watermarks;
193
194 ----------------------------------------------------------------------------
195
Nico Huber3675db52016-11-04 16:27:29 +0100196 procedure Setup_Hires_Plane
Nico Huber6a4dfc82016-11-04 15:50:58 +0100197 (Controller : Controller_Type;
Nico Huber0164b022017-08-24 15:12:51 +0200198 FB : HW.GFX.Framebuffer_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200199 with
200 Global => (In_Out => Registers.Register_State),
201 Depends =>
202 (Registers.Register_State
203 =>+
204 (Registers.Register_State,
205 Controller,
Nico Huber9b479412017-08-27 11:55:56 +0200206 FB)),
Nico Huber5ef4d602017-12-13 13:56:47 +0100207 Pre => FB.Height + FB.Start_Y <= FB.V_Stride
Nico Huber83693c82016-10-08 22:17:55 +0200208 is
209 -- FIXME: setup correct format, based on framebuffer RGB format
210 Format : constant Word32 := 6 * 2 ** 26;
211 PRI : Word32 := DSPCNTR_ENABLE or Format;
Nico Huber83693c82016-10-08 22:17:55 +0200212 begin
213 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
214
Nico Huber83693c82016-10-08 22:17:55 +0200215 if Config.Has_Plane_Control then
Nico Huber9b479412017-08-27 11:55:56 +0200216 declare
Nico Huber34be6542017-12-13 09:26:24 +0100217 Stride, Offset : Word32;
Nico Huber9b479412017-08-27 11:55:56 +0200218 Width : constant Pos16 := Rotated_Width (FB);
219 Height : constant Pos16 := Rotated_Height (FB);
220 begin
221 if Rotation_90 (FB) then
Nico Huber5ef4d602017-12-13 13:56:47 +0100222 Stride := Word32 (FB_Pitch (FB.V_Stride, FB));
223 Offset := Shift_Left (Word32 (FB.Start_X), 16) or
224 Word32 (FB.V_Stride - FB.Height - FB.Start_Y);
Nico Huber9b479412017-08-27 11:55:56 +0200225 else
Nico Huber5ef4d602017-12-13 13:56:47 +0100226 Stride := Word32 (FB_Pitch (FB.Stride, FB));
227 Offset := Shift_Left (Word32 (FB.Start_Y), 16) or
228 Word32 (FB.Start_X);
Nico Huber9b479412017-08-27 11:55:56 +0200229 end if;
230 Registers.Write
231 (Register => Controller.PLANE_CTL,
232 Value => PLANE_CTL_PLANE_ENABLE or
233 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
234 PLANE_CTL_PLANE_GAMMA_DISABLE or
235 PLANE_CTL_TILED_SURFACE (FB.Tiling) or
236 PLANE_CTL_PLANE_ROTATION (FB.Rotation));
237 Registers.Write (Controller.PLANE_OFFSET, Offset);
238 Registers.Write (Controller.PLANE_SIZE, Encode (Width, Height));
239 Registers.Write (Controller.PLANE_STRIDE, Stride);
240 Registers.Write (Controller.PLANE_POS, 16#0000_0000#);
Nico Huber34be6542017-12-13 09:26:24 +0100241 Registers.Write (Controller.PLANE_SURF, FB.Offset and 16#ffff_f000#);
Nico Huber9b479412017-08-27 11:55:56 +0200242 end;
Nico Huber83693c82016-10-08 22:17:55 +0200243 else
244 if Config.Disable_Trickle_Feed then
245 PRI := PRI or DSPCNTR_DISABLE_TRICKLE_FEED;
246 end if;
247 -- for now, just disable gamma LUT (can't do anything
248 -- useful without colorimetry information from display)
249 Registers.Unset_And_Set_Mask
250 (Register => Controller.DSPCNTR,
251 Mask_Unset => DSPCNTR_MASK,
Nico Huberab69e362018-05-29 21:20:30 +0200252 Mask_Set => PRI or DSPCNTR_TILED_SURFACE (FB.Tiling));
Nico Huber83693c82016-10-08 22:17:55 +0200253
Nico Huber0164b022017-08-24 15:12:51 +0200254 Registers.Write
255 (Controller.DSPSTRIDE, Word32 (Pixel_To_Bytes (FB.Stride, FB)));
Nico Huberab69e362018-05-29 21:20:30 +0200256 if Config.Has_DSP_Linoff and then FB.Tiling = Linear then
Nico Huber5ef4d602017-12-13 13:56:47 +0100257 Registers.Write
258 (Register => Controller.DSPLINOFF,
259 Value => Word32 (Pixel_To_Bytes
260 (FB.Start_Y * FB.Stride + FB.Start_X, FB)));
261 Registers.Write (Controller.DSPTILEOFF, 0);
262 else
Nico Huberab69e362018-05-29 21:20:30 +0200263 if Config.Has_DSP_Linoff then
264 Registers.Write (Controller.DSPLINOFF, 0);
265 end if;
Nico Huber5ef4d602017-12-13 13:56:47 +0100266 Registers.Write
267 (Register => Controller.DSPTILEOFF,
268 Value => Shift_Left (Word32 (FB.Start_Y), 16) or
269 Word32 (FB.Start_X));
Nico Huber83693c82016-10-08 22:17:55 +0200270 end if;
Nico Huber8fd92a12018-01-02 14:02:59 +0100271 Registers.Write (Controller.DSPSURF, FB.Offset and 16#ffff_f000#);
Nico Huber83693c82016-10-08 22:17:55 +0200272 end if;
Nico Huber3675db52016-11-04 16:27:29 +0100273 end Setup_Hires_Plane;
274
275 procedure Setup_Display
Nico Huber113a14b2016-12-06 21:59:15 +0100276 (Controller : Controller_Type;
277 Framebuffer : Framebuffer_Type;
278 Dither_BPC : BPC_Type;
279 Dither : Boolean)
Nico Huber3675db52016-11-04 16:27:29 +0100280 with
281 Global => (In_Out => (Registers.Register_State, Port_IO.State)),
282 Depends =>
283 (Registers.Register_State
284 =>+
285 (Registers.Register_State,
286 Controller,
Nico Huber113a14b2016-12-06 21:59:15 +0100287 Framebuffer,
288 Dither_BPC,
289 Dither),
Nico Huber3675db52016-11-04 16:27:29 +0100290 Port_IO.State
291 =>+
Nico Huber9b479412017-08-27 11:55:56 +0200292 (Framebuffer)),
293 Pre =>
294 Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
Nico Huber5ef4d602017-12-13 13:56:47 +0100295 Framebuffer.Height + Framebuffer.Start_Y <= Framebuffer.V_Stride
Nico Huber3675db52016-11-04 16:27:29 +0100296 is
297 use type Word8;
298
299 Reg8 : Word8;
300 begin
301 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
302
303 if Config.Has_Plane_Control then
304 Setup_Watermarks (Controller);
305 end if;
306
307 if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
Nico Huberfbb42202016-11-07 15:08:26 +0100308 if Config.VGA_Plane_Workaround then
309 Registers.Unset_And_Set_Mask
310 (Register => Registers.ILK_DISPLAY_CHICKEN1,
311 Mask_Unset => ILK_DISPLAY_CHICKEN1_VGA_MASK,
312 Mask_Set => ILK_DISPLAY_CHICKEN1_VGA_ENABLE);
313 Registers.Unset_And_Set_Mask
314 (Register => Registers.ILK_DISPLAY_CHICKEN2,
315 Mask_Unset => ILK_DISPLAY_CHICKEN2_VGA_MASK,
316 Mask_Set => ILK_DISPLAY_CHICKEN2_VGA_ENABLE);
317 end if;
318
Nico Huber3675db52016-11-04 16:27:29 +0100319 Registers.Unset_And_Set_Mask
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200320 (Register => VGACNTRL_REG,
Nico Huber3675db52016-11-04 16:27:29 +0100321 Mask_Unset => VGA_CONTROL_VGA_DISPLAY_DISABLE or
322 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK or
323 VGA_CONTROL_VSYNC_BLINK_RATE_MASK,
324 Mask_Set => VGA_CONTROL_BLINK_DUTY_CYCLE_50 or
325 VGA_CONTROL_VSYNC_BLINK_RATE (30));
326
327 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
328 Port_IO.InB (Reg8, VGA_SR_DATA);
329 Port_IO.OutB (VGA_SR_DATA, Reg8 and not (VGA_SR01_SCREEN_OFF));
330 else
Nico Huber6a4dfc82016-11-04 15:50:58 +0100331 Setup_Hires_Plane (Controller, Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100332 end if;
333
334 Registers.Write
335 (Register => Controller.PIPESRC,
336 Value => Encode
Nico Huber9b479412017-08-27 11:55:56 +0200337 (Rotated_Height (Framebuffer), Rotated_Width (Framebuffer)));
Nico Huber83693c82016-10-08 22:17:55 +0200338
Nico Huber113a14b2016-12-06 21:59:15 +0100339 if Config.Has_Pipeconf_Misc then
340 Registers.Write
341 (Register => Controller.PIPEMISC,
Nico Huber7ad2d652016-12-07 15:19:32 +0100342 Value => Transcoder.BPC_Conf (Dither_BPC, Dither));
Nico Huber113a14b2016-12-06 21:59:15 +0100343 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200344 end Setup_Display;
345
346 ----------------------------------------------------------------------------
347
Nico Huber4dc4c612018-01-10 15:55:09 +0100348 procedure Update_Cursor
349 (Pipe : Pipe_Index;
350 FB : Framebuffer_Type;
351 Cursor : Cursor_Type)
352 is
353 begin
354 -- on some platforms writing CUR_CTL disables self-arming of CUR_POS
355 -- so keep it first
356 Registers.Write
357 (Register => Controllers (Pipe).CUR_CTL,
358 Value => CUR_CTL_PIPE_SELECT (Pipe) or
359 CUR_CTL_MODE (Cursor.Mode, Cursor.Size));
360 Place_Cursor (Pipe, FB, Cursor);
361 end Update_Cursor;
362
363 procedure Place_Cursor
364 (Pipe : Pipe_Index;
365 FB : Framebuffer_Type;
366 Cursor : Cursor_Type)
367 is
368 Width : constant Width_Type := Cursor_Width (Cursor.Size);
369 X : Int32 := Cursor.Center_X - Width / 2;
370 Y : Int32 := Cursor.Center_Y - Width / 2;
371 begin
372 -- off-screen cursor needs special care
373 if X <= -Width or Y <= -Width or
374 X >= Int32 (Rotated_Width (FB)) or Y >= Int32 (Rotated_Height (FB)) or
375 X > Config.Maximum_Cursor_X or Y > Config.Maximum_Cursor_Y
376 then
377 X := -Width;
378 Y := -Width;
379 end if;
380 Registers.Write
381 (Register => Controllers (Pipe).CUR_POS,
382 Value => CUR_POS_Y (Y) or CUR_POS_X (X));
383 -- write to CUR_BASE always arms other CUR_* registers
384 Registers.Write
385 (Register => Controllers (Pipe).CUR_BASE,
386 Value => Shift_Left (Word32 (Cursor.GTT_Offset), 12));
387 end Place_Cursor;
388
389 ----------------------------------------------------------------------------
390
Nico Huber4916e342016-11-04 14:37:53 +0100391 procedure Scale_Keep_Aspect
392 (Width : out Pos32;
393 Height : out Pos32;
394 Max_Width : in Pos32;
395 Max_Height : in Pos32;
396 Framebuffer : in Framebuffer_Type)
397 with
398 Pre =>
399 Max_Width <= Pos32 (Pos16'Last) and
400 Max_Height <= Pos32 (Pos16'Last) and
Nico Huber9b479412017-08-27 11:55:56 +0200401 Pos32 (Rotated_Width (Framebuffer)) <= Max_Width and
402 Pos32 (Rotated_Height (Framebuffer)) <= Max_Height,
Nico Huber4916e342016-11-04 14:37:53 +0100403 Post =>
404 Width <= Max_Width and Height <= Max_Height
405 is
Nico Huber9b479412017-08-27 11:55:56 +0200406 Src_Width : constant Pos32 := Pos32 (Rotated_Width (Framebuffer));
407 Src_Height : constant Pos32 := Pos32 (Rotated_Height (Framebuffer));
Nico Huber4916e342016-11-04 14:37:53 +0100408 begin
Nico Huber9b479412017-08-27 11:55:56 +0200409 if (Max_Width * Src_Height) / Src_Width <= Max_Height then
Nico Huber4916e342016-11-04 14:37:53 +0100410 Width := Max_Width;
Nico Huber9b479412017-08-27 11:55:56 +0200411 Height := (Max_Width * Src_Height) / Src_Width;
Nico Huber4916e342016-11-04 14:37:53 +0100412 else
413 Height := Max_Height;
414 Width := Pos32'Min (Max_Width, -- could prove, it's <= Max_Width
Nico Huber9b479412017-08-27 11:55:56 +0200415 (Max_Height * Src_Width) / Src_Height);
Nico Huber4916e342016-11-04 14:37:53 +0100416 end if;
417 end Scale_Keep_Aspect;
418
419 procedure Setup_Skylake_Pipe_Scaler
420 (Controller : in Controller_Type;
421 Mode : in HW.GFX.Mode_Type;
422 Framebuffer : in HW.GFX.Framebuffer_Type)
423 with
424 Pre =>
Nico Huber9b479412017-08-27 11:55:56 +0200425 Rotated_Width (Framebuffer) <= Mode.H_Visible and
426 Rotated_Height (Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100427 is
Nico Huber7ad2d652016-12-07 15:19:32 +0100428 use type Registers.Registers_Invalid_Index;
429
Nico Huber4916e342016-11-04 14:37:53 +0100430 -- Enable 7x5 extended mode where possible:
431 Scaler_Mode : constant Word32 :=
432 (if Controller.PS_CTRL_2 /= Registers.Invalid_Register then
433 PS_CTRL_SCALER_MODE_7X5_EXTENDED else 0);
434
Nico Huber9b479412017-08-27 11:55:56 +0200435 Width_In : constant Pos32 := Pos32 (Rotated_Width (Framebuffer));
436 Height_In : constant Pos32 := Pos32 (Rotated_Height (Framebuffer));
437
Nico Huber4916e342016-11-04 14:37:53 +0100438 -- We can scale up to 2.99x horizontally:
Nico Huber9b479412017-08-27 11:55:56 +0200439 Horizontal_Limit : constant Pos32 := (Width_In * 299) / 100;
Nico Huber4916e342016-11-04 14:37:53 +0100440 -- The third scaler is limited to 1.99x
441 -- vertical scaling for source widths > 2048:
442 Vertical_Limit : constant Pos32 :=
Nico Huber9b479412017-08-27 11:55:56 +0200443 (Height_In *
Nico Huber4916e342016-11-04 14:37:53 +0100444 (if Controller.PS_CTRL_2 = Registers.Invalid_Register and
Nico Huber9b479412017-08-27 11:55:56 +0200445 Width_In > 2048
Nico Huber4916e342016-11-04 14:37:53 +0100446 then
447 199
448 else
449 299)) / 100;
450
451 Width, Height : Pos32;
452 begin
453 -- Writes to WIN_SZ arm the PS registers.
454
455 Scale_Keep_Aspect
456 (Width => Width,
457 Height => Height,
458 Max_Width => Pos32'Min (Horizontal_Limit, Pos32 (Mode.H_Visible)),
459 Max_Height => Pos32'Min (Vertical_Limit, Pos32 (Mode.V_Visible)),
460 Framebuffer => Framebuffer);
461
462 Registers.Write
463 (Register => Controller.PS_CTRL_1,
464 Value => PS_CTRL_ENABLE_SCALER or Scaler_Mode);
465 Registers.Write
466 (Register => Controller.PS_WIN_POS_1,
467 Value =>
468 Shift_Left (Word32 (Pos32 (Mode.H_Visible) - Width) / 2, 16) or
469 Word32 (Pos32 (Mode.V_Visible) - Height) / 2);
470 Registers.Write
471 (Register => Controller.PS_WIN_SZ_1,
472 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
473 end Setup_Skylake_Pipe_Scaler;
474
475 procedure Setup_Ironlake_Panel_Fitter
476 (Controller : in Controller_Type;
477 Mode : in HW.GFX.Mode_Type;
478 Framebuffer : in HW.GFX.Framebuffer_Type)
479 with
480 Pre =>
Nico Huber9b479412017-08-27 11:55:56 +0200481 Rotated_Width (Framebuffer) <= Mode.H_Visible and
482 Rotated_Height (Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100483 is
484 -- Force 1:1 mapping of panel fitter:pipe
485 PF_Ctrl_Pipe_Sel : constant Word32 :=
486 (if Config.Has_PF_Pipe_Select then
487 (case Controller.PF_CTRL is
488 when Registers.PFA_CTL_1 => 0 * 2 ** 29,
489 when Registers.PFB_CTL_1 => 1 * 2 ** 29,
490 when Registers.PFC_CTL_1 => 2 * 2 ** 29,
491 when others => 0) else 0);
492
493 Width, Height : Pos32;
Nico Huberfdb0df12018-02-07 14:30:34 +0100494 X, Y : Int32;
Nico Huber4916e342016-11-04 14:37:53 +0100495 begin
496 -- Writes to WIN_SZ arm the PF registers.
497
498 Scale_Keep_Aspect
499 (Width => Width,
500 Height => Height,
501 Max_Width => Pos32 (Mode.H_Visible),
502 Max_Height => Pos32 (Mode.V_Visible),
503 Framebuffer => Framebuffer);
504
Nico Huberfdb0df12018-02-07 14:30:34 +0100505 -- Do not scale to odd width (at least Haswell has trouble with this).
506 if Width < Pos32 (Mode.H_Visible) and Width mod 2 = 1 then
507 Width := Width + 1;
508 end if;
509
510 X := (Int32 (Mode.H_Visible) - Width) / 2;
511 Y := (Int32 (Mode.V_Visible) - Height) / 2;
512
513 -- Hardware is picky about minimal horizontal gaps.
514 if Pos32 (Mode.H_Visible) - Width <= 3 then
515 Width := Pos32(Mode.H_Visible);
516 X := 0;
517 end if;
518
Nico Huber4916e342016-11-04 14:37:53 +0100519 Registers.Write
520 (Register => Controller.PF_CTRL,
521 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_CTRL_FILTER_MED);
522 Registers.Write
523 (Register => Controller.PF_WIN_POS,
Nico Huberfdb0df12018-02-07 14:30:34 +0100524 Value => Shift_Left (Word32 (X), 16) or Word32 (Y));
Nico Huber4916e342016-11-04 14:37:53 +0100525 Registers.Write
526 (Register => Controller.PF_WIN_SZ,
527 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
528 end Setup_Ironlake_Panel_Fitter;
529
Arthur Heymansd5198442018-03-28 17:05:12 +0200530 -- TODO the panel fitter can only be set for one pipe
531 -- If this causes problems:
532 -- Check in Enable_Output if panel fitter has already been enabled
533 -- Pass this information to Validate_Config
534 procedure Setup_Gmch_Panel_Fitter
535 (Controller : in Controller_Type)
536 is
537 PF_Ctrl_Pipe_Sel : constant Word32 :=
538 (case Controller.Pipe is
539 when Primary => GMCH_PFIT_CONTROL_SELECT_PIPE_A,
540 when Secondary => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
541 when others => 0);
542 In_Use : Boolean;
543 begin
544 Registers.Is_Set_Mask
545 (Register => Registers.GMCH_PFIT_CONTROL,
546 Mask => PF_CTRL_ENABLE,
547 Result => In_Use);
548
549 if not In_Use then
550 Registers.Write
551 (Register => Registers.GMCH_PFIT_CONTROL,
552 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel);
553 else
554 Debug.Put_Line ("GMCH Pannel fitter already in use, skipping...");
555 end if;
556 end Setup_Gmch_Panel_Fitter;
557
Nico Huberb4b72792018-01-02 13:45:41 +0100558 procedure Panel_Fitter_Off (Controller : Controller_Type)
559 is
560 use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
Arthur Heymansd5198442018-03-28 17:05:12 +0200561 Used_For_Secondary : Boolean;
Nico Huberb4b72792018-01-02 13:45:41 +0100562 begin
563 -- Writes to WIN_SZ arm the PS/PF registers.
564 if Config.Has_Plane_Control then
565 Registers.Unset_Mask (Controller.PS_CTRL_1, PS_CTRL_ENABLE_SCALER);
566 Registers.Write (Controller.PS_WIN_SZ_1, 16#0000_0000#);
567 if Controller.PS_CTRL_2 /= Registers.Invalid_Register and
568 Controller.PS_WIN_SZ_2 /= Registers.Invalid_Register
569 then
570 Registers.Unset_Mask (Controller.PS_CTRL_2, PS_CTRL_ENABLE_SCALER);
571 Registers.Write (Controller.PS_WIN_SZ_2, 16#0000_0000#);
572 end if;
Arthur Heymansd5198442018-03-28 17:05:12 +0200573 elsif Config.Has_GMCH_PFIT_CONTROL then
574 Registers.Is_Set_Mask
575 (Register => Registers.GMCH_PFIT_CONTROL,
576 Mask => GMCH_PFIT_CONTROL_SELECT_PIPE_B,
577 Result => Used_For_Secondary);
578 if (Controller.Pipe = Primary and not Used_For_Secondary) or
579 (Controller.Pipe = Secondary and Used_For_Secondary)
580 then
581 Registers.Unset_Mask
582 (Register => Registers.GMCH_PFIT_CONTROL,
583 Mask => PF_CTRL_ENABLE);
584 end if;
Nico Huberb4b72792018-01-02 13:45:41 +0100585 else
586 Registers.Unset_Mask (Controller.PF_CTRL, PF_CTRL_ENABLE);
587 Registers.Write (Controller.PF_WIN_SZ, 16#0000_0000#);
588 end if;
589 end Panel_Fitter_Off;
590
Nico Huber4916e342016-11-04 14:37:53 +0100591 procedure Setup_Scaling
592 (Controller : in Controller_Type;
593 Mode : in HW.GFX.Mode_Type;
594 Framebuffer : in HW.GFX.Framebuffer_Type)
595 with
596 Pre =>
Nico Huber9b479412017-08-27 11:55:56 +0200597 Rotated_Width (Framebuffer) <= Mode.H_Visible and
598 Rotated_Height (Framebuffer) <= Mode.V_Visible
Nico Huber4916e342016-11-04 14:37:53 +0100599 is
600 begin
Nico Huber3d06de82018-05-29 01:35:04 +0200601 if Requires_Scaling (Framebuffer, Mode) then
Nico Huber4916e342016-11-04 14:37:53 +0100602 if Config.Has_Plane_Control then
603 Setup_Skylake_Pipe_Scaler (Controller, Mode, Framebuffer);
Arthur Heymansd5198442018-03-28 17:05:12 +0200604 elsif Config.Has_GMCH_PFIT_CONTROL then
605 Setup_Gmch_Panel_Fitter (Controller);
Nico Huber4916e342016-11-04 14:37:53 +0100606 else
607 Setup_Ironlake_Panel_Fitter (Controller, Mode, Framebuffer);
608 end if;
Nico Huberb4b72792018-01-02 13:45:41 +0100609 else
610 Panel_Fitter_Off (Controller);
Nico Huber4916e342016-11-04 14:37:53 +0100611 end if;
612 end Setup_Scaling;
613
614 ----------------------------------------------------------------------------
615
Nico Huberf7f537e2018-01-02 14:15:43 +0100616 procedure Setup_FB
617 (Pipe : Pipe_Index;
618 Mode : Mode_Type;
619 Framebuffer : Framebuffer_Type)
620 is
621 -- Enable dithering if framebuffer BPC differs from port BPC,
622 -- as smooth gradients look really bad without.
623 Dither : constant Boolean := Framebuffer.BPC /= Mode.BPC;
624 begin
625 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
626
Nico Huber4dc4c612018-01-10 15:55:09 +0100627 -- Disable the cursor first.
628 Update_Cursor (Pipe, Framebuffer, Default_Cursor);
629
Nico Huberf7f537e2018-01-02 14:15:43 +0100630 Setup_Display (Controllers (Pipe), Framebuffer, Mode.BPC, Dither);
631 Setup_Scaling (Controllers (Pipe), Mode, Framebuffer);
632 end Setup_FB;
633
Nico Huber83693c82016-10-08 22:17:55 +0200634 procedure On
Nico Huberf3e23662016-12-05 21:33:03 +0100635 (Pipe : Pipe_Index;
Nico Huber83693c82016-10-08 22:17:55 +0200636 Port_Cfg : Port_Config;
Nico Huber4dc4c612018-01-10 15:55:09 +0100637 Framebuffer : Framebuffer_Type;
638 Cursor : Cursor_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200639 is
640 begin
641 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
642
Nico Huber7ad2d652016-12-07 15:19:32 +0100643 Transcoder.Setup (Pipe, Port_Cfg);
Nico Huber83693c82016-10-08 22:17:55 +0200644
Nico Huberf7f537e2018-01-02 14:15:43 +0100645 Setup_FB (Pipe, Port_Cfg.Mode, Framebuffer);
Nico Huber4dc4c612018-01-10 15:55:09 +0100646 Update_Cursor (Pipe, Framebuffer, Cursor);
Nico Huber83693c82016-10-08 22:17:55 +0200647
Nico Huberabb16d92018-05-29 01:44:26 +0200648 Transcoder.On
649 (Pipe => Pipe,
650 Port_Cfg => Port_Cfg,
651 Dither => Framebuffer.BPC /= Port_Cfg.Mode.BPC,
652 Scale => Requires_Scaling (Framebuffer, Port_Cfg.Mode));
Nico Huber83693c82016-10-08 22:17:55 +0200653 end On;
654
655 ----------------------------------------------------------------------------
656
657 procedure Planes_Off (Controller : Controller_Type) is
658 begin
Nico Huber4dc4c612018-01-10 15:55:09 +0100659 Registers.Write (Controller.CUR_CTL, 16#0000_0000#);
660 if Config.Has_Cursor_FBC_Control then
661 Registers.Write (Controller.CUR_FBC_CTL, 16#0000_0000#);
662 end if;
Nico Huber7ad2d652016-12-07 15:19:32 +0100663 Registers.Unset_Mask (Controller.SPCNTR, DSPCNTR_ENABLE);
Nico Huber83693c82016-10-08 22:17:55 +0200664 if Config.Has_Plane_Control then
665 Clear_Watermarks (Controller);
666 Registers.Unset_Mask (Controller.PLANE_CTL, PLANE_CTL_PLANE_ENABLE);
667 Registers.Write (Controller.PLANE_SURF, 16#0000_0000#);
668 else
669 Registers.Unset_Mask (Controller.DSPCNTR, DSPCNTR_ENABLE);
670 end if;
671 end Planes_Off;
672
Nico Huber7ad2d652016-12-07 15:19:32 +0100673 procedure Off (Pipe : Pipe_Index)
Nico Huberf3e23662016-12-05 21:33:03 +0100674 is
Nico Huber83693c82016-10-08 22:17:55 +0200675 begin
676 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
677
Nico Huberf3e23662016-12-05 21:33:03 +0100678 Planes_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100679 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +0100680 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100681 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +0200682 end Off;
683
Nico Huber33912aa2016-12-06 20:36:23 +0100684 procedure Legacy_VGA_Off
685 is
686 use type HW.Word8;
687 Reg8 : Word8;
688 begin
689 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
690 Port_IO.InB (Reg8, VGA_SR_DATA);
691 Port_IO.OutB (VGA_SR_DATA, Reg8 or VGA_SR01_SCREEN_OFF);
692 Time.U_Delay (100); -- PRM says 100us, Linux does 300
Arthur Heymansdfcdd772018-03-28 16:42:50 +0200693 Registers.Set_Mask (VGACNTRL_REG, VGA_CONTROL_VGA_DISPLAY_DISABLE);
Nico Huber33912aa2016-12-06 20:36:23 +0100694 end Legacy_VGA_Off;
695
Nico Huber83693c82016-10-08 22:17:55 +0200696 procedure All_Off
697 is
Nico Huber83693c82016-10-08 22:17:55 +0200698 begin
699 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
700
Nico Huber33912aa2016-12-06 20:36:23 +0100701 Legacy_VGA_Off;
702
Nico Huberf3e23662016-12-05 21:33:03 +0100703 for Pipe in Pipe_Index loop
704 Planes_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100705 Transcoder.Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +0100706 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100707 Transcoder.Clk_Off (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +0200708 end loop;
Nico Huber83693c82016-10-08 22:17:55 +0200709 end All_Off;
710
Nico Huber83693c82016-10-08 22:17:55 +0200711end HW.GFX.GMA.Pipe_Setup;