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