blob: ca578554a340185610d2f9cbab15c711e5139839 [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 Huber3675db52016-11-04 16:27:29 +010073 VGA_SR01_SCREEN_OFF : constant := 1 * 2 ** 5;
74
75 VGA_CONTROL_VGA_DISPLAY_DISABLE : constant := 1 * 2 ** 31;
76 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK : constant := 16#0003# * 2 ** 6;
77 VGA_CONTROL_BLINK_DUTY_CYCLE_50 : constant := 2 * 2 ** 6;
78 VGA_CONTROL_VSYNC_BLINK_RATE_MASK : constant := 16#003f# * 2 ** 0;
79
80 subtype VGA_Cycle_Count is Pos32 range 2 .. 128;
81 function VGA_CONTROL_VSYNC_BLINK_RATE
82 (Cycles : VGA_Cycle_Count)
83 return Word32
84 is
85 begin
86 return Word32 (Cycles) / 2 - 1;
87 end VGA_CONTROL_VSYNC_BLINK_RATE;
88
Nico Huber83693c82016-10-08 22:17:55 +020089 TRANS_CLK_SEL_PORT_NONE : constant := 0 * 2 ** 29;
90
91 type TRANS_CLK_SEL_PORT_Array is
92 array (Digital_Port) of Word32;
93 TRANS_CLK_SEL_PORT : constant TRANS_CLK_SEL_PORT_Array :=
94 TRANS_CLK_SEL_PORT_Array'
95 (DIGI_A => 0 * 2 ** 29, -- DDI A is not selectable
96 DIGI_B => 2 * 2 ** 29,
97 DIGI_C => 3 * 2 ** 29,
98 DIGI_D => 4 * 2 ** 29,
99 DIGI_E => 5 * 2 ** 29);
100
101 PIPECONF_ENABLE : constant := 1 * 2 ** 31;
102 PIPECONF_ENABLED_STATUS : constant := 1 * 2 ** 30;
103 PIPECONF_ENABLE_DITHER : constant := 1 * 2 ** 4;
104 PIPECONF_DITHER_TEMPORAL : constant := 1 * 2 ** 2;
105
Nico Huber4916e342016-11-04 14:37:53 +0100106 PF_CTRL_ENABLE : constant := 1 * 2 ** 31;
107 PF_CTRL_PIPE_SELECT_MASK : constant := 3 * 2 ** 29;
108 PF_CTRL_FILTER_MED : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200109
Nico Huber4916e342016-11-04 14:37:53 +0100110 PS_CTRL_ENABLE_SCALER : constant := 1 * 2 ** 31;
111 PS_CTRL_SCALER_MODE_7X5_EXTENDED : constant := 1 * 2 ** 28;
112 PS_CTRL_FILTER_SELECT_MEDIUM_2 : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200113
114 PIPE_DDI_FUNC_CTL_ENABLE : constant := 1 * 2 ** 31;
115 PIPE_DDI_FUNC_CTL_DDI_SELECT_MASK : constant := 7 * 2 ** 28;
116 PIPE_DDI_FUNC_CTL_DDI_SELECT_NONE : constant := 0 * 2 ** 28;
117 PIPE_DDI_FUNC_CTL_DDI_SELECT_B : constant := 1 * 2 ** 28;
118 PIPE_DDI_FUNC_CTL_DDI_SELECT_C : constant := 2 * 2 ** 28;
119 PIPE_DDI_FUNC_CTL_DDI_SELECT_D : constant := 3 * 2 ** 28;
120 PIPE_DDI_FUNC_CTL_DDI_SELECT_E : constant := 4 * 2 ** 28;
121 PIPE_DDI_FUNC_CTL_MODE_SELECT_MASK : constant := 7 * 2 ** 24;
122 PIPE_DDI_FUNC_CTL_MODE_SELECT_HDMI : constant := 0 * 2 ** 24;
123 PIPE_DDI_FUNC_CTL_MODE_SELECT_DVI : constant := 1 * 2 ** 24;
124 PIPE_DDI_FUNC_CTL_MODE_SELECT_DP_SST : constant := 2 * 2 ** 24;
125 PIPE_DDI_FUNC_CTL_MODE_SELECT_DP_MST : constant := 3 * 2 ** 24;
126 PIPE_DDI_FUNC_CTL_MODE_SELECT_FDI : constant := 4 * 2 ** 24;
127 PIPE_DDI_FUNC_CTL_BPC_MASK : constant := 7 * 2 ** 20;
128 PIPE_DDI_FUNC_CTL_BPC_8BITS : constant := 0 * 2 ** 20;
129 PIPE_DDI_FUNC_CTL_BPC_10BITS : constant := 1 * 2 ** 20;
130 PIPE_DDI_FUNC_CTL_BPC_6BITS : constant := 2 * 2 ** 20;
131 PIPE_DDI_FUNC_CTL_BPC_12BITS : constant := 3 * 2 ** 20;
132 PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_LOW : constant := 0 * 2 ** 17;
133 PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 17;
134 PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_LOW : constant := 0 * 2 ** 16;
135 PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 16;
136 PIPE_DDI_FUNC_CTL_EDP_SELECT_MASK : constant := 7 * 2 ** 12;
137 PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON : constant := 0 * 2 ** 12;
138 PIPE_DDI_FUNC_CTL_EDP_SELECT_A : constant := 4 * 2 ** 12;
139 PIPE_DDI_FUNC_CTL_EDP_SELECT_B : constant := 5 * 2 ** 12;
140 PIPE_DDI_FUNC_CTL_EDP_SELECT_C : constant := 6 * 2 ** 12;
141 PIPE_DDI_FUNC_CTL_DP_VC_PAYLOAD_ALLOC : constant := 1 * 2 ** 8;
142 PIPE_DDI_FUNC_CTL_BFI_ENABLE : constant := 1 * 2 ** 4;
143 PIPE_DDI_FUNC_CTL_PORT_WIDTH_MASK : constant := 7 * 2 ** 1;
144 PIPE_DDI_FUNC_CTL_PORT_WIDTH_1_LANE : constant := 0 * 2 ** 1;
145 PIPE_DDI_FUNC_CTL_PORT_WIDTH_2_LANES : constant := 1 * 2 ** 1;
146 PIPE_DDI_FUNC_CTL_PORT_WIDTH_4_LANES : constant := 3 * 2 ** 1;
147
148 type DDI_Select_Array is array (Digital_Port) of Word32;
149 PIPE_DDI_FUNC_CTL_DDI_SELECT : constant DDI_Select_Array :=
150 DDI_Select_Array'
151 (DIGI_A => PIPE_DDI_FUNC_CTL_DDI_SELECT_NONE,
152 DIGI_B => PIPE_DDI_FUNC_CTL_DDI_SELECT_B,
153 DIGI_C => PIPE_DDI_FUNC_CTL_DDI_SELECT_C,
154 DIGI_D => PIPE_DDI_FUNC_CTL_DDI_SELECT_D,
155 DIGI_E => PIPE_DDI_FUNC_CTL_DDI_SELECT_E);
156
157 type DDI_Mode_Array is array (Display_Type) of Word32;
158 PIPE_DDI_FUNC_CTL_MODE_SELECT : constant DDI_Mode_Array :=
159 DDI_Mode_Array'
160 (VGA => PIPE_DDI_FUNC_CTL_MODE_SELECT_FDI,
161 HDMI => PIPE_DDI_FUNC_CTL_MODE_SELECT_DVI,
162 DP => PIPE_DDI_FUNC_CTL_MODE_SELECT_DP_SST,
163 others => 0);
164
165 type HV_Sync_Array is array (Boolean) of Word32;
166 PIPE_DDI_FUNC_CTL_VSYNC : constant HV_Sync_Array := HV_Sync_Array'
167 (False => PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_LOW,
168 True => PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_HIGH);
169 PIPE_DDI_FUNC_CTL_HSYNC : constant HV_Sync_Array := HV_Sync_Array'
170 (False => PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_LOW,
171 True => PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_HIGH);
172
Nico Huberf3e23662016-12-05 21:33:03 +0100173 type EDP_Select_Array is array (Pipe_Index) of Word32;
Nico Huber83693c82016-10-08 22:17:55 +0200174 PIPE_DDI_FUNC_CTL_EDP_SELECT : constant EDP_Select_Array :=
Nico Huberf3e23662016-12-05 21:33:03 +0100175 (Primary => PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON, -- we never use
176 -- panel fitter
177 Secondary => PIPE_DDI_FUNC_CTL_EDP_SELECT_B,
178 Tertiary => PIPE_DDI_FUNC_CTL_EDP_SELECT_C);
Nico Huber83693c82016-10-08 22:17:55 +0200179 PIPE_DDI_FUNC_CTL_EDP_SELECT_ONOFF : constant EDP_Select_Array :=
Nico Huberf3e23662016-12-05 21:33:03 +0100180 (Primary => PIPE_DDI_FUNC_CTL_EDP_SELECT_A,
181 Secondary => PIPE_DDI_FUNC_CTL_EDP_SELECT_B,
182 Tertiary => PIPE_DDI_FUNC_CTL_EDP_SELECT_C);
Nico Huber83693c82016-10-08 22:17:55 +0200183
184 type Port_Width_Array is array (HW.GFX.DP_Lane_Count) of Word32;
185 PIPE_DDI_FUNC_CTL_PORT_WIDTH : constant Port_Width_Array :=
186 Port_Width_Array'
187 (HW.GFX.DP_Lane_Count_1 => PIPE_DDI_FUNC_CTL_PORT_WIDTH_1_LANE,
188 HW.GFX.DP_Lane_Count_2 => PIPE_DDI_FUNC_CTL_PORT_WIDTH_2_LANES,
189 HW.GFX.DP_Lane_Count_4 => PIPE_DDI_FUNC_CTL_PORT_WIDTH_4_LANES);
190
191 function PIPE_DDI_FUNC_CTL_BPC (BPC : HW.GFX.BPC_Type) return Word32
192 is
193 Result : Word32;
194 begin
195 case BPC is
196 when 6 => Result := PIPE_DDI_FUNC_CTL_BPC_6BITS;
197 when 8 => Result := PIPE_DDI_FUNC_CTL_BPC_8BITS;
198 when 10 => Result := PIPE_DDI_FUNC_CTL_BPC_10BITS;
199 when 12 => Result := PIPE_DDI_FUNC_CTL_BPC_12BITS;
200 when others => Result := PIPE_DDI_FUNC_CTL_BPC_8BITS;
201 end case;
202 return Result;
203 end PIPE_DDI_FUNC_CTL_BPC;
204
205 function PIPE_DATA_M_TU (Transfer_Unit : Positive) return Word32 is
206 begin
207 return Shift_Left (Word32 (Transfer_Unit - 1), 25);
208 end PIPE_DATA_M_TU;
209
210 PIPE_MSA_MISC_SYNC_CLK : constant := 1 * 2 ** 0;
211 PIPE_MSA_MISC_BPC_6BITS : constant := 0 * 2 ** 5;
212 PIPE_MSA_MISC_BPC_8BITS : constant := 1 * 2 ** 5;
213 PIPE_MSA_MISC_BPC_10BITS : constant := 2 * 2 ** 5;
214 PIPE_MSA_MISC_BPC_12BITS : constant := 3 * 2 ** 5;
215 PIPE_MSA_MISC_BPC_16BITS : constant := 4 * 2 ** 5;
216
217 function PIPE_MSA_MISC_BPC (BPC : HW.GFX.BPC_Type) return Word32 is
218 Result : Word32;
219 begin
220 case BPC is
221 when 6 => Result := PIPE_MSA_MISC_BPC_6BITS;
222 when 8 => Result := PIPE_MSA_MISC_BPC_8BITS;
223 when 10 => Result := PIPE_MSA_MISC_BPC_10BITS;
224 when 12 => Result := PIPE_MSA_MISC_BPC_12BITS;
225 --when 16 => Result := PIPE_MSA_MISC_BPC_16BITS;
226 when others => Result := PIPE_MSA_MISC_BPC_8BITS;
227 end case;
228 return Result;
229 end PIPE_MSA_MISC_BPC;
230
231 ---------------------------------------------------------------------------
232
233 function PIPECONF_BPC_MAP (Bits_Per_Color : HW.GFX.BPC_Type) return Word32
234 is
235 Result : Word32;
236 begin
237 if Bits_Per_Color = 6 then
238 Result := 2 * 2 ** 5;
239 elsif Bits_Per_Color = 10 then
240 Result := 1 * 2 ** 5;
241 elsif Bits_Per_Color = 12 then
242 Result := 3 * 2 ** 5;
243 else
244 Result := 0;
245 end if;
246 return Result;
247 end PIPECONF_BPC_MAP;
248
249 ---------------------------------------------------------------------------
250
251 function PLANE_WM_LINES (Lines : Natural) return Word32 is
252 begin
253 return Shift_Left (Word32 (Lines), PLANE_WM_LINES_SHIFT)
254 and PLANE_WM_LINES_MASK;
255 end PLANE_WM_LINES;
256
257 function PLANE_WM_BLOCKS (Blocks : Natural) return Word32 is
258 begin
259 return Word32 (Blocks) and PLANE_WM_BLOCKS_MASK;
260 end PLANE_WM_BLOCKS;
261
262 ---------------------------------------------------------------------------
263
264 function Encode (LSW, MSW : Pos16) return Word32 is
265 begin
266 return Shift_Left (Word32 (MSW - 1), 16) or Word32 (LSW - 1);
267 end Encode;
268
269 ----------------------------------------------------------------------------
270
271 procedure Setup_Link
272 (Head : Head_Type;
273 Link : DP_Link;
274 Mode : Mode_Type)
275 with
276 Global => (In_Out => Registers.Register_State),
277 Depends => (Registers.Register_State =>+ (Head, Link, Mode))
278 is
279 Data_M, Link_M : DP_Info.M_Type;
280 Data_N, Link_N : DP_Info.N_Type;
281 begin
282 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
283
284 DP_Info.Calculate_M_N
285 (Link => Link,
286 Mode => Mode,
287 Data_M => Data_M,
288 Data_N => Data_N,
289 Link_M => Link_M,
290 Link_N => Link_N);
291
292 Registers.Write
293 (Register => Head.PIPE_DATA_M1,
294 Value => PIPE_DATA_M_TU (64) or
295 Word32 (Data_M));
296 Registers.Write
297 (Register => Head.PIPE_DATA_N1,
298 Value => Word32 (Data_N));
299
300 Registers.Write
301 (Register => Head.PIPE_LINK_M1,
302 Value => Word32 (Link_M));
303 Registers.Write
304 (Register => Head.PIPE_LINK_N1,
305 Value => Word32 (Link_N));
306
307 if Config.Has_Pipe_MSA_Misc then
308 Registers.Write
309 (Register => Head.PIPE_MSA_MISC,
310 Value => PIPE_MSA_MISC_SYNC_CLK or
311 PIPE_MSA_MISC_BPC (Mode.BPC));
312 end if;
313 end Setup_Link;
314
315 ----------------------------------------------------------------------------
316
317 procedure Clear_Watermarks (Controller : Controller_Type) is
318 begin
319 Registers.Write
320 (Register => Controller.PLANE_BUF_CFG,
321 Value => 16#0000_0000#);
322 for Level in WM_Levels range 0 .. WM_Levels'Last loop
323 Registers.Write
324 (Register => Controller.PLANE_WM (Level),
325 Value => 16#0000_0000#);
326 end loop;
327 Registers.Write
328 (Register => Controller.WM_LINETIME,
329 Value => 16#0000_0000#);
330 end Clear_Watermarks;
331
332 procedure Setup_Watermarks (Controller : Controller_Type)
333 is
Nico Huberf3e23662016-12-05 21:33:03 +0100334 type Per_Plane_Buffer_Range is array (Pipe_Index) of Word32;
335 Buffer_Range : constant Per_Plane_Buffer_Range :=
336 (Primary => Shift_Left (159, 16) or 0,
337 Secondary => Shift_Left (319, 16) or 160,
338 Tertiary => Shift_Left (479, 16) or 320);
Nico Huber83693c82016-10-08 22:17:55 +0200339 begin
340 Registers.Write
341 (Register => Controller.PLANE_BUF_CFG,
Nico Huberf3e23662016-12-05 21:33:03 +0100342 Value => Buffer_Range (Controller.Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200343 Registers.Write
344 (Register => Controller.PLANE_WM (0),
345 Value => PLANE_WM_ENABLE or
346 PLANE_WM_LINES (2) or
347 PLANE_WM_BLOCKS (160));
348 end Setup_Watermarks;
349
350 ----------------------------------------------------------------------------
351
Nico Huber3675db52016-11-04 16:27:29 +0100352 procedure Setup_Hires_Plane
Nico Huber6a4dfc82016-11-04 15:50:58 +0100353 (Controller : Controller_Type;
354 Framebuffer : HW.GFX.Framebuffer_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200355 with
356 Global => (In_Out => Registers.Register_State),
357 Depends =>
358 (Registers.Register_State
359 =>+
360 (Registers.Register_State,
361 Controller,
Nico Huber83693c82016-10-08 22:17:55 +0200362 Framebuffer))
363 is
364 -- FIXME: setup correct format, based on framebuffer RGB format
365 Format : constant Word32 := 6 * 2 ** 26;
366 PRI : Word32 := DSPCNTR_ENABLE or Format;
367
368 function To_Bytes (Pixels : Width_Type) return Word32
369 with
370 Pre => (Word32 (Pixels) <= Word32'Last / 4 / Word32 (BPC_Type'Last) * 8)
371 is
372 begin
373 return Word32 (Pos64 (Pixels) * 4 * Framebuffer.BPC / 8);
374 end To_Bytes;
375 begin
376 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
377
Nico Huber83693c82016-10-08 22:17:55 +0200378 if Config.Has_Plane_Control then
Nico Huber83693c82016-10-08 22:17:55 +0200379 Registers.Write
380 (Register => Controller.PLANE_CTL,
381 Value => PLANE_CTL_PLANE_ENABLE or
382 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
383 PLANE_CTL_PLANE_GAMMA_DISABLE);
384 Registers.Write (Controller.PLANE_OFFSET, 16#0000_0000#);
Nico Huber6a4dfc82016-11-04 15:50:58 +0100385 Registers.Write
386 (Controller.PLANE_SIZE,
387 Encode (Pos16 (Framebuffer.Width), Pos16 (Framebuffer.Height)));
Nico Huber83693c82016-10-08 22:17:55 +0200388 Registers.Write (Controller.PLANE_STRIDE, To_Bytes (Framebuffer.Stride) / 64);
389 Registers.Write (Controller.PLANE_POS, 16#0000_0000#);
390 Registers.Write (Controller.PLANE_SURF, Framebuffer.Offset and 16#ffff_f000#);
391 else
392 if Config.Disable_Trickle_Feed then
393 PRI := PRI or DSPCNTR_DISABLE_TRICKLE_FEED;
394 end if;
395 -- for now, just disable gamma LUT (can't do anything
396 -- useful without colorimetry information from display)
397 Registers.Unset_And_Set_Mask
398 (Register => Controller.DSPCNTR,
399 Mask_Unset => DSPCNTR_MASK,
400 Mask_Set => PRI);
401
402 Registers.Write (Controller.DSPSTRIDE, To_Bytes (Framebuffer.Stride));
403 Registers.Write (Controller.DSPSURF, Framebuffer.Offset and 16#ffff_f000#);
404 if Config.Has_DSP_Linoff then
405 Registers.Write (Controller.DSPLINOFF, 0);
406 end if;
407 Registers.Write (Controller.DSPTILEOFF, 0);
408 end if;
Nico Huber3675db52016-11-04 16:27:29 +0100409 end Setup_Hires_Plane;
410
411 procedure Setup_Display
412 (Controller : in Controller_Type;
413 Head : in Head_Type;
414 Mode : in HW.GFX.Mode_Type;
415 Framebuffer : in HW.GFX.Framebuffer_Type)
416 with
417 Global => (In_Out => (Registers.Register_State, Port_IO.State)),
418 Depends =>
419 (Registers.Register_State
420 =>+
421 (Registers.Register_State,
422 Controller,
423 Head,
424 Mode,
425 Framebuffer),
426 Port_IO.State
427 =>+
428 (Framebuffer))
429 is
430 use type Word8;
431
432 Reg8 : Word8;
433 begin
434 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
435
436 if Config.Has_Plane_Control then
437 Setup_Watermarks (Controller);
438 end if;
439
440 if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
Nico Huberfbb42202016-11-07 15:08:26 +0100441 if Config.VGA_Plane_Workaround then
442 Registers.Unset_And_Set_Mask
443 (Register => Registers.ILK_DISPLAY_CHICKEN1,
444 Mask_Unset => ILK_DISPLAY_CHICKEN1_VGA_MASK,
445 Mask_Set => ILK_DISPLAY_CHICKEN1_VGA_ENABLE);
446 Registers.Unset_And_Set_Mask
447 (Register => Registers.ILK_DISPLAY_CHICKEN2,
448 Mask_Unset => ILK_DISPLAY_CHICKEN2_VGA_MASK,
449 Mask_Set => ILK_DISPLAY_CHICKEN2_VGA_ENABLE);
450 end if;
451
Nico Huber3675db52016-11-04 16:27:29 +0100452 Registers.Unset_And_Set_Mask
453 (Register => Registers.VGACNTRL,
454 Mask_Unset => VGA_CONTROL_VGA_DISPLAY_DISABLE or
455 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK or
456 VGA_CONTROL_VSYNC_BLINK_RATE_MASK,
457 Mask_Set => VGA_CONTROL_BLINK_DUTY_CYCLE_50 or
458 VGA_CONTROL_VSYNC_BLINK_RATE (30));
459
460 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
461 Port_IO.InB (Reg8, VGA_SR_DATA);
462 Port_IO.OutB (VGA_SR_DATA, Reg8 and not (VGA_SR01_SCREEN_OFF));
463 else
Nico Huber6a4dfc82016-11-04 15:50:58 +0100464 Setup_Hires_Plane (Controller, Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100465 end if;
466
467 Registers.Write
468 (Register => Controller.PIPESRC,
469 Value => Encode
470 (Pos16 (Framebuffer.Height), Pos16 (Framebuffer.Width)));
Nico Huber83693c82016-10-08 22:17:55 +0200471
472 Registers.Write (Head.HTOTAL, Encode (Mode.H_Visible, Mode.H_Total));
473 Registers.Write (Head.HBLANK, Encode (Mode.H_Visible, Mode.H_Total));
474 Registers.Write (Head.HSYNC, Encode (Mode.H_Sync_Begin, Mode.H_Sync_End));
475 Registers.Write (Head.VTOTAL, Encode (Mode.V_Visible, Mode.V_Total));
476 Registers.Write (Head.VBLANK, Encode (Mode.V_Visible, Mode.V_Total));
477 Registers.Write (Head.VSYNC, Encode (Mode.V_Sync_Begin, Mode.V_Sync_End));
478 end Setup_Display;
479
480 ----------------------------------------------------------------------------
481
Nico Huber4916e342016-11-04 14:37:53 +0100482 procedure Scale_Keep_Aspect
483 (Width : out Pos32;
484 Height : out Pos32;
485 Max_Width : in Pos32;
486 Max_Height : in Pos32;
487 Framebuffer : in Framebuffer_Type)
488 with
489 Pre =>
490 Max_Width <= Pos32 (Pos16'Last) and
491 Max_Height <= Pos32 (Pos16'Last) and
492 Framebuffer.Width <= Max_Width and
493 Framebuffer.Height <= Max_Height,
494 Post =>
495 Width <= Max_Width and Height <= Max_Height
496 is
497 begin
498 if (Max_Width * Framebuffer.Height) / Framebuffer.Width <= Max_Height then
499 Width := Max_Width;
500 Height := (Max_Width * Framebuffer.Height) / Framebuffer.Width;
501 else
502 Height := Max_Height;
503 Width := Pos32'Min (Max_Width, -- could prove, it's <= Max_Width
504 (Max_Height * Framebuffer.Width) / Framebuffer.Height);
505 end if;
506 end Scale_Keep_Aspect;
507
508 procedure Setup_Skylake_Pipe_Scaler
509 (Controller : in Controller_Type;
510 Mode : in HW.GFX.Mode_Type;
511 Framebuffer : in HW.GFX.Framebuffer_Type)
512 with
513 Pre =>
514 Framebuffer.Width <= Pos32 (Mode.H_Visible) and
515 Framebuffer.Height <= Pos32 (Mode.V_Visible)
516 is
517 -- Enable 7x5 extended mode where possible:
518 Scaler_Mode : constant Word32 :=
519 (if Controller.PS_CTRL_2 /= Registers.Invalid_Register then
520 PS_CTRL_SCALER_MODE_7X5_EXTENDED else 0);
521
522 -- We can scale up to 2.99x horizontally:
523 Horizontal_Limit : constant Pos32 := ((Framebuffer.Width * 299) / 100);
524 -- The third scaler is limited to 1.99x
525 -- vertical scaling for source widths > 2048:
526 Vertical_Limit : constant Pos32 :=
527 (Framebuffer.Height *
528 (if Controller.PS_CTRL_2 = Registers.Invalid_Register and
529 Framebuffer.Width > 2048
530 then
531 199
532 else
533 299)) / 100;
534
535 Width, Height : Pos32;
536 begin
537 -- Writes to WIN_SZ arm the PS registers.
538
539 Scale_Keep_Aspect
540 (Width => Width,
541 Height => Height,
542 Max_Width => Pos32'Min (Horizontal_Limit, Pos32 (Mode.H_Visible)),
543 Max_Height => Pos32'Min (Vertical_Limit, Pos32 (Mode.V_Visible)),
544 Framebuffer => Framebuffer);
545
546 Registers.Write
547 (Register => Controller.PS_CTRL_1,
548 Value => PS_CTRL_ENABLE_SCALER or Scaler_Mode);
549 Registers.Write
550 (Register => Controller.PS_WIN_POS_1,
551 Value =>
552 Shift_Left (Word32 (Pos32 (Mode.H_Visible) - Width) / 2, 16) or
553 Word32 (Pos32 (Mode.V_Visible) - Height) / 2);
554 Registers.Write
555 (Register => Controller.PS_WIN_SZ_1,
556 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
557 end Setup_Skylake_Pipe_Scaler;
558
559 procedure Setup_Ironlake_Panel_Fitter
560 (Controller : in Controller_Type;
561 Mode : in HW.GFX.Mode_Type;
562 Framebuffer : in HW.GFX.Framebuffer_Type)
563 with
564 Pre =>
565 Framebuffer.Width <= Pos32 (Mode.H_Visible) and
566 Framebuffer.Height <= Pos32 (Mode.V_Visible)
567 is
568 -- Force 1:1 mapping of panel fitter:pipe
569 PF_Ctrl_Pipe_Sel : constant Word32 :=
570 (if Config.Has_PF_Pipe_Select then
571 (case Controller.PF_CTRL is
572 when Registers.PFA_CTL_1 => 0 * 2 ** 29,
573 when Registers.PFB_CTL_1 => 1 * 2 ** 29,
574 when Registers.PFC_CTL_1 => 2 * 2 ** 29,
575 when others => 0) else 0);
576
577 Width, Height : Pos32;
578 begin
579 -- Writes to WIN_SZ arm the PF registers.
580
581 Scale_Keep_Aspect
582 (Width => Width,
583 Height => Height,
584 Max_Width => Pos32 (Mode.H_Visible),
585 Max_Height => Pos32 (Mode.V_Visible),
586 Framebuffer => Framebuffer);
587
588 Registers.Write
589 (Register => Controller.PF_CTRL,
590 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_CTRL_FILTER_MED);
591 Registers.Write
592 (Register => Controller.PF_WIN_POS,
593 Value =>
594 Shift_Left (Word32 (Pos32 (Mode.H_Visible) - Width) / 2, 16) or
595 Word32 (Pos32 (Mode.V_Visible) - Height) / 2);
596 Registers.Write
597 (Register => Controller.PF_WIN_SZ,
598 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
599 end Setup_Ironlake_Panel_Fitter;
600
601 procedure Setup_Scaling
602 (Controller : in Controller_Type;
603 Mode : in HW.GFX.Mode_Type;
604 Framebuffer : in HW.GFX.Framebuffer_Type)
605 with
606 Pre =>
607 Framebuffer.Width <= Pos32 (Mode.H_Visible) and
608 Framebuffer.Height <= Pos32 (Mode.V_Visible)
609 is
610 begin
611 if Framebuffer.Width /= Pos32 (Mode.H_Visible) or
612 Framebuffer.Height /= Pos32 (Mode.V_Visible)
613 then
614 if Config.Has_Plane_Control then
615 Setup_Skylake_Pipe_Scaler (Controller, Mode, Framebuffer);
616 else
617 Setup_Ironlake_Panel_Fitter (Controller, Mode, Framebuffer);
618 end if;
619 end if;
620 end Setup_Scaling;
621
622 ----------------------------------------------------------------------------
623
Nico Huber83693c82016-10-08 22:17:55 +0200624 procedure Setup_Head
625 (Controller : Controller_Type;
626 Head : Head_Type;
627 Port_Cfg : Port_Config;
628 Framebuffer : Framebuffer_Type)
629 is
630 PIPECONF_Options : Word32 := 0;
631 begin
632 if Config.Has_Pipe_DDI_Func then
633 Registers.Write
634 (Register => Head.PIPE_DDI_FUNC_CTL,
635 Value => PIPE_DDI_FUNC_CTL_ENABLE or
636 PIPE_DDI_FUNC_CTL_DDI_SELECT (Port_Cfg.Port) or
637 PIPE_DDI_FUNC_CTL_MODE_SELECT (Port_Cfg.Display) or
638 PIPE_DDI_FUNC_CTL_BPC (Port_Cfg.Mode.BPC) or
639 PIPE_DDI_FUNC_CTL_VSYNC (Port_Cfg.Mode.V_Sync_Active_High) or
640 PIPE_DDI_FUNC_CTL_HSYNC (Port_Cfg.Mode.H_Sync_Active_High) or
Nico Huberf3e23662016-12-05 21:33:03 +0100641 PIPE_DDI_FUNC_CTL_EDP_SELECT (Controller.Pipe) or
Nico Huber83693c82016-10-08 22:17:55 +0200642 PIPE_DDI_FUNC_CTL_PORT_WIDTH (Port_Cfg.DP.Lane_Count));
643 end if;
644
645 if Config.Has_Pipeconf_BPC then
646 PIPECONF_Options := PIPECONF_BPC_MAP (Port_Cfg.Mode.BPC);
647 end if;
648
649 -- Enable dithering if framebuffer BPC differs from connector BPC,
650 -- as smooth gradients look really bad without
651 if Framebuffer.BPC /= Port_Cfg.Mode.BPC then
652 PIPECONF_Options := PIPECONF_Options or PIPECONF_ENABLE_DITHER;
653 end if;
654
655 if not Config.Has_Pipeconf_Misc then
656 Registers.Write
657 (Register => Head.PIPECONF,
658 Value => PIPECONF_ENABLE or PIPECONF_Options);
659 else
660 Registers.Write
661 (Register => Controller.PIPEMISC,
662 Value => PIPECONF_Options);
663 Registers.Write
664 (Register => Head.PIPECONF,
665 Value => PIPECONF_ENABLE);
666 end if;
667 Registers.Posting_Read (Head.PIPECONF);
668 end Setup_Head;
669
670 ----------------------------------------------------------------------------
671
672 procedure On
Nico Huberf3e23662016-12-05 21:33:03 +0100673 (Pipe : Pipe_Index;
Nico Huber83693c82016-10-08 22:17:55 +0200674 Port_Cfg : Port_Config;
675 Framebuffer : Framebuffer_Type)
676 is
Nico Huberf3e23662016-12-05 21:33:03 +0100677 Head : constant Pipe_Head := Get_Pipe_Head (Pipe, Port_Cfg.Port);
Nico Huber83693c82016-10-08 22:17:55 +0200678 begin
679 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
680
681 if Config.Has_Trans_Clk_Sel then
682 Registers.Write
Nico Huberf3e23662016-12-05 21:33:03 +0100683 (Register => Controllers (Pipe).TRANS_CLK_SEL,
Nico Huber83693c82016-10-08 22:17:55 +0200684 Value => TRANS_CLK_SEL_PORT (Port_Cfg.Port));
685 end if;
686
687 if Port_Cfg.Is_FDI then
Nico Huberf3e23662016-12-05 21:33:03 +0100688 Setup_Link (Heads (Head), Port_Cfg.FDI, Port_Cfg.Mode);
Nico Huber83693c82016-10-08 22:17:55 +0200689 elsif Port_Cfg.Display = DP then
Nico Huberf3e23662016-12-05 21:33:03 +0100690 Setup_Link (Heads (Head), Port_Cfg.DP, Port_Cfg.Mode);
Nico Huber83693c82016-10-08 22:17:55 +0200691 end if;
692
Nico Huberf3e23662016-12-05 21:33:03 +0100693 Setup_Display
694 (Controllers (Pipe), Heads (Head), Port_Cfg.Mode, Framebuffer);
Nico Huber83693c82016-10-08 22:17:55 +0200695
Nico Huberf3e23662016-12-05 21:33:03 +0100696 Setup_Scaling (Controllers (Pipe), Port_Cfg.Mode, Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100697
Nico Huberf3e23662016-12-05 21:33:03 +0100698 Setup_Head (Controllers (Pipe), Heads (Head), Port_Cfg, Framebuffer);
Nico Huber83693c82016-10-08 22:17:55 +0200699 end On;
700
701 ----------------------------------------------------------------------------
702
703 procedure Planes_Off (Controller : Controller_Type) is
704 begin
705 Registers.Unset_Mask (Controller.SPCNTR, SPCNTR_ENABLE);
706 if Config.Has_Plane_Control then
707 Clear_Watermarks (Controller);
708 Registers.Unset_Mask (Controller.PLANE_CTL, PLANE_CTL_PLANE_ENABLE);
709 Registers.Write (Controller.PLANE_SURF, 16#0000_0000#);
710 else
711 Registers.Unset_Mask (Controller.DSPCNTR, DSPCNTR_ENABLE);
712 end if;
713 end Planes_Off;
714
715 procedure Head_Off (Head : Head_Type)
716 is
717 Enabled : Boolean;
718 begin
719 Registers.Is_Set_Mask (Head.PIPECONF, PIPECONF_ENABLE, Enabled);
720
721 if Enabled then
722 Registers.Unset_Mask (Head.PIPECONF, PIPECONF_ENABLE);
723 end if;
724
725 -- Workaround for Broadwell:
726 -- Status may be wrong if pipe hasn't been enabled since reset.
727 if not Config.Pipe_Enabled_Workaround or else Enabled then
728 -- synchronously wait until pipe is truly off
729 Registers.Wait_Unset_Mask
730 (Register => Head.PIPECONF,
731 Mask => PIPECONF_ENABLED_STATUS,
732 TOut_MS => 40);
733 end if;
734
735 if Config.Has_Pipe_DDI_Func then
736 Registers.Write (Head.PIPE_DDI_FUNC_CTL, 0);
737 end if;
738 end Head_Off;
739
740 procedure Panel_Fitter_Off (Controller : Controller_Type) is
741 begin
742 -- Writes to WIN_SZ arm the PS/PF registers.
743 if Config.Has_Plane_Control then
744 Registers.Unset_Mask (Controller.PS_CTRL_1, PS_CTRL_ENABLE_SCALER);
745 Registers.Write (Controller.PS_WIN_SZ_1, 16#0000_0000#);
746 if Controller.PS_CTRL_2 /= Registers.Invalid_Register and
747 Controller.PS_WIN_SZ_2 /= Registers.Invalid_Register
748 then
749 Registers.Unset_Mask (Controller.PS_CTRL_2, PS_CTRL_ENABLE_SCALER);
750 Registers.Write (Controller.PS_WIN_SZ_2, 16#0000_0000#);
751 end if;
752 else
Nico Huber4916e342016-11-04 14:37:53 +0100753 Registers.Unset_Mask (Controller.PF_CTRL, PF_CTRL_ENABLE);
Nico Huber83693c82016-10-08 22:17:55 +0200754 Registers.Write (Controller.PF_WIN_SZ, 16#0000_0000#);
755 end if;
756 end Panel_Fitter_Off;
757
758 procedure Trans_Clk_Off (Controller : Controller_Type) is
759 begin
760 if Config.Has_Trans_Clk_Sel then
761 Registers.Write (Controller.TRANS_CLK_SEL, TRANS_CLK_SEL_PORT_NONE);
762 end if;
763 end Trans_Clk_Off;
764
Nico Huberf3e23662016-12-05 21:33:03 +0100765 procedure Off (Pipe : Pipe_Index; Port_Cfg : Port_Config)
766 is
Nico Huber83693c82016-10-08 22:17:55 +0200767 begin
768 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
769
Nico Huberf3e23662016-12-05 21:33:03 +0100770 Planes_Off (Controllers (Pipe));
771 Head_Off (Heads (Get_Pipe_Head (Pipe, Port_Cfg.Port)));
772 Panel_Fitter_Off (Controllers (Pipe));
773 Trans_Clk_Off (Controllers (Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200774 end Off;
775
776 procedure All_Off
777 is
778 EDP_Enabled, EDP_Piped : Boolean;
779
Nico Huberf3e23662016-12-05 21:33:03 +0100780 procedure EDP_Piped_To (Pipe : Pipe_Index; Piped_To : out Boolean)
Nico Huber83693c82016-10-08 22:17:55 +0200781 is
782 Pipe_DDI_Func_Ctl : Word32;
783 begin
784 Registers.Read (Registers.PIPE_EDP_DDI_FUNC_CTL, Pipe_DDI_Func_Ctl);
785 Pipe_DDI_Func_Ctl :=
786 Pipe_DDI_Func_Ctl and PIPE_DDI_FUNC_CTL_EDP_SELECT_MASK;
787
Nico Huberf3e23662016-12-05 21:33:03 +0100788 Piped_To :=
789 (Pipe = Primary and
790 Pipe_DDI_Func_Ctl = PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON) or
791 Pipe_DDI_Func_Ctl = PIPE_DDI_FUNC_CTL_EDP_SELECT_ONOFF (Pipe);
Nico Huber83693c82016-10-08 22:17:55 +0200792 end EDP_Piped_To;
793 begin
794 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
795
796 if Config.Has_EDP_Pipe then
797 Registers.Is_Set_Mask
798 (Registers.PIPE_EDP_CONF, PIPECONF_ENABLE, EDP_Enabled);
799 else
800 EDP_Enabled := False;
801 end if;
802
Nico Huberf3e23662016-12-05 21:33:03 +0100803 for Pipe in Pipe_Index loop
804 Planes_Off (Controllers (Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200805 if EDP_Enabled then
Nico Huberf3e23662016-12-05 21:33:03 +0100806 EDP_Piped_To (Pipe, EDP_Piped);
Nico Huber83693c82016-10-08 22:17:55 +0200807 if EDP_Piped then
808 Head_Off (Heads (Head_EDP));
809 EDP_Enabled := False;
810 end if;
811 end if;
Nico Huberf3e23662016-12-05 21:33:03 +0100812 Head_Off (Heads (Default_Pipe_Head (Pipe)));
813 Panel_Fitter_Off (Controllers (Pipe));
814 Trans_Clk_Off (Controllers (Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200815 end loop;
816
817 if EDP_Enabled then
818 Head_Off (Heads (Head_EDP));
819 end if;
820 end All_Off;
821
822 ----------------------------------------------------------------------------
823
Nico Huberf3e23662016-12-05 21:33:03 +0100824 procedure Update_Offset (Pipe : Pipe_Index; Framebuffer : Framebuffer_Type)
825 is
Nico Huber83693c82016-10-08 22:17:55 +0200826 begin
827 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
828
Nico Huberf3e23662016-12-05 21:33:03 +0100829 Registers.Write
830 (Controllers (Pipe).DSPSURF, Framebuffer.Offset and 16#ffff_f000#);
Nico Huber83693c82016-10-08 22:17:55 +0200831 end Update_Offset;
832
833 ----------------------------------------------------------------------------
834
Nico Huberf3e23662016-12-05 21:33:03 +0100835 function Get_Pipe_Hint (Pipe : Pipe_Index) return Word32
Nico Huber83693c82016-10-08 22:17:55 +0200836 is
Nico Huber83693c82016-10-08 22:17:55 +0200837 begin
Nico Huberf3e23662016-12-05 21:33:03 +0100838 return
839 (case Pipe is
840 when Primary => 0,
841 when Secondary => 1,
842 when Tertiary => 2);
Nico Huber83693c82016-10-08 22:17:55 +0200843 end Get_Pipe_Hint;
844
Nico Huber83693c82016-10-08 22:17:55 +0200845end HW.GFX.GMA.Pipe_Setup;