blob: 6293f206e68c30bbbac4f2c60d57b2c60d92f331 [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
2-- Copyright (C) 2015-2016 secunet Security Networks AG
3--
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;
19with HW.GFX.GMA.DP_Info;
20with HW.GFX.GMA.Registers;
21
22use type HW.Word64;
23use type HW.Pos16;
Nico Huber83693c82016-10-08 22:17:55 +020024use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
25
26package body HW.GFX.GMA.Pipe_Setup is
27
Nico Huberf3e23662016-12-05 21:33:03 +010028 type Default_Head_Array is array (Pipe_Index) of Pipe_Head;
29 Default_Pipe_Head : constant Default_Head_Array :=
30 (Primary => Head_A,
31 Secondary => Head_B,
32 Tertiary => Head_C);
33
34 function Get_Pipe_Head (Pipe : Pipe_Index; Port : GPU_Port) return Pipe_Head
35 is
36 begin
37 return
38 (if Config.Has_EDP_Pipe and then Port = DIGI_A then
39 Head_EDP
40 else
41 Default_Pipe_Head (Pipe));
42 end Get_Pipe_Head;
43
44 ----------------------------------------------------------------------------
45
Nico Huberfbb42202016-11-07 15:08:26 +010046 ILK_DISPLAY_CHICKEN1_VGA_MASK : constant := 7 * 2 ** 29;
47 ILK_DISPLAY_CHICKEN1_VGA_ENABLE : constant := 5 * 2 ** 29;
48 ILK_DISPLAY_CHICKEN2_VGA_MASK : constant := 1 * 2 ** 25;
49 ILK_DISPLAY_CHICKEN2_VGA_ENABLE : constant := 0 * 2 ** 25;
50
Nico Huber83693c82016-10-08 22:17:55 +020051 DSPCNTR_ENABLE : constant := 1 * 2 ** 31;
52 DSPCNTR_GAMMA_CORRECTION : constant := 1 * 2 ** 30;
53 DSPCNTR_DISABLE_TRICKLE_FEED : constant := 1 * 2 ** 14;
54 DSPCNTR_FORMAT_MASK : constant := 15 * 2 ** 26;
55
56 DSPCNTR_MASK : constant Word32 :=
57 DSPCNTR_ENABLE or
58 DSPCNTR_GAMMA_CORRECTION or
59 DSPCNTR_FORMAT_MASK or
60 DSPCNTR_DISABLE_TRICKLE_FEED;
61
62 PLANE_CTL_PLANE_ENABLE : constant := 1 * 2 ** 31;
63 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 : constant := 4 * 2 ** 24;
64 PLANE_CTL_PLANE_GAMMA_DISABLE : constant := 1 * 2 ** 13;
65
66 PLANE_WM_ENABLE : constant := 1 * 2 ** 31;
67 PLANE_WM_LINES_SHIFT : constant := 14;
68 PLANE_WM_LINES_MASK : constant := 16#001f# * 2 ** 14;
69 PLANE_WM_BLOCKS_MASK : constant := 16#03ff# * 2 ** 0;
70
71 SPCNTR_ENABLE : constant := 1 * 2 ** 31;
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
83 subtype VGA_Cycle_Count is Pos32 range 2 .. 128;
84 function VGA_CONTROL_VSYNC_BLINK_RATE
85 (Cycles : VGA_Cycle_Count)
86 return Word32
87 is
88 begin
89 return Word32 (Cycles) / 2 - 1;
90 end VGA_CONTROL_VSYNC_BLINK_RATE;
91
Nico Huber83693c82016-10-08 22:17:55 +020092 TRANS_CLK_SEL_PORT_NONE : constant := 0 * 2 ** 29;
93
94 type TRANS_CLK_SEL_PORT_Array is
95 array (Digital_Port) of Word32;
96 TRANS_CLK_SEL_PORT : constant TRANS_CLK_SEL_PORT_Array :=
97 TRANS_CLK_SEL_PORT_Array'
98 (DIGI_A => 0 * 2 ** 29, -- DDI A is not selectable
99 DIGI_B => 2 * 2 ** 29,
100 DIGI_C => 3 * 2 ** 29,
101 DIGI_D => 4 * 2 ** 29,
102 DIGI_E => 5 * 2 ** 29);
103
104 PIPECONF_ENABLE : constant := 1 * 2 ** 31;
105 PIPECONF_ENABLED_STATUS : constant := 1 * 2 ** 30;
106 PIPECONF_ENABLE_DITHER : constant := 1 * 2 ** 4;
107 PIPECONF_DITHER_TEMPORAL : constant := 1 * 2 ** 2;
108
Nico Huber4916e342016-11-04 14:37:53 +0100109 PF_CTRL_ENABLE : constant := 1 * 2 ** 31;
110 PF_CTRL_PIPE_SELECT_MASK : constant := 3 * 2 ** 29;
111 PF_CTRL_FILTER_MED : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200112
Nico Huber4916e342016-11-04 14:37:53 +0100113 PS_CTRL_ENABLE_SCALER : constant := 1 * 2 ** 31;
114 PS_CTRL_SCALER_MODE_7X5_EXTENDED : constant := 1 * 2 ** 28;
115 PS_CTRL_FILTER_SELECT_MEDIUM_2 : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200116
117 PIPE_DDI_FUNC_CTL_ENABLE : constant := 1 * 2 ** 31;
118 PIPE_DDI_FUNC_CTL_DDI_SELECT_MASK : constant := 7 * 2 ** 28;
119 PIPE_DDI_FUNC_CTL_DDI_SELECT_NONE : constant := 0 * 2 ** 28;
120 PIPE_DDI_FUNC_CTL_DDI_SELECT_B : constant := 1 * 2 ** 28;
121 PIPE_DDI_FUNC_CTL_DDI_SELECT_C : constant := 2 * 2 ** 28;
122 PIPE_DDI_FUNC_CTL_DDI_SELECT_D : constant := 3 * 2 ** 28;
123 PIPE_DDI_FUNC_CTL_DDI_SELECT_E : constant := 4 * 2 ** 28;
124 PIPE_DDI_FUNC_CTL_MODE_SELECT_MASK : constant := 7 * 2 ** 24;
125 PIPE_DDI_FUNC_CTL_MODE_SELECT_HDMI : constant := 0 * 2 ** 24;
126 PIPE_DDI_FUNC_CTL_MODE_SELECT_DVI : constant := 1 * 2 ** 24;
127 PIPE_DDI_FUNC_CTL_MODE_SELECT_DP_SST : constant := 2 * 2 ** 24;
128 PIPE_DDI_FUNC_CTL_MODE_SELECT_DP_MST : constant := 3 * 2 ** 24;
129 PIPE_DDI_FUNC_CTL_MODE_SELECT_FDI : constant := 4 * 2 ** 24;
130 PIPE_DDI_FUNC_CTL_BPC_MASK : constant := 7 * 2 ** 20;
131 PIPE_DDI_FUNC_CTL_BPC_8BITS : constant := 0 * 2 ** 20;
132 PIPE_DDI_FUNC_CTL_BPC_10BITS : constant := 1 * 2 ** 20;
133 PIPE_DDI_FUNC_CTL_BPC_6BITS : constant := 2 * 2 ** 20;
134 PIPE_DDI_FUNC_CTL_BPC_12BITS : constant := 3 * 2 ** 20;
135 PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_LOW : constant := 0 * 2 ** 17;
136 PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 17;
137 PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_LOW : constant := 0 * 2 ** 16;
138 PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 16;
139 PIPE_DDI_FUNC_CTL_EDP_SELECT_MASK : constant := 7 * 2 ** 12;
140 PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON : constant := 0 * 2 ** 12;
141 PIPE_DDI_FUNC_CTL_EDP_SELECT_A : constant := 4 * 2 ** 12;
142 PIPE_DDI_FUNC_CTL_EDP_SELECT_B : constant := 5 * 2 ** 12;
143 PIPE_DDI_FUNC_CTL_EDP_SELECT_C : constant := 6 * 2 ** 12;
144 PIPE_DDI_FUNC_CTL_DP_VC_PAYLOAD_ALLOC : constant := 1 * 2 ** 8;
145 PIPE_DDI_FUNC_CTL_BFI_ENABLE : constant := 1 * 2 ** 4;
146 PIPE_DDI_FUNC_CTL_PORT_WIDTH_MASK : constant := 7 * 2 ** 1;
147 PIPE_DDI_FUNC_CTL_PORT_WIDTH_1_LANE : constant := 0 * 2 ** 1;
148 PIPE_DDI_FUNC_CTL_PORT_WIDTH_2_LANES : constant := 1 * 2 ** 1;
149 PIPE_DDI_FUNC_CTL_PORT_WIDTH_4_LANES : constant := 3 * 2 ** 1;
150
151 type DDI_Select_Array is array (Digital_Port) of Word32;
152 PIPE_DDI_FUNC_CTL_DDI_SELECT : constant DDI_Select_Array :=
153 DDI_Select_Array'
154 (DIGI_A => PIPE_DDI_FUNC_CTL_DDI_SELECT_NONE,
155 DIGI_B => PIPE_DDI_FUNC_CTL_DDI_SELECT_B,
156 DIGI_C => PIPE_DDI_FUNC_CTL_DDI_SELECT_C,
157 DIGI_D => PIPE_DDI_FUNC_CTL_DDI_SELECT_D,
158 DIGI_E => PIPE_DDI_FUNC_CTL_DDI_SELECT_E);
159
160 type DDI_Mode_Array is array (Display_Type) of Word32;
161 PIPE_DDI_FUNC_CTL_MODE_SELECT : constant DDI_Mode_Array :=
162 DDI_Mode_Array'
163 (VGA => PIPE_DDI_FUNC_CTL_MODE_SELECT_FDI,
164 HDMI => PIPE_DDI_FUNC_CTL_MODE_SELECT_DVI,
165 DP => PIPE_DDI_FUNC_CTL_MODE_SELECT_DP_SST,
166 others => 0);
167
168 type HV_Sync_Array is array (Boolean) of Word32;
169 PIPE_DDI_FUNC_CTL_VSYNC : constant HV_Sync_Array := HV_Sync_Array'
170 (False => PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_LOW,
171 True => PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_HIGH);
172 PIPE_DDI_FUNC_CTL_HSYNC : constant HV_Sync_Array := HV_Sync_Array'
173 (False => PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_LOW,
174 True => PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_HIGH);
175
Nico Huberf3e23662016-12-05 21:33:03 +0100176 type EDP_Select_Array is array (Pipe_Index) of Word32;
Nico Huber83693c82016-10-08 22:17:55 +0200177 PIPE_DDI_FUNC_CTL_EDP_SELECT : constant EDP_Select_Array :=
Nico Huberf3e23662016-12-05 21:33:03 +0100178 (Primary => PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON, -- we never use
179 -- panel fitter
180 Secondary => PIPE_DDI_FUNC_CTL_EDP_SELECT_B,
181 Tertiary => PIPE_DDI_FUNC_CTL_EDP_SELECT_C);
Nico Huber83693c82016-10-08 22:17:55 +0200182 PIPE_DDI_FUNC_CTL_EDP_SELECT_ONOFF : constant EDP_Select_Array :=
Nico Huberf3e23662016-12-05 21:33:03 +0100183 (Primary => PIPE_DDI_FUNC_CTL_EDP_SELECT_A,
184 Secondary => PIPE_DDI_FUNC_CTL_EDP_SELECT_B,
185 Tertiary => PIPE_DDI_FUNC_CTL_EDP_SELECT_C);
Nico Huber83693c82016-10-08 22:17:55 +0200186
187 type Port_Width_Array is array (HW.GFX.DP_Lane_Count) of Word32;
188 PIPE_DDI_FUNC_CTL_PORT_WIDTH : constant Port_Width_Array :=
189 Port_Width_Array'
190 (HW.GFX.DP_Lane_Count_1 => PIPE_DDI_FUNC_CTL_PORT_WIDTH_1_LANE,
191 HW.GFX.DP_Lane_Count_2 => PIPE_DDI_FUNC_CTL_PORT_WIDTH_2_LANES,
192 HW.GFX.DP_Lane_Count_4 => PIPE_DDI_FUNC_CTL_PORT_WIDTH_4_LANES);
193
194 function PIPE_DDI_FUNC_CTL_BPC (BPC : HW.GFX.BPC_Type) return Word32
195 is
196 Result : Word32;
197 begin
198 case BPC is
199 when 6 => Result := PIPE_DDI_FUNC_CTL_BPC_6BITS;
200 when 8 => Result := PIPE_DDI_FUNC_CTL_BPC_8BITS;
201 when 10 => Result := PIPE_DDI_FUNC_CTL_BPC_10BITS;
202 when 12 => Result := PIPE_DDI_FUNC_CTL_BPC_12BITS;
203 when others => Result := PIPE_DDI_FUNC_CTL_BPC_8BITS;
204 end case;
205 return Result;
206 end PIPE_DDI_FUNC_CTL_BPC;
207
208 function PIPE_DATA_M_TU (Transfer_Unit : Positive) return Word32 is
209 begin
210 return Shift_Left (Word32 (Transfer_Unit - 1), 25);
211 end PIPE_DATA_M_TU;
212
213 PIPE_MSA_MISC_SYNC_CLK : constant := 1 * 2 ** 0;
214 PIPE_MSA_MISC_BPC_6BITS : constant := 0 * 2 ** 5;
215 PIPE_MSA_MISC_BPC_8BITS : constant := 1 * 2 ** 5;
216 PIPE_MSA_MISC_BPC_10BITS : constant := 2 * 2 ** 5;
217 PIPE_MSA_MISC_BPC_12BITS : constant := 3 * 2 ** 5;
218 PIPE_MSA_MISC_BPC_16BITS : constant := 4 * 2 ** 5;
219
220 function PIPE_MSA_MISC_BPC (BPC : HW.GFX.BPC_Type) return Word32 is
221 Result : Word32;
222 begin
223 case BPC is
224 when 6 => Result := PIPE_MSA_MISC_BPC_6BITS;
225 when 8 => Result := PIPE_MSA_MISC_BPC_8BITS;
226 when 10 => Result := PIPE_MSA_MISC_BPC_10BITS;
227 when 12 => Result := PIPE_MSA_MISC_BPC_12BITS;
228 --when 16 => Result := PIPE_MSA_MISC_BPC_16BITS;
229 when others => Result := PIPE_MSA_MISC_BPC_8BITS;
230 end case;
231 return Result;
232 end PIPE_MSA_MISC_BPC;
233
234 ---------------------------------------------------------------------------
235
236 function PIPECONF_BPC_MAP (Bits_Per_Color : HW.GFX.BPC_Type) return Word32
237 is
238 Result : Word32;
239 begin
240 if Bits_Per_Color = 6 then
241 Result := 2 * 2 ** 5;
242 elsif Bits_Per_Color = 10 then
243 Result := 1 * 2 ** 5;
244 elsif Bits_Per_Color = 12 then
245 Result := 3 * 2 ** 5;
246 else
247 Result := 0;
248 end if;
249 return Result;
250 end PIPECONF_BPC_MAP;
251
252 ---------------------------------------------------------------------------
253
254 function PLANE_WM_LINES (Lines : Natural) return Word32 is
255 begin
256 return Shift_Left (Word32 (Lines), PLANE_WM_LINES_SHIFT)
257 and PLANE_WM_LINES_MASK;
258 end PLANE_WM_LINES;
259
260 function PLANE_WM_BLOCKS (Blocks : Natural) return Word32 is
261 begin
262 return Word32 (Blocks) and PLANE_WM_BLOCKS_MASK;
263 end PLANE_WM_BLOCKS;
264
265 ---------------------------------------------------------------------------
266
267 function Encode (LSW, MSW : Pos16) return Word32 is
268 begin
269 return Shift_Left (Word32 (MSW - 1), 16) or Word32 (LSW - 1);
270 end Encode;
271
272 ----------------------------------------------------------------------------
273
274 procedure Setup_Link
275 (Head : Head_Type;
276 Link : DP_Link;
277 Mode : Mode_Type)
278 with
279 Global => (In_Out => Registers.Register_State),
280 Depends => (Registers.Register_State =>+ (Head, Link, Mode))
281 is
282 Data_M, Link_M : DP_Info.M_Type;
283 Data_N, Link_N : DP_Info.N_Type;
284 begin
285 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
286
287 DP_Info.Calculate_M_N
288 (Link => Link,
289 Mode => Mode,
290 Data_M => Data_M,
291 Data_N => Data_N,
292 Link_M => Link_M,
293 Link_N => Link_N);
294
295 Registers.Write
296 (Register => Head.PIPE_DATA_M1,
297 Value => PIPE_DATA_M_TU (64) or
298 Word32 (Data_M));
299 Registers.Write
300 (Register => Head.PIPE_DATA_N1,
301 Value => Word32 (Data_N));
302
303 Registers.Write
304 (Register => Head.PIPE_LINK_M1,
305 Value => Word32 (Link_M));
306 Registers.Write
307 (Register => Head.PIPE_LINK_N1,
308 Value => Word32 (Link_N));
309
310 if Config.Has_Pipe_MSA_Misc then
311 Registers.Write
312 (Register => Head.PIPE_MSA_MISC,
313 Value => PIPE_MSA_MISC_SYNC_CLK or
314 PIPE_MSA_MISC_BPC (Mode.BPC));
315 end if;
316 end Setup_Link;
317
318 ----------------------------------------------------------------------------
319
320 procedure Clear_Watermarks (Controller : Controller_Type) is
321 begin
322 Registers.Write
323 (Register => Controller.PLANE_BUF_CFG,
324 Value => 16#0000_0000#);
325 for Level in WM_Levels range 0 .. WM_Levels'Last loop
326 Registers.Write
327 (Register => Controller.PLANE_WM (Level),
328 Value => 16#0000_0000#);
329 end loop;
330 Registers.Write
331 (Register => Controller.WM_LINETIME,
332 Value => 16#0000_0000#);
333 end Clear_Watermarks;
334
335 procedure Setup_Watermarks (Controller : Controller_Type)
336 is
Nico Huberf3e23662016-12-05 21:33:03 +0100337 type Per_Plane_Buffer_Range is array (Pipe_Index) of Word32;
338 Buffer_Range : constant Per_Plane_Buffer_Range :=
339 (Primary => Shift_Left (159, 16) or 0,
340 Secondary => Shift_Left (319, 16) or 160,
341 Tertiary => Shift_Left (479, 16) or 320);
Nico Huber83693c82016-10-08 22:17:55 +0200342 begin
343 Registers.Write
344 (Register => Controller.PLANE_BUF_CFG,
Nico Huberf3e23662016-12-05 21:33:03 +0100345 Value => Buffer_Range (Controller.Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200346 Registers.Write
347 (Register => Controller.PLANE_WM (0),
348 Value => PLANE_WM_ENABLE or
349 PLANE_WM_LINES (2) or
350 PLANE_WM_BLOCKS (160));
351 end Setup_Watermarks;
352
353 ----------------------------------------------------------------------------
354
Nico Huber3675db52016-11-04 16:27:29 +0100355 procedure Setup_Hires_Plane
Nico Huber6a4dfc82016-11-04 15:50:58 +0100356 (Controller : Controller_Type;
357 Framebuffer : HW.GFX.Framebuffer_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200358 with
359 Global => (In_Out => Registers.Register_State),
360 Depends =>
361 (Registers.Register_State
362 =>+
363 (Registers.Register_State,
364 Controller,
Nico Huber83693c82016-10-08 22:17:55 +0200365 Framebuffer))
366 is
367 -- FIXME: setup correct format, based on framebuffer RGB format
368 Format : constant Word32 := 6 * 2 ** 26;
369 PRI : Word32 := DSPCNTR_ENABLE or Format;
370
371 function To_Bytes (Pixels : Width_Type) return Word32
372 with
373 Pre => (Word32 (Pixels) <= Word32'Last / 4 / Word32 (BPC_Type'Last) * 8)
374 is
375 begin
376 return Word32 (Pos64 (Pixels) * 4 * Framebuffer.BPC / 8);
377 end To_Bytes;
378 begin
379 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
380
Nico Huber83693c82016-10-08 22:17:55 +0200381 if Config.Has_Plane_Control then
Nico Huber83693c82016-10-08 22:17:55 +0200382 Registers.Write
383 (Register => Controller.PLANE_CTL,
384 Value => PLANE_CTL_PLANE_ENABLE or
385 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
386 PLANE_CTL_PLANE_GAMMA_DISABLE);
387 Registers.Write (Controller.PLANE_OFFSET, 16#0000_0000#);
Nico Huber6a4dfc82016-11-04 15:50:58 +0100388 Registers.Write
389 (Controller.PLANE_SIZE,
390 Encode (Pos16 (Framebuffer.Width), Pos16 (Framebuffer.Height)));
Nico Huber83693c82016-10-08 22:17:55 +0200391 Registers.Write (Controller.PLANE_STRIDE, To_Bytes (Framebuffer.Stride) / 64);
392 Registers.Write (Controller.PLANE_POS, 16#0000_0000#);
393 Registers.Write (Controller.PLANE_SURF, Framebuffer.Offset and 16#ffff_f000#);
394 else
395 if Config.Disable_Trickle_Feed then
396 PRI := PRI or DSPCNTR_DISABLE_TRICKLE_FEED;
397 end if;
398 -- for now, just disable gamma LUT (can't do anything
399 -- useful without colorimetry information from display)
400 Registers.Unset_And_Set_Mask
401 (Register => Controller.DSPCNTR,
402 Mask_Unset => DSPCNTR_MASK,
403 Mask_Set => PRI);
404
405 Registers.Write (Controller.DSPSTRIDE, To_Bytes (Framebuffer.Stride));
406 Registers.Write (Controller.DSPSURF, Framebuffer.Offset and 16#ffff_f000#);
407 if Config.Has_DSP_Linoff then
408 Registers.Write (Controller.DSPLINOFF, 0);
409 end if;
410 Registers.Write (Controller.DSPTILEOFF, 0);
411 end if;
Nico Huber3675db52016-11-04 16:27:29 +0100412 end Setup_Hires_Plane;
413
414 procedure Setup_Display
415 (Controller : in Controller_Type;
416 Head : in Head_Type;
417 Mode : in HW.GFX.Mode_Type;
418 Framebuffer : in HW.GFX.Framebuffer_Type)
419 with
420 Global => (In_Out => (Registers.Register_State, Port_IO.State)),
421 Depends =>
422 (Registers.Register_State
423 =>+
424 (Registers.Register_State,
425 Controller,
426 Head,
427 Mode,
428 Framebuffer),
429 Port_IO.State
430 =>+
431 (Framebuffer))
432 is
433 use type Word8;
434
435 Reg8 : Word8;
436 begin
437 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
438
439 if Config.Has_Plane_Control then
440 Setup_Watermarks (Controller);
441 end if;
442
443 if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
Nico Huberfbb42202016-11-07 15:08:26 +0100444 if Config.VGA_Plane_Workaround then
445 Registers.Unset_And_Set_Mask
446 (Register => Registers.ILK_DISPLAY_CHICKEN1,
447 Mask_Unset => ILK_DISPLAY_CHICKEN1_VGA_MASK,
448 Mask_Set => ILK_DISPLAY_CHICKEN1_VGA_ENABLE);
449 Registers.Unset_And_Set_Mask
450 (Register => Registers.ILK_DISPLAY_CHICKEN2,
451 Mask_Unset => ILK_DISPLAY_CHICKEN2_VGA_MASK,
452 Mask_Set => ILK_DISPLAY_CHICKEN2_VGA_ENABLE);
453 end if;
454
Nico Huber3675db52016-11-04 16:27:29 +0100455 Registers.Unset_And_Set_Mask
456 (Register => Registers.VGACNTRL,
457 Mask_Unset => VGA_CONTROL_VGA_DISPLAY_DISABLE or
458 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK or
459 VGA_CONTROL_VSYNC_BLINK_RATE_MASK,
460 Mask_Set => VGA_CONTROL_BLINK_DUTY_CYCLE_50 or
461 VGA_CONTROL_VSYNC_BLINK_RATE (30));
462
463 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
464 Port_IO.InB (Reg8, VGA_SR_DATA);
465 Port_IO.OutB (VGA_SR_DATA, Reg8 and not (VGA_SR01_SCREEN_OFF));
466 else
Nico Huber6a4dfc82016-11-04 15:50:58 +0100467 Setup_Hires_Plane (Controller, Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100468 end if;
469
470 Registers.Write
471 (Register => Controller.PIPESRC,
472 Value => Encode
473 (Pos16 (Framebuffer.Height), Pos16 (Framebuffer.Width)));
Nico Huber83693c82016-10-08 22:17:55 +0200474
475 Registers.Write (Head.HTOTAL, Encode (Mode.H_Visible, Mode.H_Total));
476 Registers.Write (Head.HBLANK, Encode (Mode.H_Visible, Mode.H_Total));
477 Registers.Write (Head.HSYNC, Encode (Mode.H_Sync_Begin, Mode.H_Sync_End));
478 Registers.Write (Head.VTOTAL, Encode (Mode.V_Visible, Mode.V_Total));
479 Registers.Write (Head.VBLANK, Encode (Mode.V_Visible, Mode.V_Total));
480 Registers.Write (Head.VSYNC, Encode (Mode.V_Sync_Begin, Mode.V_Sync_End));
481 end Setup_Display;
482
483 ----------------------------------------------------------------------------
484
Nico Huber4916e342016-11-04 14:37:53 +0100485 procedure Scale_Keep_Aspect
486 (Width : out Pos32;
487 Height : out Pos32;
488 Max_Width : in Pos32;
489 Max_Height : in Pos32;
490 Framebuffer : in Framebuffer_Type)
491 with
492 Pre =>
493 Max_Width <= Pos32 (Pos16'Last) and
494 Max_Height <= Pos32 (Pos16'Last) and
495 Framebuffer.Width <= Max_Width and
496 Framebuffer.Height <= Max_Height,
497 Post =>
498 Width <= Max_Width and Height <= Max_Height
499 is
500 begin
501 if (Max_Width * Framebuffer.Height) / Framebuffer.Width <= Max_Height then
502 Width := Max_Width;
503 Height := (Max_Width * Framebuffer.Height) / Framebuffer.Width;
504 else
505 Height := Max_Height;
506 Width := Pos32'Min (Max_Width, -- could prove, it's <= Max_Width
507 (Max_Height * Framebuffer.Width) / Framebuffer.Height);
508 end if;
509 end Scale_Keep_Aspect;
510
511 procedure Setup_Skylake_Pipe_Scaler
512 (Controller : in Controller_Type;
513 Mode : in HW.GFX.Mode_Type;
514 Framebuffer : in HW.GFX.Framebuffer_Type)
515 with
516 Pre =>
517 Framebuffer.Width <= Pos32 (Mode.H_Visible) and
518 Framebuffer.Height <= Pos32 (Mode.V_Visible)
519 is
520 -- Enable 7x5 extended mode where possible:
521 Scaler_Mode : constant Word32 :=
522 (if Controller.PS_CTRL_2 /= Registers.Invalid_Register then
523 PS_CTRL_SCALER_MODE_7X5_EXTENDED else 0);
524
525 -- We can scale up to 2.99x horizontally:
526 Horizontal_Limit : constant Pos32 := ((Framebuffer.Width * 299) / 100);
527 -- The third scaler is limited to 1.99x
528 -- vertical scaling for source widths > 2048:
529 Vertical_Limit : constant Pos32 :=
530 (Framebuffer.Height *
531 (if Controller.PS_CTRL_2 = Registers.Invalid_Register and
532 Framebuffer.Width > 2048
533 then
534 199
535 else
536 299)) / 100;
537
538 Width, Height : Pos32;
539 begin
540 -- Writes to WIN_SZ arm the PS registers.
541
542 Scale_Keep_Aspect
543 (Width => Width,
544 Height => Height,
545 Max_Width => Pos32'Min (Horizontal_Limit, Pos32 (Mode.H_Visible)),
546 Max_Height => Pos32'Min (Vertical_Limit, Pos32 (Mode.V_Visible)),
547 Framebuffer => Framebuffer);
548
549 Registers.Write
550 (Register => Controller.PS_CTRL_1,
551 Value => PS_CTRL_ENABLE_SCALER or Scaler_Mode);
552 Registers.Write
553 (Register => Controller.PS_WIN_POS_1,
554 Value =>
555 Shift_Left (Word32 (Pos32 (Mode.H_Visible) - Width) / 2, 16) or
556 Word32 (Pos32 (Mode.V_Visible) - Height) / 2);
557 Registers.Write
558 (Register => Controller.PS_WIN_SZ_1,
559 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
560 end Setup_Skylake_Pipe_Scaler;
561
562 procedure Setup_Ironlake_Panel_Fitter
563 (Controller : in Controller_Type;
564 Mode : in HW.GFX.Mode_Type;
565 Framebuffer : in HW.GFX.Framebuffer_Type)
566 with
567 Pre =>
568 Framebuffer.Width <= Pos32 (Mode.H_Visible) and
569 Framebuffer.Height <= Pos32 (Mode.V_Visible)
570 is
571 -- Force 1:1 mapping of panel fitter:pipe
572 PF_Ctrl_Pipe_Sel : constant Word32 :=
573 (if Config.Has_PF_Pipe_Select then
574 (case Controller.PF_CTRL is
575 when Registers.PFA_CTL_1 => 0 * 2 ** 29,
576 when Registers.PFB_CTL_1 => 1 * 2 ** 29,
577 when Registers.PFC_CTL_1 => 2 * 2 ** 29,
578 when others => 0) else 0);
579
580 Width, Height : Pos32;
581 begin
582 -- Writes to WIN_SZ arm the PF registers.
583
584 Scale_Keep_Aspect
585 (Width => Width,
586 Height => Height,
587 Max_Width => Pos32 (Mode.H_Visible),
588 Max_Height => Pos32 (Mode.V_Visible),
589 Framebuffer => Framebuffer);
590
591 Registers.Write
592 (Register => Controller.PF_CTRL,
593 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_CTRL_FILTER_MED);
594 Registers.Write
595 (Register => Controller.PF_WIN_POS,
596 Value =>
597 Shift_Left (Word32 (Pos32 (Mode.H_Visible) - Width) / 2, 16) or
598 Word32 (Pos32 (Mode.V_Visible) - Height) / 2);
599 Registers.Write
600 (Register => Controller.PF_WIN_SZ,
601 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
602 end Setup_Ironlake_Panel_Fitter;
603
604 procedure Setup_Scaling
605 (Controller : in Controller_Type;
606 Mode : in HW.GFX.Mode_Type;
607 Framebuffer : in HW.GFX.Framebuffer_Type)
608 with
609 Pre =>
610 Framebuffer.Width <= Pos32 (Mode.H_Visible) and
611 Framebuffer.Height <= Pos32 (Mode.V_Visible)
612 is
613 begin
614 if Framebuffer.Width /= Pos32 (Mode.H_Visible) or
615 Framebuffer.Height /= Pos32 (Mode.V_Visible)
616 then
617 if Config.Has_Plane_Control then
618 Setup_Skylake_Pipe_Scaler (Controller, Mode, Framebuffer);
619 else
620 Setup_Ironlake_Panel_Fitter (Controller, Mode, Framebuffer);
621 end if;
622 end if;
623 end Setup_Scaling;
624
625 ----------------------------------------------------------------------------
626
Nico Huber83693c82016-10-08 22:17:55 +0200627 procedure Setup_Head
628 (Controller : Controller_Type;
629 Head : Head_Type;
630 Port_Cfg : Port_Config;
631 Framebuffer : Framebuffer_Type)
632 is
633 PIPECONF_Options : Word32 := 0;
634 begin
635 if Config.Has_Pipe_DDI_Func then
636 Registers.Write
637 (Register => Head.PIPE_DDI_FUNC_CTL,
638 Value => PIPE_DDI_FUNC_CTL_ENABLE or
639 PIPE_DDI_FUNC_CTL_DDI_SELECT (Port_Cfg.Port) or
640 PIPE_DDI_FUNC_CTL_MODE_SELECT (Port_Cfg.Display) or
641 PIPE_DDI_FUNC_CTL_BPC (Port_Cfg.Mode.BPC) or
642 PIPE_DDI_FUNC_CTL_VSYNC (Port_Cfg.Mode.V_Sync_Active_High) or
643 PIPE_DDI_FUNC_CTL_HSYNC (Port_Cfg.Mode.H_Sync_Active_High) or
Nico Huberf3e23662016-12-05 21:33:03 +0100644 PIPE_DDI_FUNC_CTL_EDP_SELECT (Controller.Pipe) or
Nico Huber83693c82016-10-08 22:17:55 +0200645 PIPE_DDI_FUNC_CTL_PORT_WIDTH (Port_Cfg.DP.Lane_Count));
646 end if;
647
648 if Config.Has_Pipeconf_BPC then
649 PIPECONF_Options := PIPECONF_BPC_MAP (Port_Cfg.Mode.BPC);
650 end if;
651
652 -- Enable dithering if framebuffer BPC differs from connector BPC,
653 -- as smooth gradients look really bad without
654 if Framebuffer.BPC /= Port_Cfg.Mode.BPC then
655 PIPECONF_Options := PIPECONF_Options or PIPECONF_ENABLE_DITHER;
656 end if;
657
658 if not Config.Has_Pipeconf_Misc then
659 Registers.Write
660 (Register => Head.PIPECONF,
661 Value => PIPECONF_ENABLE or PIPECONF_Options);
662 else
663 Registers.Write
664 (Register => Controller.PIPEMISC,
665 Value => PIPECONF_Options);
666 Registers.Write
667 (Register => Head.PIPECONF,
668 Value => PIPECONF_ENABLE);
669 end if;
670 Registers.Posting_Read (Head.PIPECONF);
671 end Setup_Head;
672
673 ----------------------------------------------------------------------------
674
675 procedure On
Nico Huberf3e23662016-12-05 21:33:03 +0100676 (Pipe : Pipe_Index;
Nico Huber83693c82016-10-08 22:17:55 +0200677 Port_Cfg : Port_Config;
678 Framebuffer : Framebuffer_Type)
679 is
Nico Huberf3e23662016-12-05 21:33:03 +0100680 Head : constant Pipe_Head := Get_Pipe_Head (Pipe, Port_Cfg.Port);
Nico Huber83693c82016-10-08 22:17:55 +0200681 begin
682 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
683
684 if Config.Has_Trans_Clk_Sel then
685 Registers.Write
Nico Huberf3e23662016-12-05 21:33:03 +0100686 (Register => Controllers (Pipe).TRANS_CLK_SEL,
Nico Huber83693c82016-10-08 22:17:55 +0200687 Value => TRANS_CLK_SEL_PORT (Port_Cfg.Port));
688 end if;
689
690 if Port_Cfg.Is_FDI then
Nico Huberf3e23662016-12-05 21:33:03 +0100691 Setup_Link (Heads (Head), Port_Cfg.FDI, Port_Cfg.Mode);
Nico Huber83693c82016-10-08 22:17:55 +0200692 elsif Port_Cfg.Display = DP then
Nico Huberf3e23662016-12-05 21:33:03 +0100693 Setup_Link (Heads (Head), Port_Cfg.DP, Port_Cfg.Mode);
Nico Huber83693c82016-10-08 22:17:55 +0200694 end if;
695
Nico Huberf3e23662016-12-05 21:33:03 +0100696 Setup_Display
697 (Controllers (Pipe), Heads (Head), Port_Cfg.Mode, Framebuffer);
Nico Huber83693c82016-10-08 22:17:55 +0200698
Nico Huberf3e23662016-12-05 21:33:03 +0100699 Setup_Scaling (Controllers (Pipe), Port_Cfg.Mode, Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100700
Nico Huberf3e23662016-12-05 21:33:03 +0100701 Setup_Head (Controllers (Pipe), Heads (Head), Port_Cfg, Framebuffer);
Nico Huber83693c82016-10-08 22:17:55 +0200702 end On;
703
704 ----------------------------------------------------------------------------
705
706 procedure Planes_Off (Controller : Controller_Type) is
707 begin
708 Registers.Unset_Mask (Controller.SPCNTR, SPCNTR_ENABLE);
709 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
718 procedure Head_Off (Head : Head_Type)
719 is
720 Enabled : Boolean;
721 begin
722 Registers.Is_Set_Mask (Head.PIPECONF, PIPECONF_ENABLE, Enabled);
723
724 if Enabled then
725 Registers.Unset_Mask (Head.PIPECONF, PIPECONF_ENABLE);
726 end if;
727
728 -- Workaround for Broadwell:
729 -- Status may be wrong if pipe hasn't been enabled since reset.
730 if not Config.Pipe_Enabled_Workaround or else Enabled then
731 -- synchronously wait until pipe is truly off
732 Registers.Wait_Unset_Mask
733 (Register => Head.PIPECONF,
734 Mask => PIPECONF_ENABLED_STATUS,
735 TOut_MS => 40);
736 end if;
737
738 if Config.Has_Pipe_DDI_Func then
739 Registers.Write (Head.PIPE_DDI_FUNC_CTL, 0);
740 end if;
741 end Head_Off;
742
743 procedure Panel_Fitter_Off (Controller : Controller_Type) is
744 begin
745 -- Writes to WIN_SZ arm the PS/PF registers.
746 if Config.Has_Plane_Control then
747 Registers.Unset_Mask (Controller.PS_CTRL_1, PS_CTRL_ENABLE_SCALER);
748 Registers.Write (Controller.PS_WIN_SZ_1, 16#0000_0000#);
749 if Controller.PS_CTRL_2 /= Registers.Invalid_Register and
750 Controller.PS_WIN_SZ_2 /= Registers.Invalid_Register
751 then
752 Registers.Unset_Mask (Controller.PS_CTRL_2, PS_CTRL_ENABLE_SCALER);
753 Registers.Write (Controller.PS_WIN_SZ_2, 16#0000_0000#);
754 end if;
755 else
Nico Huber4916e342016-11-04 14:37:53 +0100756 Registers.Unset_Mask (Controller.PF_CTRL, PF_CTRL_ENABLE);
Nico Huber83693c82016-10-08 22:17:55 +0200757 Registers.Write (Controller.PF_WIN_SZ, 16#0000_0000#);
758 end if;
759 end Panel_Fitter_Off;
760
761 procedure Trans_Clk_Off (Controller : Controller_Type) is
762 begin
763 if Config.Has_Trans_Clk_Sel then
764 Registers.Write (Controller.TRANS_CLK_SEL, TRANS_CLK_SEL_PORT_NONE);
765 end if;
766 end Trans_Clk_Off;
767
Nico Huberf3e23662016-12-05 21:33:03 +0100768 procedure Off (Pipe : Pipe_Index; Port_Cfg : Port_Config)
769 is
Nico Huber83693c82016-10-08 22:17:55 +0200770 begin
771 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
772
Nico Huberf3e23662016-12-05 21:33:03 +0100773 Planes_Off (Controllers (Pipe));
774 Head_Off (Heads (Get_Pipe_Head (Pipe, Port_Cfg.Port)));
775 Panel_Fitter_Off (Controllers (Pipe));
776 Trans_Clk_Off (Controllers (Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200777 end Off;
778
Nico Huber33912aa2016-12-06 20:36:23 +0100779 procedure Legacy_VGA_Off
780 is
781 use type HW.Word8;
782 Reg8 : Word8;
783 begin
784 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
785 Port_IO.InB (Reg8, VGA_SR_DATA);
786 Port_IO.OutB (VGA_SR_DATA, Reg8 or VGA_SR01_SCREEN_OFF);
787 Time.U_Delay (100); -- PRM says 100us, Linux does 300
788 Registers.Set_Mask (Registers.VGACNTRL, VGA_CONTROL_VGA_DISPLAY_DISABLE);
789 end Legacy_VGA_Off;
790
Nico Huber83693c82016-10-08 22:17:55 +0200791 procedure All_Off
792 is
793 EDP_Enabled, EDP_Piped : Boolean;
794
Nico Huberf3e23662016-12-05 21:33:03 +0100795 procedure EDP_Piped_To (Pipe : Pipe_Index; Piped_To : out Boolean)
Nico Huber83693c82016-10-08 22:17:55 +0200796 is
797 Pipe_DDI_Func_Ctl : Word32;
798 begin
799 Registers.Read (Registers.PIPE_EDP_DDI_FUNC_CTL, Pipe_DDI_Func_Ctl);
800 Pipe_DDI_Func_Ctl :=
801 Pipe_DDI_Func_Ctl and PIPE_DDI_FUNC_CTL_EDP_SELECT_MASK;
802
Nico Huberf3e23662016-12-05 21:33:03 +0100803 Piped_To :=
804 (Pipe = Primary and
805 Pipe_DDI_Func_Ctl = PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON) or
806 Pipe_DDI_Func_Ctl = PIPE_DDI_FUNC_CTL_EDP_SELECT_ONOFF (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +0200807 end EDP_Piped_To;
808 begin
809 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
810
Nico Huber33912aa2016-12-06 20:36:23 +0100811 Legacy_VGA_Off;
812
Nico Huber83693c82016-10-08 22:17:55 +0200813 if Config.Has_EDP_Pipe then
814 Registers.Is_Set_Mask
815 (Registers.PIPE_EDP_CONF, PIPECONF_ENABLE, EDP_Enabled);
816 else
817 EDP_Enabled := False;
818 end if;
819
Nico Huberf3e23662016-12-05 21:33:03 +0100820 for Pipe in Pipe_Index loop
821 Planes_Off (Controllers (Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200822 if EDP_Enabled then
Nico Huberf3e23662016-12-05 21:33:03 +0100823 EDP_Piped_To (Pipe, EDP_Piped);
Nico Huber83693c82016-10-08 22:17:55 +0200824 if EDP_Piped then
825 Head_Off (Heads (Head_EDP));
826 EDP_Enabled := False;
827 end if;
828 end if;
Nico Huberf3e23662016-12-05 21:33:03 +0100829 Head_Off (Heads (Default_Pipe_Head (Pipe)));
830 Panel_Fitter_Off (Controllers (Pipe));
831 Trans_Clk_Off (Controllers (Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200832 end loop;
833
834 if EDP_Enabled then
835 Head_Off (Heads (Head_EDP));
836 end if;
837 end All_Off;
838
839 ----------------------------------------------------------------------------
840
Nico Huberf3e23662016-12-05 21:33:03 +0100841 procedure Update_Offset (Pipe : Pipe_Index; Framebuffer : Framebuffer_Type)
842 is
Nico Huber83693c82016-10-08 22:17:55 +0200843 begin
844 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
845
Nico Huberf3e23662016-12-05 21:33:03 +0100846 Registers.Write
847 (Controllers (Pipe).DSPSURF, Framebuffer.Offset and 16#ffff_f000#);
Nico Huber83693c82016-10-08 22:17:55 +0200848 end Update_Offset;
849
850 ----------------------------------------------------------------------------
851
Nico Huberf3e23662016-12-05 21:33:03 +0100852 function Get_Pipe_Hint (Pipe : Pipe_Index) return Word32
Nico Huber83693c82016-10-08 22:17:55 +0200853 is
Nico Huber83693c82016-10-08 22:17:55 +0200854 begin
Nico Huberf3e23662016-12-05 21:33:03 +0100855 return
856 (case Pipe is
857 when Primary => 0,
858 when Secondary => 1,
859 when Tertiary => 2);
Nico Huber83693c82016-10-08 22:17:55 +0200860 end Get_Pipe_Hint;
861
Nico Huber83693c82016-10-08 22:17:55 +0200862end HW.GFX.GMA.Pipe_Setup;