blob: 6eea4512caa3a14de1883e6b83f7da280ff1b5a8 [file] [log] [blame]
Nico Huber7ad2d652016-12-07 15:19:32 +01001--
Nico Huberabb16d92018-05-29 01:44:26 +02002-- Copyright (C) 2015-2018 secunet Security Networks AG
Nico Huber7ad2d652016-12-07 15:19:32 +01003--
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
6-- the Free Software Foundation; either version 2 of the License, or
7-- (at your option) any later version.
8--
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
Tim Wawrzynczak4be2e752022-09-09 10:37:06 -060018with HW.GFX.GMA.Config_Helpers;
Nico Huber7ad2d652016-12-07 15:19:32 +010019with HW.GFX.GMA.DP_Info;
20
21package body HW.GFX.GMA.Transcoder is
22
23 type Default_Transcoder_Array is array (Pipe_Index) of Transcoder_Index;
24 Default_Transcoder : constant Default_Transcoder_Array :=
25 (Primary => Trans_A,
26 Secondary => Trans_B,
27 Tertiary => Trans_C);
28
29 function Get_Idx (Pipe : Pipe_Index; Port : GPU_Port) return Transcoder_Index
30 is
31 begin
32 return
33 (if Config.Has_EDP_Transcoder and then Port = DIGI_A then
34 Trans_EDP
35 else
36 Default_Transcoder (Pipe));
37 end Get_Idx;
38
39 ----------------------------------------------------------------------------
40
41 TRANS_CLK_SEL_PORT_NONE : constant := 0 * 2 ** 29;
Tim Wawrzynczak4be2e752022-09-09 10:37:06 -060042 TRANS_CLK_SEL_MASK : constant := 16#f000_0000#;
Nico Huber7ad2d652016-12-07 15:19:32 +010043
44 type TRANS_CLK_SEL_PORT_Array is
45 array (Digital_Port) of Word32;
46 TRANS_CLK_SEL_PORT : constant TRANS_CLK_SEL_PORT_Array :=
47 (DIGI_A => 0 * 2 ** 29, -- DDI A is not selectable
48 DIGI_B => 2 * 2 ** 29,
49 DIGI_C => 3 * 2 ** 29,
50 DIGI_D => 4 * 2 ** 29,
51 DIGI_E => 5 * 2 ** 29);
52
Tim Wawrzynczak4be2e752022-09-09 10:37:06 -060053 function TGL_TRANS_CLK_SEL_PORT (Port : TGL_Digital_Port) return Word32 is
54 (case Port is
55 when DIGI_A => 1 * 2 ** 28,
56 when DIGI_B => 2 * 2 ** 28,
57 when DIGI_C => 3 * 2 ** 28,
58 when DDI_TC1 => 4 * 2 ** 28,
59 when DDI_TC2 => 5 * 2 ** 28,
60 when DDI_TC3 => 6 * 2 ** 28,
61 when DDI_TC4 => 7 * 2 ** 28,
62 when DDI_TC5 => 8 * 2 ** 28,
63 when DDI_TC6 => 9 * 2 ** 28,
64 when others => 0);
65
Nico Huber7ad2d652016-12-07 15:19:32 +010066 TRANS_CONF_ENABLE : constant := 1 * 2 ** 31;
67 TRANS_CONF_ENABLED_STATUS : constant := 1 * 2 ** 30;
68 TRANS_CONF_ENABLE_DITHER : constant := 1 * 2 ** 4;
69
70 type BPC_Array is array (BPC_Type) of Word32;
71 TRANS_CONF_BPC : constant BPC_Array :=
72 (6 => 2 * 2 ** 5,
73 8 => 0 * 2 ** 5,
74 10 => 1 * 2 ** 5,
75 12 => 3 * 2 ** 5,
76 others => 0 * 2 ** 5); -- default to 8 BPC
77
78 function BPC_Conf (BPC : BPC_Type; Dither : Boolean) return Word32 is
79 begin
80 return
81 (if Config.Has_Pipeconf_BPC then TRANS_CONF_BPC (BPC) else 0) or
82 (if Dither then TRANS_CONF_ENABLE_DITHER else 0);
83 end BPC_Conf;
84
85 ----------------------------------------------------------------------------
86
87 DDI_FUNC_CTL_ENABLE : constant := 1 * 2 ** 31;
88 DDI_FUNC_CTL_MODE_SELECT_MASK : constant := 7 * 2 ** 24;
89 DDI_FUNC_CTL_MODE_SELECT_HDMI : constant := 0 * 2 ** 24;
90 DDI_FUNC_CTL_MODE_SELECT_DVI : constant := 1 * 2 ** 24;
91 DDI_FUNC_CTL_MODE_SELECT_DP_SST : constant := 2 * 2 ** 24;
92 DDI_FUNC_CTL_MODE_SELECT_DP_MST : constant := 3 * 2 ** 24;
93 DDI_FUNC_CTL_MODE_SELECT_FDI : constant := 4 * 2 ** 24;
Nico Huber7ad2d652016-12-07 15:19:32 +010094
95 type DDI_Select_Array is array (Digital_Port) of Word32;
96 DDI_FUNC_CTL_DDI_SELECT : constant DDI_Select_Array :=
97 (DIGI_A => 0 * 2 ** 28,
98 DIGI_B => 1 * 2 ** 28,
99 DIGI_C => 2 * 2 ** 28,
100 DIGI_D => 3 * 2 ** 28,
101 DIGI_E => 4 * 2 ** 28);
102
Tim Wawrzynczak4be2e752022-09-09 10:37:06 -0600103 function TGL_DDI_FUNC_CTL_DDI_SELECT (Port : TGL_Digital_Port)
104 return Word32
105 is
106 (case Port is
107 when DIGI_A => 1 * 2 ** 27,
108 when DIGI_B => 2 * 2 ** 27,
109 when DIGI_C => 3 * 2 ** 27,
110 when DDI_TC1 => 4 * 2 ** 27,
111 when DDI_TC2 => 5 * 2 ** 27,
112 when DDI_TC3 => 6 * 2 ** 27,
113 when DDI_TC4 => 7 * 2 ** 27,
114 when DDI_TC5 => 8 * 2 ** 27,
115 when DDI_TC6 => 9 * 2 ** 27,
116 when others => 0);
117
Nico Huber7ad2d652016-12-07 15:19:32 +0100118 type DDI_Mode_Array is array (Display_Type) of Word32;
119 DDI_FUNC_CTL_MODE_SELECT : constant DDI_Mode_Array :=
120 (VGA => DDI_FUNC_CTL_MODE_SELECT_FDI,
121 HDMI => DDI_FUNC_CTL_MODE_SELECT_DVI,
122 DP => DDI_FUNC_CTL_MODE_SELECT_DP_SST,
123 others => 0);
124
125 type HV_Sync_Array is array (Boolean) of Word32;
126 DDI_FUNC_CTL_VSYNC : constant HV_Sync_Array :=
127 (False => 0 * 2 ** 17,
128 True => 1 * 2 ** 17);
129 DDI_FUNC_CTL_HSYNC : constant HV_Sync_Array :=
130 (False => 0 * 2 ** 16,
131 True => 1 * 2 ** 16);
132
Nico Huberabb16d92018-05-29 01:44:26 +0200133 DDI_FUNC_CTL_EDP_SELECT_MASK : constant := 7 * 2 ** 12;
134 DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON : constant := 0 * 2 ** 12;
135 DDI_FUNC_CTL_EDP_SELECT : constant array (Pipe_Index) of Word32 :=
136 (Primary => 4 * 2 ** 12,
137 Secondary => 5 * 2 ** 12,
138 Tertiary => 6 * 2 ** 12);
Nico Huber7ad2d652016-12-07 15:19:32 +0100139
140 type Port_Width_Array is array (DP_Lane_Count) of Word32;
141 DDI_FUNC_CTL_PORT_WIDTH : constant Port_Width_Array :=
142 (DP_Lane_Count_1 => 0 * 2 ** 1,
143 DP_Lane_Count_2 => 1 * 2 ** 1,
144 DP_Lane_Count_4 => 3 * 2 ** 1);
145
146 DDI_FUNC_CTL_BPC : constant BPC_Array :=
147 (6 => 2 * 2 ** 20,
148 8 => 0 * 2 ** 20,
149 10 => 1 * 2 ** 20,
150 12 => 3 * 2 ** 20,
151 others => 0 * 2 ** 20); -- default to 8 BPC
152
153 ----------------------------------------------------------------------------
154
155 TRANS_MSA_MISC_SYNC_CLK : constant := 1 * 2 ** 0;
156 TRANS_MSA_MISC_BPC : constant BPC_Array :=
157 (6 => 0 * 2 ** 5,
158 8 => 1 * 2 ** 5,
159 10 => 2 * 2 ** 5,
160 12 => 3 * 2 ** 5,
161 16 => 4 * 2 ** 5,
162 others => 1 * 2 ** 5); -- default to 8 BPC
163
164 function TRANS_DATA_M_TU (Transfer_Unit : Positive) return Word32 is
165 begin
166 return Shift_Left (Word32 (Transfer_Unit - 1), 25);
167 end TRANS_DATA_M_TU;
168
169 ----------------------------------------------------------------------------
170
Nico Huberc5c767a2018-06-03 01:09:04 +0200171 function Encode (LSW, MSW : Pos32) return Word32 is
Nico Huber7ad2d652016-12-07 15:19:32 +0100172 begin
173 return Shift_Left (Word32 (MSW - 1), 16) or Word32 (LSW - 1);
174 end Encode;
175
176 ----------------------------------------------------------------------------
177
178 procedure Setup_Link
179 (Trans : Transcoder_Regs;
180 Link : DP_Link;
181 Mode : Mode_Type)
182 with
183 Global => (In_Out => Registers.Register_State),
184 Depends => (Registers.Register_State =>+ (Trans, Link, Mode))
185 is
186 Data_M, Link_M : DP_Info.M_Type;
187 Data_N, Link_N : DP_Info.N_Type;
188 begin
189 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
190
191 DP_Info.Calculate_M_N
192 (Link => Link,
193 Mode => Mode,
194 Data_M => Data_M,
195 Data_N => Data_N,
196 Link_M => Link_M,
197 Link_N => Link_N);
198
199 Registers.Write
200 (Register => Trans.DATA_M1,
201 Value => TRANS_DATA_M_TU (64) or
202 Word32 (Data_M));
203 Registers.Write
204 (Register => Trans.DATA_N1,
205 Value => Word32 (Data_N));
206
207 Registers.Write
208 (Register => Trans.LINK_M1,
209 Value => Word32 (Link_M));
210 Registers.Write
211 (Register => Trans.LINK_N1,
212 Value => Word32 (Link_N));
213
214 if Config.Has_Pipe_MSA_Misc then
215 Registers.Write
216 (Register => Trans.MSA_MISC,
217 Value => TRANS_MSA_MISC_SYNC_CLK or
218 TRANS_MSA_MISC_BPC (Mode.BPC));
219 end if;
220 end Setup_Link;
221
222 ----------------------------------------------------------------------------
223
224 procedure Setup
225 (Pipe : Pipe_Index;
226 Port_Cfg : Port_Config)
227 is
228 use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
229
230 Trans : Transcoder_Regs renames
231 Transcoders (Get_Idx (Pipe, Port_Cfg.Port));
232 M : constant Mode_Type := Port_Cfg.Mode;
233 begin
234 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
235
236 if Config.Has_Trans_Clk_Sel and then
Tim Wawrzynczak4be2e752022-09-09 10:37:06 -0600237 not Config.Need_Early_Transcoder_Setup and then
Arthur Heymans5d08a932018-03-28 17:00:18 +0200238 Trans.CLK_SEL /= Registers.Invalid_Register and then
239 Port_Cfg.Port in Digital_Port
Nico Huber7ad2d652016-12-07 15:19:32 +0100240 then
241 Registers.Write
242 (Register => Trans.CLK_SEL,
243 Value => TRANS_CLK_SEL_PORT (Port_Cfg.Port));
244 end if;
245
246 if Port_Cfg.Is_FDI then
247 Setup_Link (Trans, Port_Cfg.FDI, Port_Cfg.Mode);
248 elsif Port_Cfg.Display = DP then
249 Setup_Link (Trans, Port_Cfg.DP, Port_Cfg.Mode);
250 end if;
251
252 Registers.Write (Trans.HTOTAL, Encode (M.H_Visible, M.H_Total));
253 Registers.Write (Trans.HBLANK, Encode (M.H_Visible, M.H_Total));
254 Registers.Write (Trans.HSYNC, Encode (M.H_Sync_Begin, M.H_Sync_End));
255 Registers.Write (Trans.VTOTAL, Encode (M.V_Visible, M.V_Total));
256 Registers.Write (Trans.VBLANK, Encode (M.V_Visible, M.V_Total));
257 Registers.Write (Trans.VSYNC, Encode (M.V_Sync_Begin, M.V_Sync_End));
258 end Setup;
259
260 ----------------------------------------------------------------------------
261
Tim Wawrzynczak4be2e752022-09-09 10:37:06 -0600262 procedure Enable_Pipe_Clock (Pipe : Pipe_Index; Port_Cfg : Port_Config)
263 is
264 use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
265
266 Trans : Transcoder_Regs renames
267 Transcoders (Get_Idx (Pipe, Port_Cfg.Port));
268 begin
269 if Config.Need_Early_Transcoder_Setup and then
270 Trans.CLK_SEL /= Registers.Invalid_Register and then
271 Port_Cfg.Port in TGL_Digital_Port
272 then
273 Registers.Unset_And_Set_Mask
274 (Register => Trans.CLK_SEL,
275 Mask_Unset => TRANS_CLK_SEL_MASK,
276 Mask_Set => TGL_TRANS_CLK_SEL_PORT (Port_Cfg.Port));
277 end if;
278 end Enable_Pipe_Clock;
279
280 ----------------------------------------------------------------------------
281
282 procedure Configure (Pipe : Pipe_Index; Port_Cfg : Port_Config; Scale : Boolean)
283 is
284 Trans : Transcoder_Regs renames
285 Transcoders (Get_Idx (Pipe, Port_Cfg.Port));
286 Lane_Count : constant DP_Lane_Count :=
287 (if Port_Cfg.Is_FDI then Port_Cfg.FDI.Lane_Count else Port_Cfg.DP.Lane_Count);
288 EDP_Select : constant Word32 :=
289 (if Config.Has_TGL_DDI_Select
290 then 0
291 else
292 (if Pipe = Primary and
293 (not Config.Use_PDW_For_EDP_Scaling or else not Scale)
294 then
295 DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON
296 else
297 DDI_FUNC_CTL_EDP_SELECT (Pipe)));
298 DDI_Select : constant Word32 :=
299 (if Config.Has_TGL_DDI_Select and Port_Cfg.Port in TGL_Digital_Port then
300 TGL_DDI_FUNC_CTL_DDI_SELECT (Port_Cfg.Port)
301 else
302 (if Port_Cfg.Port in Digital_Port
303 then
304 DDI_FUNC_CTL_DDI_SELECT (Port_Cfg.Port)
305 else 0));
306 begin
307 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
308 if Config.Has_Pipe_DDI_Func then
309 if Is_Digital_Port (Port_Cfg.Port) then
310 Registers.Write
311 (Register => Trans.DDI_FUNC_CTL,
312 Value => DDI_Select or
313 DDI_FUNC_CTL_MODE_SELECT (Port_Cfg.Display) or
314 DDI_FUNC_CTL_BPC (Port_Cfg.Mode.BPC) or
315 DDI_FUNC_CTL_VSYNC (Port_Cfg.Mode.V_Sync_Active_High) or
316 DDI_FUNC_CTL_HSYNC (Port_Cfg.Mode.H_Sync_Active_High) or
317 EDP_Select or
318 DDI_FUNC_CTL_PORT_WIDTH (Lane_Count));
319 end if;
320 end if;
321 end Configure;
322
323 ----------------------------------------------------------------------------
324
Nico Huber7ad2d652016-12-07 15:19:32 +0100325 procedure On
326 (Pipe : Pipe_Index;
327 Port_Cfg : Port_Config;
Nico Huberabb16d92018-05-29 01:44:26 +0200328 Dither : Boolean;
329 Scale : Boolean)
Nico Huber7ad2d652016-12-07 15:19:32 +0100330 is
331 Trans : Transcoder_Regs renames
332 Transcoders (Get_Idx (Pipe, Port_Cfg.Port));
333 begin
Tim Wawrzynczak4be2e752022-09-09 10:37:06 -0600334 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
335 if not Config.Need_Early_Transcoder_Setup then
336 Configure (Pipe, Port_Cfg, Scale);
337 end if;
338
339 if Config.Has_Pipe_DDI_Func and Is_Digital_Port (Port_Cfg.Port) then
340 Registers.Set_Mask
Nico Huber7ad2d652016-12-07 15:19:32 +0100341 (Register => Trans.DDI_FUNC_CTL,
Tim Wawrzynczak4be2e752022-09-09 10:37:06 -0600342 Mask => DDI_FUNC_CTL_ENABLE);
Nico Huber7ad2d652016-12-07 15:19:32 +0100343 end if;
344
345 Registers.Write
346 (Register => Trans.CONF,
347 Value => TRANS_CONF_ENABLE or
348 (if not Config.Has_Pipeconf_Misc then
349 BPC_Conf (Port_Cfg.Mode.BPC, Dither) else 0));
350 Registers.Posting_Read (Trans.CONF);
351 end On;
352
353 ----------------------------------------------------------------------------
354
355 procedure Trans_Off (Trans : Transcoder_Regs)
356 is
357 Enabled : Boolean;
358 begin
359 Registers.Is_Set_Mask (Trans.CONF, TRANS_CONF_ENABLE, Enabled);
360
361 if Enabled then
362 Registers.Unset_Mask (Trans.CONF, TRANS_CONF_ENABLE);
363 end if;
364
365 -- Workaround for Broadwell:
366 -- Status may be wrong if pipe hasn't been enabled since reset.
367 if not Config.Pipe_Enabled_Workaround or else Enabled then
368 -- synchronously wait until pipe is truly off
369 Registers.Wait_Unset_Mask
370 (Register => Trans.CONF,
371 Mask => TRANS_CONF_ENABLED_STATUS,
372 TOut_MS => 40);
373 end if;
374
375 if Config.Has_Pipe_DDI_Func then
Nico Huber6489f3d2024-07-15 15:28:47 +0000376 Registers.Is_Set_Mask (Trans.DDI_FUNC_CTL, DDI_FUNC_CTL_ENABLE, Enabled);
377 if Enabled then
378 Registers.Write (Trans.DDI_FUNC_CTL, 0);
379 end if;
Nico Huber7ad2d652016-12-07 15:19:32 +0100380 end if;
381 end Trans_Off;
382
383 procedure Off (Pipe : Pipe_Index)
384 is
385 DDI_Func_Ctl : Word32;
386 begin
387 if Config.Has_EDP_Transcoder then
388 Registers.Read (Registers.PIPE_EDP_DDI_FUNC_CTL, DDI_Func_Ctl);
389 DDI_Func_Ctl := DDI_Func_Ctl and DDI_FUNC_CTL_EDP_SELECT_MASK;
390
391 if (Pipe = Primary and
392 DDI_Func_Ctl = DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON) or
Nico Huberabb16d92018-05-29 01:44:26 +0200393 DDI_Func_Ctl = DDI_FUNC_CTL_EDP_SELECT (Pipe)
Nico Huber7ad2d652016-12-07 15:19:32 +0100394 then
395 Trans_Off (Transcoders (Trans_EDP));
396 end if;
397 end if;
398
399 Trans_Off (Transcoders (Default_Transcoder (Pipe)));
400 end Off;
401
402 procedure Clk_Off (Pipe : Pipe_Index)
403 is
404 use type Registers.Registers_Invalid_Index;
405
406 Trans : Transcoder_Regs renames Transcoders (Default_Transcoder (Pipe));
407 begin
408 if Config.Has_Trans_Clk_Sel and then
409 Trans.CLK_SEL /= Registers.Invalid_Register
410 then
411 Registers.Write (Trans.CLK_SEL, TRANS_CLK_SEL_PORT_NONE);
412 end if;
413 end Clk_Off;
414
Angel Pons3f86b0b2020-07-18 00:22:32 +0200415 ----------------------------------------------------------------------------
416
417 SRD_CTL_ENABLE : constant := 1 * 2 ** 31;
418 SRD_STATUS_STATE_MASK : constant := 7 * 2 ** 29;
419
420 type SRD_Regs is record
421 CTL : Registers.Registers_Index;
422 STATUS : Registers.Registers_Index;
423 end record;
424 type SRD_Per_Pipe_Regs is array (Transcoder_Index) of SRD_Regs;
425
426 SRD : constant SRD_Per_Pipe_Regs := SRD_Per_Pipe_Regs'
427 (Trans_EDP => SRD_Regs'
428 (CTL => Registers.SRD_CTL_EDP,
429 STATUS => Registers.SRD_STATUS_EDP),
430 Trans_A => SRD_Regs'
431 (CTL => Registers.SRD_CTL_A,
432 STATUS => Registers.SRD_STATUS_A),
433 Trans_B => SRD_Regs'
434 (CTL => Registers.SRD_CTL_B,
435 STATUS => Registers.SRD_STATUS_B),
436 Trans_C => SRD_Regs'
437 (CTL => Registers.SRD_CTL_C,
438 STATUS => Registers.SRD_STATUS_C));
439
440 ----------------------------------------------------------------------------
441
442 procedure PSR_Off
443 is
444 Enabled : Boolean;
445 begin
446 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
447
448 if Config.Has_Per_Pipe_SRD then
Tim Wawrzynczak4be2e752022-09-09 10:37:06 -0600449 declare
450 First_Transcoder : constant Transcoder_Index :=
451 (if Config.Has_EDP_Transcoder then Trans_EDP else Trans_A);
452 begin
453 for P in Transcoder_Index range First_Transcoder .. Transcoder_Index'Last loop
454 Registers.Is_Set_Mask (SRD (P).CTL, SRD_CTL_ENABLE, Enabled);
455 if Enabled then
456 Registers.Unset_Mask (SRD (P).CTL, SRD_CTL_ENABLE);
457 Registers.Wait_Unset_Mask (SRD (P).STATUS, SRD_STATUS_STATE_MASK);
Angel Pons3f86b0b2020-07-18 00:22:32 +0200458
Tim Wawrzynczak4be2e752022-09-09 10:37:06 -0600459 pragma Debug (Debug.Put_Line ("Disabled PSR."));
460 end if;
461 end loop;
462 end;
Angel Pons3f86b0b2020-07-18 00:22:32 +0200463 else
464 Registers.Is_Set_Mask (Registers.SRD_CTL, SRD_CTL_ENABLE, Enabled);
465 if Enabled then
466 Registers.Unset_Mask (Registers.SRD_CTL, SRD_CTL_ENABLE);
467 Registers.Wait_Unset_Mask (Registers.SRD_STATUS, SRD_STATUS_STATE_MASK);
468
469 pragma Debug (Debug.Put_Line ("Disabled PSR."));
470 end if;
471 end if;
472 end PSR_Off;
473
474 ----------------------------------------------------------------------------
475
Nico Huber7ad2d652016-12-07 15:19:32 +0100476end HW.GFX.GMA.Transcoder;