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