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