blob: 40b31c896beb11f23c237a592fe7d1d87914c6fa [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
2-- Copyright (C) 2015-2016 secunet Security Networks AG
3--
4-- This program is free software; you can redistribute it and/or modify
5-- it under the terms of the GNU General Public License as published by
Nico Huber125a29e2016-10-18 00:23:54 +02006-- the Free Software Foundation; either version 2 of the License, or
7-- (at your option) any later version.
Nico Huber83693c82016-10-08 22:17:55 +02008--
9-- This program is distributed in the hope that it will be useful,
10-- but WITHOUT ANY WARRANTY; without even the implied warranty of
11-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12-- GNU General Public License for more details.
13--
14
15with HW.Debug;
16with GNAT.Source_Info;
17
18with HW.GFX.GMA.Config;
19with HW.GFX.GMA.DP_Info;
20with HW.GFX.GMA.Registers;
21
22use type HW.Word64;
23use type HW.Pos16;
Nico Huber83693c82016-10-08 22:17:55 +020024use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
25
26package body HW.GFX.GMA.Pipe_Setup is
27
Nico Huberf3e23662016-12-05 21:33:03 +010028 type Default_Head_Array is array (Pipe_Index) of Pipe_Head;
29 Default_Pipe_Head : constant Default_Head_Array :=
30 (Primary => Head_A,
31 Secondary => Head_B,
32 Tertiary => Head_C);
33
34 function Get_Pipe_Head (Pipe : Pipe_Index; Port : GPU_Port) return Pipe_Head
35 is
36 begin
37 return
38 (if Config.Has_EDP_Pipe and then Port = DIGI_A then
39 Head_EDP
40 else
41 Default_Pipe_Head (Pipe));
42 end Get_Pipe_Head;
43
44 ----------------------------------------------------------------------------
45
Nico Huberfbb42202016-11-07 15:08:26 +010046 ILK_DISPLAY_CHICKEN1_VGA_MASK : constant := 7 * 2 ** 29;
47 ILK_DISPLAY_CHICKEN1_VGA_ENABLE : constant := 5 * 2 ** 29;
48 ILK_DISPLAY_CHICKEN2_VGA_MASK : constant := 1 * 2 ** 25;
49 ILK_DISPLAY_CHICKEN2_VGA_ENABLE : constant := 0 * 2 ** 25;
50
Nico Huber83693c82016-10-08 22:17:55 +020051 DSPCNTR_ENABLE : constant := 1 * 2 ** 31;
52 DSPCNTR_GAMMA_CORRECTION : constant := 1 * 2 ** 30;
53 DSPCNTR_DISABLE_TRICKLE_FEED : constant := 1 * 2 ** 14;
54 DSPCNTR_FORMAT_MASK : constant := 15 * 2 ** 26;
55
56 DSPCNTR_MASK : constant Word32 :=
57 DSPCNTR_ENABLE or
58 DSPCNTR_GAMMA_CORRECTION or
59 DSPCNTR_FORMAT_MASK or
60 DSPCNTR_DISABLE_TRICKLE_FEED;
61
62 PLANE_CTL_PLANE_ENABLE : constant := 1 * 2 ** 31;
63 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 : constant := 4 * 2 ** 24;
64 PLANE_CTL_PLANE_GAMMA_DISABLE : constant := 1 * 2 ** 13;
65
66 PLANE_WM_ENABLE : constant := 1 * 2 ** 31;
67 PLANE_WM_LINES_SHIFT : constant := 14;
68 PLANE_WM_LINES_MASK : constant := 16#001f# * 2 ** 14;
69 PLANE_WM_BLOCKS_MASK : constant := 16#03ff# * 2 ** 0;
70
71 SPCNTR_ENABLE : constant := 1 * 2 ** 31;
72
Nico Huber33912aa2016-12-06 20:36:23 +010073 VGA_SR_INDEX : constant := 16#03c4#;
74 VGA_SR_DATA : constant := 16#03c5#;
75 VGA_SR01 : constant := 16#01#;
76 VGA_SR01_SCREEN_OFF : constant := 1 * 2 ** 5;
Nico Huber3675db52016-11-04 16:27:29 +010077
78 VGA_CONTROL_VGA_DISPLAY_DISABLE : constant := 1 * 2 ** 31;
79 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK : constant := 16#0003# * 2 ** 6;
80 VGA_CONTROL_BLINK_DUTY_CYCLE_50 : constant := 2 * 2 ** 6;
81 VGA_CONTROL_VSYNC_BLINK_RATE_MASK : constant := 16#003f# * 2 ** 0;
82
83 subtype VGA_Cycle_Count is Pos32 range 2 .. 128;
84 function VGA_CONTROL_VSYNC_BLINK_RATE
85 (Cycles : VGA_Cycle_Count)
86 return Word32
87 is
88 begin
89 return Word32 (Cycles) / 2 - 1;
90 end VGA_CONTROL_VSYNC_BLINK_RATE;
91
Nico Huber83693c82016-10-08 22:17:55 +020092 TRANS_CLK_SEL_PORT_NONE : constant := 0 * 2 ** 29;
93
94 type TRANS_CLK_SEL_PORT_Array is
95 array (Digital_Port) of Word32;
96 TRANS_CLK_SEL_PORT : constant TRANS_CLK_SEL_PORT_Array :=
97 TRANS_CLK_SEL_PORT_Array'
98 (DIGI_A => 0 * 2 ** 29, -- DDI A is not selectable
99 DIGI_B => 2 * 2 ** 29,
100 DIGI_C => 3 * 2 ** 29,
101 DIGI_D => 4 * 2 ** 29,
102 DIGI_E => 5 * 2 ** 29);
103
104 PIPECONF_ENABLE : constant := 1 * 2 ** 31;
105 PIPECONF_ENABLED_STATUS : constant := 1 * 2 ** 30;
106 PIPECONF_ENABLE_DITHER : constant := 1 * 2 ** 4;
107 PIPECONF_DITHER_TEMPORAL : constant := 1 * 2 ** 2;
108
Nico Huber113a14b2016-12-06 21:59:15 +0100109 function PIPECONF_BPC (Bits_Per_Color : BPC_Type) return Word32
110 with
111 Pre => True
112 is
113 begin
114 return
115 (case Bits_Per_Color is
116 when 6 => 2 * 2 ** 5,
117 when 10 => 1 * 2 ** 5,
118 when 12 => 3 * 2 ** 5,
119 when others => 0 * 2 ** 5);
120 end PIPECONF_BPC;
121
122 function PIPECONF_Misc (BPC : BPC_Type; Dither : Boolean) return Word32
123 with
124 Pre => True
125 is
126 begin
127 return
128 (if Config.Has_Pipeconf_BPC then PIPECONF_BPC (BPC) else 0) or
129 (if Dither then PIPECONF_ENABLE_DITHER else 0);
130 end PIPECONF_Misc;
131
Nico Huber4916e342016-11-04 14:37:53 +0100132 PF_CTRL_ENABLE : constant := 1 * 2 ** 31;
133 PF_CTRL_PIPE_SELECT_MASK : constant := 3 * 2 ** 29;
134 PF_CTRL_FILTER_MED : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200135
Nico Huber4916e342016-11-04 14:37:53 +0100136 PS_CTRL_ENABLE_SCALER : constant := 1 * 2 ** 31;
137 PS_CTRL_SCALER_MODE_7X5_EXTENDED : constant := 1 * 2 ** 28;
138 PS_CTRL_FILTER_SELECT_MEDIUM_2 : constant := 1 * 2 ** 23;
Nico Huber83693c82016-10-08 22:17:55 +0200139
140 PIPE_DDI_FUNC_CTL_ENABLE : constant := 1 * 2 ** 31;
141 PIPE_DDI_FUNC_CTL_DDI_SELECT_MASK : constant := 7 * 2 ** 28;
142 PIPE_DDI_FUNC_CTL_DDI_SELECT_NONE : constant := 0 * 2 ** 28;
143 PIPE_DDI_FUNC_CTL_DDI_SELECT_B : constant := 1 * 2 ** 28;
144 PIPE_DDI_FUNC_CTL_DDI_SELECT_C : constant := 2 * 2 ** 28;
145 PIPE_DDI_FUNC_CTL_DDI_SELECT_D : constant := 3 * 2 ** 28;
146 PIPE_DDI_FUNC_CTL_DDI_SELECT_E : constant := 4 * 2 ** 28;
147 PIPE_DDI_FUNC_CTL_MODE_SELECT_MASK : constant := 7 * 2 ** 24;
148 PIPE_DDI_FUNC_CTL_MODE_SELECT_HDMI : constant := 0 * 2 ** 24;
149 PIPE_DDI_FUNC_CTL_MODE_SELECT_DVI : constant := 1 * 2 ** 24;
150 PIPE_DDI_FUNC_CTL_MODE_SELECT_DP_SST : constant := 2 * 2 ** 24;
151 PIPE_DDI_FUNC_CTL_MODE_SELECT_DP_MST : constant := 3 * 2 ** 24;
152 PIPE_DDI_FUNC_CTL_MODE_SELECT_FDI : constant := 4 * 2 ** 24;
153 PIPE_DDI_FUNC_CTL_BPC_MASK : constant := 7 * 2 ** 20;
154 PIPE_DDI_FUNC_CTL_BPC_8BITS : constant := 0 * 2 ** 20;
155 PIPE_DDI_FUNC_CTL_BPC_10BITS : constant := 1 * 2 ** 20;
156 PIPE_DDI_FUNC_CTL_BPC_6BITS : constant := 2 * 2 ** 20;
157 PIPE_DDI_FUNC_CTL_BPC_12BITS : constant := 3 * 2 ** 20;
158 PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_LOW : constant := 0 * 2 ** 17;
159 PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 17;
160 PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_LOW : constant := 0 * 2 ** 16;
161 PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 16;
162 PIPE_DDI_FUNC_CTL_EDP_SELECT_MASK : constant := 7 * 2 ** 12;
163 PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON : constant := 0 * 2 ** 12;
164 PIPE_DDI_FUNC_CTL_EDP_SELECT_A : constant := 4 * 2 ** 12;
165 PIPE_DDI_FUNC_CTL_EDP_SELECT_B : constant := 5 * 2 ** 12;
166 PIPE_DDI_FUNC_CTL_EDP_SELECT_C : constant := 6 * 2 ** 12;
167 PIPE_DDI_FUNC_CTL_DP_VC_PAYLOAD_ALLOC : constant := 1 * 2 ** 8;
168 PIPE_DDI_FUNC_CTL_BFI_ENABLE : constant := 1 * 2 ** 4;
169 PIPE_DDI_FUNC_CTL_PORT_WIDTH_MASK : constant := 7 * 2 ** 1;
170 PIPE_DDI_FUNC_CTL_PORT_WIDTH_1_LANE : constant := 0 * 2 ** 1;
171 PIPE_DDI_FUNC_CTL_PORT_WIDTH_2_LANES : constant := 1 * 2 ** 1;
172 PIPE_DDI_FUNC_CTL_PORT_WIDTH_4_LANES : constant := 3 * 2 ** 1;
173
174 type DDI_Select_Array is array (Digital_Port) of Word32;
175 PIPE_DDI_FUNC_CTL_DDI_SELECT : constant DDI_Select_Array :=
176 DDI_Select_Array'
177 (DIGI_A => PIPE_DDI_FUNC_CTL_DDI_SELECT_NONE,
178 DIGI_B => PIPE_DDI_FUNC_CTL_DDI_SELECT_B,
179 DIGI_C => PIPE_DDI_FUNC_CTL_DDI_SELECT_C,
180 DIGI_D => PIPE_DDI_FUNC_CTL_DDI_SELECT_D,
181 DIGI_E => PIPE_DDI_FUNC_CTL_DDI_SELECT_E);
182
183 type DDI_Mode_Array is array (Display_Type) of Word32;
184 PIPE_DDI_FUNC_CTL_MODE_SELECT : constant DDI_Mode_Array :=
185 DDI_Mode_Array'
186 (VGA => PIPE_DDI_FUNC_CTL_MODE_SELECT_FDI,
187 HDMI => PIPE_DDI_FUNC_CTL_MODE_SELECT_DVI,
188 DP => PIPE_DDI_FUNC_CTL_MODE_SELECT_DP_SST,
189 others => 0);
190
191 type HV_Sync_Array is array (Boolean) of Word32;
192 PIPE_DDI_FUNC_CTL_VSYNC : constant HV_Sync_Array := HV_Sync_Array'
193 (False => PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_LOW,
194 True => PIPE_DDI_FUNC_CTL_VSYNC_ACTIVE_HIGH);
195 PIPE_DDI_FUNC_CTL_HSYNC : constant HV_Sync_Array := HV_Sync_Array'
196 (False => PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_LOW,
197 True => PIPE_DDI_FUNC_CTL_HSYNC_ACTIVE_HIGH);
198
Nico Huberf3e23662016-12-05 21:33:03 +0100199 type EDP_Select_Array is array (Pipe_Index) of Word32;
Nico Huber83693c82016-10-08 22:17:55 +0200200 PIPE_DDI_FUNC_CTL_EDP_SELECT : constant EDP_Select_Array :=
Nico Huberf3e23662016-12-05 21:33:03 +0100201 (Primary => PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON, -- we never use
202 -- panel fitter
203 Secondary => PIPE_DDI_FUNC_CTL_EDP_SELECT_B,
204 Tertiary => PIPE_DDI_FUNC_CTL_EDP_SELECT_C);
Nico Huber83693c82016-10-08 22:17:55 +0200205 PIPE_DDI_FUNC_CTL_EDP_SELECT_ONOFF : constant EDP_Select_Array :=
Nico Huberf3e23662016-12-05 21:33:03 +0100206 (Primary => PIPE_DDI_FUNC_CTL_EDP_SELECT_A,
207 Secondary => PIPE_DDI_FUNC_CTL_EDP_SELECT_B,
208 Tertiary => PIPE_DDI_FUNC_CTL_EDP_SELECT_C);
Nico Huber83693c82016-10-08 22:17:55 +0200209
210 type Port_Width_Array is array (HW.GFX.DP_Lane_Count) of Word32;
211 PIPE_DDI_FUNC_CTL_PORT_WIDTH : constant Port_Width_Array :=
212 Port_Width_Array'
213 (HW.GFX.DP_Lane_Count_1 => PIPE_DDI_FUNC_CTL_PORT_WIDTH_1_LANE,
214 HW.GFX.DP_Lane_Count_2 => PIPE_DDI_FUNC_CTL_PORT_WIDTH_2_LANES,
215 HW.GFX.DP_Lane_Count_4 => PIPE_DDI_FUNC_CTL_PORT_WIDTH_4_LANES);
216
217 function PIPE_DDI_FUNC_CTL_BPC (BPC : HW.GFX.BPC_Type) return Word32
218 is
219 Result : Word32;
220 begin
221 case BPC is
222 when 6 => Result := PIPE_DDI_FUNC_CTL_BPC_6BITS;
223 when 8 => Result := PIPE_DDI_FUNC_CTL_BPC_8BITS;
224 when 10 => Result := PIPE_DDI_FUNC_CTL_BPC_10BITS;
225 when 12 => Result := PIPE_DDI_FUNC_CTL_BPC_12BITS;
226 when others => Result := PIPE_DDI_FUNC_CTL_BPC_8BITS;
227 end case;
228 return Result;
229 end PIPE_DDI_FUNC_CTL_BPC;
230
231 function PIPE_DATA_M_TU (Transfer_Unit : Positive) return Word32 is
232 begin
233 return Shift_Left (Word32 (Transfer_Unit - 1), 25);
234 end PIPE_DATA_M_TU;
235
236 PIPE_MSA_MISC_SYNC_CLK : constant := 1 * 2 ** 0;
237 PIPE_MSA_MISC_BPC_6BITS : constant := 0 * 2 ** 5;
238 PIPE_MSA_MISC_BPC_8BITS : constant := 1 * 2 ** 5;
239 PIPE_MSA_MISC_BPC_10BITS : constant := 2 * 2 ** 5;
240 PIPE_MSA_MISC_BPC_12BITS : constant := 3 * 2 ** 5;
241 PIPE_MSA_MISC_BPC_16BITS : constant := 4 * 2 ** 5;
242
243 function PIPE_MSA_MISC_BPC (BPC : HW.GFX.BPC_Type) return Word32 is
244 Result : Word32;
245 begin
246 case BPC is
247 when 6 => Result := PIPE_MSA_MISC_BPC_6BITS;
248 when 8 => Result := PIPE_MSA_MISC_BPC_8BITS;
249 when 10 => Result := PIPE_MSA_MISC_BPC_10BITS;
250 when 12 => Result := PIPE_MSA_MISC_BPC_12BITS;
251 --when 16 => Result := PIPE_MSA_MISC_BPC_16BITS;
252 when others => Result := PIPE_MSA_MISC_BPC_8BITS;
253 end case;
254 return Result;
255 end PIPE_MSA_MISC_BPC;
256
257 ---------------------------------------------------------------------------
258
Nico Huber83693c82016-10-08 22:17:55 +0200259 function PLANE_WM_LINES (Lines : Natural) return Word32 is
260 begin
261 return Shift_Left (Word32 (Lines), PLANE_WM_LINES_SHIFT)
262 and PLANE_WM_LINES_MASK;
263 end PLANE_WM_LINES;
264
265 function PLANE_WM_BLOCKS (Blocks : Natural) return Word32 is
266 begin
267 return Word32 (Blocks) and PLANE_WM_BLOCKS_MASK;
268 end PLANE_WM_BLOCKS;
269
270 ---------------------------------------------------------------------------
271
272 function Encode (LSW, MSW : Pos16) return Word32 is
273 begin
274 return Shift_Left (Word32 (MSW - 1), 16) or Word32 (LSW - 1);
275 end Encode;
276
277 ----------------------------------------------------------------------------
278
279 procedure Setup_Link
280 (Head : Head_Type;
281 Link : DP_Link;
282 Mode : Mode_Type)
283 with
284 Global => (In_Out => Registers.Register_State),
285 Depends => (Registers.Register_State =>+ (Head, Link, Mode))
286 is
287 Data_M, Link_M : DP_Info.M_Type;
288 Data_N, Link_N : DP_Info.N_Type;
289 begin
290 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
291
292 DP_Info.Calculate_M_N
293 (Link => Link,
294 Mode => Mode,
295 Data_M => Data_M,
296 Data_N => Data_N,
297 Link_M => Link_M,
298 Link_N => Link_N);
299
300 Registers.Write
301 (Register => Head.PIPE_DATA_M1,
302 Value => PIPE_DATA_M_TU (64) or
303 Word32 (Data_M));
304 Registers.Write
305 (Register => Head.PIPE_DATA_N1,
306 Value => Word32 (Data_N));
307
308 Registers.Write
309 (Register => Head.PIPE_LINK_M1,
310 Value => Word32 (Link_M));
311 Registers.Write
312 (Register => Head.PIPE_LINK_N1,
313 Value => Word32 (Link_N));
314
315 if Config.Has_Pipe_MSA_Misc then
316 Registers.Write
317 (Register => Head.PIPE_MSA_MISC,
318 Value => PIPE_MSA_MISC_SYNC_CLK or
319 PIPE_MSA_MISC_BPC (Mode.BPC));
320 end if;
321 end Setup_Link;
322
323 ----------------------------------------------------------------------------
324
325 procedure Clear_Watermarks (Controller : Controller_Type) is
326 begin
327 Registers.Write
328 (Register => Controller.PLANE_BUF_CFG,
329 Value => 16#0000_0000#);
330 for Level in WM_Levels range 0 .. WM_Levels'Last loop
331 Registers.Write
332 (Register => Controller.PLANE_WM (Level),
333 Value => 16#0000_0000#);
334 end loop;
335 Registers.Write
336 (Register => Controller.WM_LINETIME,
337 Value => 16#0000_0000#);
338 end Clear_Watermarks;
339
340 procedure Setup_Watermarks (Controller : Controller_Type)
341 is
Nico Huberf3e23662016-12-05 21:33:03 +0100342 type Per_Plane_Buffer_Range is array (Pipe_Index) of Word32;
343 Buffer_Range : constant Per_Plane_Buffer_Range :=
344 (Primary => Shift_Left (159, 16) or 0,
345 Secondary => Shift_Left (319, 16) or 160,
346 Tertiary => Shift_Left (479, 16) or 320);
Nico Huber83693c82016-10-08 22:17:55 +0200347 begin
348 Registers.Write
349 (Register => Controller.PLANE_BUF_CFG,
Nico Huberf3e23662016-12-05 21:33:03 +0100350 Value => Buffer_Range (Controller.Pipe));
Nico Huber83693c82016-10-08 22:17:55 +0200351 Registers.Write
352 (Register => Controller.PLANE_WM (0),
353 Value => PLANE_WM_ENABLE or
354 PLANE_WM_LINES (2) or
355 PLANE_WM_BLOCKS (160));
356 end Setup_Watermarks;
357
358 ----------------------------------------------------------------------------
359
Nico Huber3675db52016-11-04 16:27:29 +0100360 procedure Setup_Hires_Plane
Nico Huber6a4dfc82016-11-04 15:50:58 +0100361 (Controller : Controller_Type;
362 Framebuffer : HW.GFX.Framebuffer_Type)
Nico Huber83693c82016-10-08 22:17:55 +0200363 with
364 Global => (In_Out => Registers.Register_State),
365 Depends =>
366 (Registers.Register_State
367 =>+
368 (Registers.Register_State,
369 Controller,
Nico Huber83693c82016-10-08 22:17:55 +0200370 Framebuffer))
371 is
372 -- FIXME: setup correct format, based on framebuffer RGB format
373 Format : constant Word32 := 6 * 2 ** 26;
374 PRI : Word32 := DSPCNTR_ENABLE or Format;
375
376 function To_Bytes (Pixels : Width_Type) return Word32
377 with
378 Pre => (Word32 (Pixels) <= Word32'Last / 4 / Word32 (BPC_Type'Last) * 8)
379 is
380 begin
381 return Word32 (Pos64 (Pixels) * 4 * Framebuffer.BPC / 8);
382 end To_Bytes;
383 begin
384 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
385
Nico Huber83693c82016-10-08 22:17:55 +0200386 if Config.Has_Plane_Control then
Nico Huber83693c82016-10-08 22:17:55 +0200387 Registers.Write
388 (Register => Controller.PLANE_CTL,
389 Value => PLANE_CTL_PLANE_ENABLE or
390 PLANE_CTL_SRC_PIX_FMT_RGB_32B_8888 or
391 PLANE_CTL_PLANE_GAMMA_DISABLE);
392 Registers.Write (Controller.PLANE_OFFSET, 16#0000_0000#);
Nico Huber6a4dfc82016-11-04 15:50:58 +0100393 Registers.Write
394 (Controller.PLANE_SIZE,
395 Encode (Pos16 (Framebuffer.Width), Pos16 (Framebuffer.Height)));
Nico Huber83693c82016-10-08 22:17:55 +0200396 Registers.Write (Controller.PLANE_STRIDE, To_Bytes (Framebuffer.Stride) / 64);
397 Registers.Write (Controller.PLANE_POS, 16#0000_0000#);
398 Registers.Write (Controller.PLANE_SURF, Framebuffer.Offset and 16#ffff_f000#);
399 else
400 if Config.Disable_Trickle_Feed then
401 PRI := PRI or DSPCNTR_DISABLE_TRICKLE_FEED;
402 end if;
403 -- for now, just disable gamma LUT (can't do anything
404 -- useful without colorimetry information from display)
405 Registers.Unset_And_Set_Mask
406 (Register => Controller.DSPCNTR,
407 Mask_Unset => DSPCNTR_MASK,
408 Mask_Set => PRI);
409
410 Registers.Write (Controller.DSPSTRIDE, To_Bytes (Framebuffer.Stride));
411 Registers.Write (Controller.DSPSURF, Framebuffer.Offset and 16#ffff_f000#);
412 if Config.Has_DSP_Linoff then
413 Registers.Write (Controller.DSPLINOFF, 0);
414 end if;
415 Registers.Write (Controller.DSPTILEOFF, 0);
416 end if;
Nico Huber3675db52016-11-04 16:27:29 +0100417 end Setup_Hires_Plane;
418
419 procedure Setup_Display
Nico Huber113a14b2016-12-06 21:59:15 +0100420 (Controller : Controller_Type;
421 Framebuffer : Framebuffer_Type;
422 Dither_BPC : BPC_Type;
423 Dither : Boolean)
Nico Huber3675db52016-11-04 16:27:29 +0100424 with
425 Global => (In_Out => (Registers.Register_State, Port_IO.State)),
426 Depends =>
427 (Registers.Register_State
428 =>+
429 (Registers.Register_State,
430 Controller,
Nico Huber113a14b2016-12-06 21:59:15 +0100431 Framebuffer,
432 Dither_BPC,
433 Dither),
Nico Huber3675db52016-11-04 16:27:29 +0100434 Port_IO.State
435 =>+
436 (Framebuffer))
437 is
438 use type Word8;
439
440 Reg8 : Word8;
441 begin
442 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
443
444 if Config.Has_Plane_Control then
445 Setup_Watermarks (Controller);
446 end if;
447
448 if Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET then
Nico Huberfbb42202016-11-07 15:08:26 +0100449 if Config.VGA_Plane_Workaround then
450 Registers.Unset_And_Set_Mask
451 (Register => Registers.ILK_DISPLAY_CHICKEN1,
452 Mask_Unset => ILK_DISPLAY_CHICKEN1_VGA_MASK,
453 Mask_Set => ILK_DISPLAY_CHICKEN1_VGA_ENABLE);
454 Registers.Unset_And_Set_Mask
455 (Register => Registers.ILK_DISPLAY_CHICKEN2,
456 Mask_Unset => ILK_DISPLAY_CHICKEN2_VGA_MASK,
457 Mask_Set => ILK_DISPLAY_CHICKEN2_VGA_ENABLE);
458 end if;
459
Nico Huber3675db52016-11-04 16:27:29 +0100460 Registers.Unset_And_Set_Mask
461 (Register => Registers.VGACNTRL,
462 Mask_Unset => VGA_CONTROL_VGA_DISPLAY_DISABLE or
463 VGA_CONTROL_BLINK_DUTY_CYCLE_MASK or
464 VGA_CONTROL_VSYNC_BLINK_RATE_MASK,
465 Mask_Set => VGA_CONTROL_BLINK_DUTY_CYCLE_50 or
466 VGA_CONTROL_VSYNC_BLINK_RATE (30));
467
468 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
469 Port_IO.InB (Reg8, VGA_SR_DATA);
470 Port_IO.OutB (VGA_SR_DATA, Reg8 and not (VGA_SR01_SCREEN_OFF));
471 else
Nico Huber6a4dfc82016-11-04 15:50:58 +0100472 Setup_Hires_Plane (Controller, Framebuffer);
Nico Huber3675db52016-11-04 16:27:29 +0100473 end if;
474
475 Registers.Write
476 (Register => Controller.PIPESRC,
477 Value => Encode
478 (Pos16 (Framebuffer.Height), Pos16 (Framebuffer.Width)));
Nico Huber83693c82016-10-08 22:17:55 +0200479
Nico Huber113a14b2016-12-06 21:59:15 +0100480 if Config.Has_Pipeconf_Misc then
481 Registers.Write
482 (Register => Controller.PIPEMISC,
483 Value => PIPECONF_Misc (Dither_BPC, Dither));
484 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200485 end Setup_Display;
486
Nico Huber113a14b2016-12-06 21:59:15 +0100487 procedure Setup_Transcoder
488 (Head : Head_Type;
489 Port_Cfg : Port_Config)
490 is
491 M : constant Mode_Type := Port_Cfg.Mode;
492 begin
493 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
494
495 if Config.Has_Trans_Clk_Sel and then
496 Head.TRANS_CLK_SEL /= Registers.Invalid_Register
497 then
498 Registers.Write
499 (Register => Head.TRANS_CLK_SEL,
500 Value => TRANS_CLK_SEL_PORT (Port_Cfg.Port));
501 end if;
502
503 if Port_Cfg.Is_FDI then
504 Setup_Link (Head, Port_Cfg.FDI, Port_Cfg.Mode);
505 elsif Port_Cfg.Display = DP then
506 Setup_Link (Head, Port_Cfg.DP, Port_Cfg.Mode);
507 end if;
508
509 Registers.Write (Head.HTOTAL, Encode (M.H_Visible, M.H_Total));
510 Registers.Write (Head.HBLANK, Encode (M.H_Visible, M.H_Total));
511 Registers.Write (Head.HSYNC, Encode (M.H_Sync_Begin, M.H_Sync_End));
512 Registers.Write (Head.VTOTAL, Encode (M.V_Visible, M.V_Total));
513 Registers.Write (Head.VBLANK, Encode (M.V_Visible, M.V_Total));
514 Registers.Write (Head.VSYNC, Encode (M.V_Sync_Begin, M.V_Sync_End));
515 end Setup_Transcoder;
516
Nico Huber83693c82016-10-08 22:17:55 +0200517 ----------------------------------------------------------------------------
518
Nico Huber4916e342016-11-04 14:37:53 +0100519 procedure Scale_Keep_Aspect
520 (Width : out Pos32;
521 Height : out Pos32;
522 Max_Width : in Pos32;
523 Max_Height : in Pos32;
524 Framebuffer : in Framebuffer_Type)
525 with
526 Pre =>
527 Max_Width <= Pos32 (Pos16'Last) and
528 Max_Height <= Pos32 (Pos16'Last) and
529 Framebuffer.Width <= Max_Width and
530 Framebuffer.Height <= Max_Height,
531 Post =>
532 Width <= Max_Width and Height <= Max_Height
533 is
534 begin
535 if (Max_Width * Framebuffer.Height) / Framebuffer.Width <= Max_Height then
536 Width := Max_Width;
537 Height := (Max_Width * Framebuffer.Height) / Framebuffer.Width;
538 else
539 Height := Max_Height;
540 Width := Pos32'Min (Max_Width, -- could prove, it's <= Max_Width
541 (Max_Height * Framebuffer.Width) / Framebuffer.Height);
542 end if;
543 end Scale_Keep_Aspect;
544
545 procedure Setup_Skylake_Pipe_Scaler
546 (Controller : in Controller_Type;
547 Mode : in HW.GFX.Mode_Type;
548 Framebuffer : in HW.GFX.Framebuffer_Type)
549 with
550 Pre =>
551 Framebuffer.Width <= Pos32 (Mode.H_Visible) and
552 Framebuffer.Height <= Pos32 (Mode.V_Visible)
553 is
554 -- Enable 7x5 extended mode where possible:
555 Scaler_Mode : constant Word32 :=
556 (if Controller.PS_CTRL_2 /= Registers.Invalid_Register then
557 PS_CTRL_SCALER_MODE_7X5_EXTENDED else 0);
558
559 -- We can scale up to 2.99x horizontally:
560 Horizontal_Limit : constant Pos32 := ((Framebuffer.Width * 299) / 100);
561 -- The third scaler is limited to 1.99x
562 -- vertical scaling for source widths > 2048:
563 Vertical_Limit : constant Pos32 :=
564 (Framebuffer.Height *
565 (if Controller.PS_CTRL_2 = Registers.Invalid_Register and
566 Framebuffer.Width > 2048
567 then
568 199
569 else
570 299)) / 100;
571
572 Width, Height : Pos32;
573 begin
574 -- Writes to WIN_SZ arm the PS registers.
575
576 Scale_Keep_Aspect
577 (Width => Width,
578 Height => Height,
579 Max_Width => Pos32'Min (Horizontal_Limit, Pos32 (Mode.H_Visible)),
580 Max_Height => Pos32'Min (Vertical_Limit, Pos32 (Mode.V_Visible)),
581 Framebuffer => Framebuffer);
582
583 Registers.Write
584 (Register => Controller.PS_CTRL_1,
585 Value => PS_CTRL_ENABLE_SCALER or Scaler_Mode);
586 Registers.Write
587 (Register => Controller.PS_WIN_POS_1,
588 Value =>
589 Shift_Left (Word32 (Pos32 (Mode.H_Visible) - Width) / 2, 16) or
590 Word32 (Pos32 (Mode.V_Visible) - Height) / 2);
591 Registers.Write
592 (Register => Controller.PS_WIN_SZ_1,
593 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
594 end Setup_Skylake_Pipe_Scaler;
595
596 procedure Setup_Ironlake_Panel_Fitter
597 (Controller : in Controller_Type;
598 Mode : in HW.GFX.Mode_Type;
599 Framebuffer : in HW.GFX.Framebuffer_Type)
600 with
601 Pre =>
602 Framebuffer.Width <= Pos32 (Mode.H_Visible) and
603 Framebuffer.Height <= Pos32 (Mode.V_Visible)
604 is
605 -- Force 1:1 mapping of panel fitter:pipe
606 PF_Ctrl_Pipe_Sel : constant Word32 :=
607 (if Config.Has_PF_Pipe_Select then
608 (case Controller.PF_CTRL is
609 when Registers.PFA_CTL_1 => 0 * 2 ** 29,
610 when Registers.PFB_CTL_1 => 1 * 2 ** 29,
611 when Registers.PFC_CTL_1 => 2 * 2 ** 29,
612 when others => 0) else 0);
613
614 Width, Height : Pos32;
615 begin
616 -- Writes to WIN_SZ arm the PF registers.
617
618 Scale_Keep_Aspect
619 (Width => Width,
620 Height => Height,
621 Max_Width => Pos32 (Mode.H_Visible),
622 Max_Height => Pos32 (Mode.V_Visible),
623 Framebuffer => Framebuffer);
624
625 Registers.Write
626 (Register => Controller.PF_CTRL,
627 Value => PF_CTRL_ENABLE or PF_Ctrl_Pipe_Sel or PF_CTRL_FILTER_MED);
628 Registers.Write
629 (Register => Controller.PF_WIN_POS,
630 Value =>
631 Shift_Left (Word32 (Pos32 (Mode.H_Visible) - Width) / 2, 16) or
632 Word32 (Pos32 (Mode.V_Visible) - Height) / 2);
633 Registers.Write
634 (Register => Controller.PF_WIN_SZ,
635 Value => Shift_Left (Word32 (Width), 16) or Word32 (Height));
636 end Setup_Ironlake_Panel_Fitter;
637
638 procedure Setup_Scaling
639 (Controller : in Controller_Type;
640 Mode : in HW.GFX.Mode_Type;
641 Framebuffer : in HW.GFX.Framebuffer_Type)
642 with
643 Pre =>
644 Framebuffer.Width <= Pos32 (Mode.H_Visible) and
645 Framebuffer.Height <= Pos32 (Mode.V_Visible)
646 is
647 begin
648 if Framebuffer.Width /= Pos32 (Mode.H_Visible) or
649 Framebuffer.Height /= Pos32 (Mode.V_Visible)
650 then
651 if Config.Has_Plane_Control then
652 Setup_Skylake_Pipe_Scaler (Controller, Mode, Framebuffer);
653 else
654 Setup_Ironlake_Panel_Fitter (Controller, Mode, Framebuffer);
655 end if;
656 end if;
657 end Setup_Scaling;
658
659 ----------------------------------------------------------------------------
660
Nico Huber113a14b2016-12-06 21:59:15 +0100661 procedure Transcoder_On
662 (Pipe : Pipe_Index;
Nico Huber83693c82016-10-08 22:17:55 +0200663 Head : Head_Type;
664 Port_Cfg : Port_Config;
Nico Huber113a14b2016-12-06 21:59:15 +0100665 Dither : Boolean)
Nico Huber83693c82016-10-08 22:17:55 +0200666 is
Nico Huber83693c82016-10-08 22:17:55 +0200667 begin
668 if Config.Has_Pipe_DDI_Func then
669 Registers.Write
670 (Register => Head.PIPE_DDI_FUNC_CTL,
671 Value => PIPE_DDI_FUNC_CTL_ENABLE or
672 PIPE_DDI_FUNC_CTL_DDI_SELECT (Port_Cfg.Port) or
673 PIPE_DDI_FUNC_CTL_MODE_SELECT (Port_Cfg.Display) or
674 PIPE_DDI_FUNC_CTL_BPC (Port_Cfg.Mode.BPC) or
675 PIPE_DDI_FUNC_CTL_VSYNC (Port_Cfg.Mode.V_Sync_Active_High) or
676 PIPE_DDI_FUNC_CTL_HSYNC (Port_Cfg.Mode.H_Sync_Active_High) or
Nico Huber113a14b2016-12-06 21:59:15 +0100677 PIPE_DDI_FUNC_CTL_EDP_SELECT (Pipe) or
Nico Huber83693c82016-10-08 22:17:55 +0200678 PIPE_DDI_FUNC_CTL_PORT_WIDTH (Port_Cfg.DP.Lane_Count));
679 end if;
680
Nico Huber113a14b2016-12-06 21:59:15 +0100681 Registers.Write
682 (Register => Head.PIPECONF,
683 Value => PIPECONF_ENABLE or
684 (if not Config.Has_Pipeconf_Misc then
685 PIPECONF_Misc (Port_Cfg.Mode.BPC, Dither) else 0));
Nico Huber83693c82016-10-08 22:17:55 +0200686 Registers.Posting_Read (Head.PIPECONF);
Nico Huber113a14b2016-12-06 21:59:15 +0100687 end Transcoder_On;
Nico Huber83693c82016-10-08 22:17:55 +0200688
689 ----------------------------------------------------------------------------
690
691 procedure On
Nico Huberf3e23662016-12-05 21:33:03 +0100692 (Pipe : Pipe_Index;
Nico Huber83693c82016-10-08 22:17:55 +0200693 Port_Cfg : Port_Config;
694 Framebuffer : Framebuffer_Type)
695 is
Nico Huber113a14b2016-12-06 21:59:15 +0100696 -- Enable dithering if framebuffer BPC differs from port BPC,
697 -- as smooth gradients look really bad without.
698 Dither : constant Boolean := Framebuffer.BPC /= Port_Cfg.Mode.BPC;
Nico Huberf3e23662016-12-05 21:33:03 +0100699 Head : constant Pipe_Head := Get_Pipe_Head (Pipe, Port_Cfg.Port);
Nico Huber83693c82016-10-08 22:17:55 +0200700 begin
701 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
702
Nico Huber113a14b2016-12-06 21:59:15 +0100703 Setup_Transcoder (Heads (Head), Port_Cfg);
Nico Huber83693c82016-10-08 22:17:55 +0200704
Nico Huberf3e23662016-12-05 21:33:03 +0100705 Setup_Display
Nico Huber113a14b2016-12-06 21:59:15 +0100706 (Controllers (Pipe), Framebuffer, Port_Cfg.Mode.BPC, Dither);
Nico Huber83693c82016-10-08 22:17:55 +0200707
Nico Huberf3e23662016-12-05 21:33:03 +0100708 Setup_Scaling (Controllers (Pipe), Port_Cfg.Mode, Framebuffer);
Nico Huber4916e342016-11-04 14:37:53 +0100709
Nico Huber113a14b2016-12-06 21:59:15 +0100710 Transcoder_On (Pipe, Heads (Head), Port_Cfg, Dither);
Nico Huber83693c82016-10-08 22:17:55 +0200711 end On;
712
713 ----------------------------------------------------------------------------
714
715 procedure Planes_Off (Controller : Controller_Type) is
716 begin
717 Registers.Unset_Mask (Controller.SPCNTR, SPCNTR_ENABLE);
718 if Config.Has_Plane_Control then
719 Clear_Watermarks (Controller);
720 Registers.Unset_Mask (Controller.PLANE_CTL, PLANE_CTL_PLANE_ENABLE);
721 Registers.Write (Controller.PLANE_SURF, 16#0000_0000#);
722 else
723 Registers.Unset_Mask (Controller.DSPCNTR, DSPCNTR_ENABLE);
724 end if;
725 end Planes_Off;
726
727 procedure Head_Off (Head : Head_Type)
728 is
729 Enabled : Boolean;
730 begin
731 Registers.Is_Set_Mask (Head.PIPECONF, PIPECONF_ENABLE, Enabled);
732
733 if Enabled then
734 Registers.Unset_Mask (Head.PIPECONF, PIPECONF_ENABLE);
735 end if;
736
737 -- Workaround for Broadwell:
738 -- Status may be wrong if pipe hasn't been enabled since reset.
739 if not Config.Pipe_Enabled_Workaround or else Enabled then
740 -- synchronously wait until pipe is truly off
741 Registers.Wait_Unset_Mask
742 (Register => Head.PIPECONF,
743 Mask => PIPECONF_ENABLED_STATUS,
744 TOut_MS => 40);
745 end if;
746
747 if Config.Has_Pipe_DDI_Func then
748 Registers.Write (Head.PIPE_DDI_FUNC_CTL, 0);
749 end if;
750 end Head_Off;
751
Nico Huber113a14b2016-12-06 21:59:15 +0100752 procedure Transcoder_Off (Pipe : Pipe_Index)
753 is
754 DDI_Func_Ctl : Word32;
755 begin
756 if Config.Has_EDP_Pipe then
757 Registers.Read (Registers.PIPE_EDP_DDI_FUNC_CTL, DDI_Func_Ctl);
758 DDI_Func_Ctl := DDI_Func_Ctl and PIPE_DDI_FUNC_CTL_EDP_SELECT_MASK;
759
760 if (Pipe = Primary and
761 DDI_Func_Ctl = PIPE_DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON) or
762 DDI_Func_Ctl = PIPE_DDI_FUNC_CTL_EDP_SELECT_ONOFF (Pipe)
763 then
764 Head_Off (Heads (Head_EDP));
765 end if;
766 end if;
767
768 Head_Off (Heads (Default_Pipe_Head (Pipe)));
769 end Transcoder_Off;
770
Nico Huber83693c82016-10-08 22:17:55 +0200771 procedure Panel_Fitter_Off (Controller : Controller_Type) is
772 begin
773 -- Writes to WIN_SZ arm the PS/PF registers.
774 if Config.Has_Plane_Control then
775 Registers.Unset_Mask (Controller.PS_CTRL_1, PS_CTRL_ENABLE_SCALER);
776 Registers.Write (Controller.PS_WIN_SZ_1, 16#0000_0000#);
777 if Controller.PS_CTRL_2 /= Registers.Invalid_Register and
778 Controller.PS_WIN_SZ_2 /= Registers.Invalid_Register
779 then
780 Registers.Unset_Mask (Controller.PS_CTRL_2, PS_CTRL_ENABLE_SCALER);
781 Registers.Write (Controller.PS_WIN_SZ_2, 16#0000_0000#);
782 end if;
783 else
Nico Huber4916e342016-11-04 14:37:53 +0100784 Registers.Unset_Mask (Controller.PF_CTRL, PF_CTRL_ENABLE);
Nico Huber83693c82016-10-08 22:17:55 +0200785 Registers.Write (Controller.PF_WIN_SZ, 16#0000_0000#);
786 end if;
787 end Panel_Fitter_Off;
788
Nico Huber113a14b2016-12-06 21:59:15 +0100789 procedure Trans_Clk_Off (Head : Head_Type) is
Nico Huber83693c82016-10-08 22:17:55 +0200790 begin
Nico Huber113a14b2016-12-06 21:59:15 +0100791 if Config.Has_Trans_Clk_Sel and then
792 Head.TRANS_CLK_SEL /= Registers.Invalid_Register
793 then
794 Registers.Write (Head.TRANS_CLK_SEL, TRANS_CLK_SEL_PORT_NONE);
Nico Huber83693c82016-10-08 22:17:55 +0200795 end if;
796 end Trans_Clk_Off;
797
Nico Huberf3e23662016-12-05 21:33:03 +0100798 procedure Off (Pipe : Pipe_Index; Port_Cfg : Port_Config)
799 is
Nico Huber113a14b2016-12-06 21:59:15 +0100800 Head : constant Pipe_Head := Get_Pipe_Head (Pipe, Port_Cfg.Port);
Nico Huber83693c82016-10-08 22:17:55 +0200801 begin
802 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
803
Nico Huberf3e23662016-12-05 21:33:03 +0100804 Planes_Off (Controllers (Pipe));
Nico Huber113a14b2016-12-06 21:59:15 +0100805 Transcoder_Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +0100806 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber113a14b2016-12-06 21:59:15 +0100807 Trans_Clk_Off (Heads (Head));
Nico Huber83693c82016-10-08 22:17:55 +0200808 end Off;
809
Nico Huber33912aa2016-12-06 20:36:23 +0100810 procedure Legacy_VGA_Off
811 is
812 use type HW.Word8;
813 Reg8 : Word8;
814 begin
815 Port_IO.OutB (VGA_SR_INDEX, VGA_SR01);
816 Port_IO.InB (Reg8, VGA_SR_DATA);
817 Port_IO.OutB (VGA_SR_DATA, Reg8 or VGA_SR01_SCREEN_OFF);
818 Time.U_Delay (100); -- PRM says 100us, Linux does 300
819 Registers.Set_Mask (Registers.VGACNTRL, VGA_CONTROL_VGA_DISPLAY_DISABLE);
820 end Legacy_VGA_Off;
821
Nico Huber83693c82016-10-08 22:17:55 +0200822 procedure All_Off
823 is
Nico Huber83693c82016-10-08 22:17:55 +0200824 begin
825 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
826
Nico Huber33912aa2016-12-06 20:36:23 +0100827 Legacy_VGA_Off;
828
Nico Huberf3e23662016-12-05 21:33:03 +0100829 for Pipe in Pipe_Index loop
830 Planes_Off (Controllers (Pipe));
Nico Huber113a14b2016-12-06 21:59:15 +0100831 Transcoder_Off (Pipe);
Nico Huberf3e23662016-12-05 21:33:03 +0100832 Panel_Fitter_Off (Controllers (Pipe));
Nico Huber113a14b2016-12-06 21:59:15 +0100833 Trans_Clk_Off (Heads (Default_Pipe_Head (Pipe)));
Nico Huber83693c82016-10-08 22:17:55 +0200834 end loop;
Nico Huber83693c82016-10-08 22:17:55 +0200835 end All_Off;
836
837 ----------------------------------------------------------------------------
838
Nico Huberf3e23662016-12-05 21:33:03 +0100839 procedure Update_Offset (Pipe : Pipe_Index; Framebuffer : Framebuffer_Type)
840 is
Nico Huber83693c82016-10-08 22:17:55 +0200841 begin
842 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
843
Nico Huberf3e23662016-12-05 21:33:03 +0100844 Registers.Write
845 (Controllers (Pipe).DSPSURF, Framebuffer.Offset and 16#ffff_f000#);
Nico Huber83693c82016-10-08 22:17:55 +0200846 end Update_Offset;
847
848 ----------------------------------------------------------------------------
849
Nico Huberf3e23662016-12-05 21:33:03 +0100850 function Get_Pipe_Hint (Pipe : Pipe_Index) return Word32
Nico Huber83693c82016-10-08 22:17:55 +0200851 is
Nico Huber83693c82016-10-08 22:17:55 +0200852 begin
Nico Huberf3e23662016-12-05 21:33:03 +0100853 return
854 (case Pipe is
855 when Primary => 0,
856 when Secondary => 1,
857 when Tertiary => 2);
Nico Huber83693c82016-10-08 22:17:55 +0200858 end Get_Pipe_Hint;
859
Nico Huber83693c82016-10-08 22:17:55 +0200860end HW.GFX.GMA.Pipe_Setup;