blob: e74d76932d642c03d321d14f6ba080d32864ebae [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
Nico Huber7ad2d652016-12-07 15:19:32 +010018with HW.GFX.GMA.DP_Info;
19
20package body HW.GFX.GMA.Transcoder is
21
22 type Default_Transcoder_Array is array (Pipe_Index) of Transcoder_Index;
23 Default_Transcoder : constant Default_Transcoder_Array :=
24 (Primary => Trans_A,
25 Secondary => Trans_B,
26 Tertiary => Trans_C);
27
28 function Get_Idx (Pipe : Pipe_Index; Port : GPU_Port) return Transcoder_Index
29 is
30 begin
31 return
32 (if Config.Has_EDP_Transcoder and then Port = DIGI_A then
33 Trans_EDP
34 else
35 Default_Transcoder (Pipe));
36 end Get_Idx;
37
38 ----------------------------------------------------------------------------
39
40 TRANS_CLK_SEL_PORT_NONE : constant := 0 * 2 ** 29;
41
42 type TRANS_CLK_SEL_PORT_Array is
43 array (Digital_Port) of Word32;
44 TRANS_CLK_SEL_PORT : constant TRANS_CLK_SEL_PORT_Array :=
45 (DIGI_A => 0 * 2 ** 29, -- DDI A is not selectable
46 DIGI_B => 2 * 2 ** 29,
47 DIGI_C => 3 * 2 ** 29,
48 DIGI_D => 4 * 2 ** 29,
49 DIGI_E => 5 * 2 ** 29);
50
51 TRANS_CONF_ENABLE : constant := 1 * 2 ** 31;
52 TRANS_CONF_ENABLED_STATUS : constant := 1 * 2 ** 30;
53 TRANS_CONF_ENABLE_DITHER : constant := 1 * 2 ** 4;
54
55 type BPC_Array is array (BPC_Type) of Word32;
56 TRANS_CONF_BPC : constant BPC_Array :=
57 (6 => 2 * 2 ** 5,
58 8 => 0 * 2 ** 5,
59 10 => 1 * 2 ** 5,
60 12 => 3 * 2 ** 5,
61 others => 0 * 2 ** 5); -- default to 8 BPC
62
63 function BPC_Conf (BPC : BPC_Type; Dither : Boolean) return Word32 is
64 begin
65 return
66 (if Config.Has_Pipeconf_BPC then TRANS_CONF_BPC (BPC) else 0) or
67 (if Dither then TRANS_CONF_ENABLE_DITHER else 0);
68 end BPC_Conf;
69
70 ----------------------------------------------------------------------------
71
72 DDI_FUNC_CTL_ENABLE : constant := 1 * 2 ** 31;
73 DDI_FUNC_CTL_MODE_SELECT_MASK : constant := 7 * 2 ** 24;
74 DDI_FUNC_CTL_MODE_SELECT_HDMI : constant := 0 * 2 ** 24;
75 DDI_FUNC_CTL_MODE_SELECT_DVI : constant := 1 * 2 ** 24;
76 DDI_FUNC_CTL_MODE_SELECT_DP_SST : constant := 2 * 2 ** 24;
77 DDI_FUNC_CTL_MODE_SELECT_DP_MST : constant := 3 * 2 ** 24;
78 DDI_FUNC_CTL_MODE_SELECT_FDI : constant := 4 * 2 ** 24;
Nico Huber7ad2d652016-12-07 15:19:32 +010079
80 type DDI_Select_Array is array (Digital_Port) of Word32;
81 DDI_FUNC_CTL_DDI_SELECT : constant DDI_Select_Array :=
82 (DIGI_A => 0 * 2 ** 28,
83 DIGI_B => 1 * 2 ** 28,
84 DIGI_C => 2 * 2 ** 28,
85 DIGI_D => 3 * 2 ** 28,
86 DIGI_E => 4 * 2 ** 28);
87
88 type DDI_Mode_Array is array (Display_Type) of Word32;
89 DDI_FUNC_CTL_MODE_SELECT : constant DDI_Mode_Array :=
90 (VGA => DDI_FUNC_CTL_MODE_SELECT_FDI,
91 HDMI => DDI_FUNC_CTL_MODE_SELECT_DVI,
92 DP => DDI_FUNC_CTL_MODE_SELECT_DP_SST,
93 others => 0);
94
95 type HV_Sync_Array is array (Boolean) of Word32;
96 DDI_FUNC_CTL_VSYNC : constant HV_Sync_Array :=
97 (False => 0 * 2 ** 17,
98 True => 1 * 2 ** 17);
99 DDI_FUNC_CTL_HSYNC : constant HV_Sync_Array :=
100 (False => 0 * 2 ** 16,
101 True => 1 * 2 ** 16);
102
Nico Huberabb16d92018-05-29 01:44:26 +0200103 DDI_FUNC_CTL_EDP_SELECT_MASK : constant := 7 * 2 ** 12;
104 DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON : constant := 0 * 2 ** 12;
105 DDI_FUNC_CTL_EDP_SELECT : constant array (Pipe_Index) of Word32 :=
106 (Primary => 4 * 2 ** 12,
107 Secondary => 5 * 2 ** 12,
108 Tertiary => 6 * 2 ** 12);
Nico Huber7ad2d652016-12-07 15:19:32 +0100109
110 type Port_Width_Array is array (DP_Lane_Count) of Word32;
111 DDI_FUNC_CTL_PORT_WIDTH : constant Port_Width_Array :=
112 (DP_Lane_Count_1 => 0 * 2 ** 1,
113 DP_Lane_Count_2 => 1 * 2 ** 1,
114 DP_Lane_Count_4 => 3 * 2 ** 1);
115
116 DDI_FUNC_CTL_BPC : constant BPC_Array :=
117 (6 => 2 * 2 ** 20,
118 8 => 0 * 2 ** 20,
119 10 => 1 * 2 ** 20,
120 12 => 3 * 2 ** 20,
121 others => 0 * 2 ** 20); -- default to 8 BPC
122
123 ----------------------------------------------------------------------------
124
125 TRANS_MSA_MISC_SYNC_CLK : constant := 1 * 2 ** 0;
126 TRANS_MSA_MISC_BPC : constant BPC_Array :=
127 (6 => 0 * 2 ** 5,
128 8 => 1 * 2 ** 5,
129 10 => 2 * 2 ** 5,
130 12 => 3 * 2 ** 5,
131 16 => 4 * 2 ** 5,
132 others => 1 * 2 ** 5); -- default to 8 BPC
133
134 function TRANS_DATA_M_TU (Transfer_Unit : Positive) return Word32 is
135 begin
136 return Shift_Left (Word32 (Transfer_Unit - 1), 25);
137 end TRANS_DATA_M_TU;
138
139 ----------------------------------------------------------------------------
140
Nico Huberc5c767a2018-06-03 01:09:04 +0200141 function Encode (LSW, MSW : Pos32) return Word32 is
Nico Huber7ad2d652016-12-07 15:19:32 +0100142 begin
143 return Shift_Left (Word32 (MSW - 1), 16) or Word32 (LSW - 1);
144 end Encode;
145
146 ----------------------------------------------------------------------------
147
148 procedure Setup_Link
149 (Trans : Transcoder_Regs;
150 Link : DP_Link;
151 Mode : Mode_Type)
152 with
153 Global => (In_Out => Registers.Register_State),
154 Depends => (Registers.Register_State =>+ (Trans, Link, Mode))
155 is
156 Data_M, Link_M : DP_Info.M_Type;
157 Data_N, Link_N : DP_Info.N_Type;
158 begin
159 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
160
161 DP_Info.Calculate_M_N
162 (Link => Link,
163 Mode => Mode,
164 Data_M => Data_M,
165 Data_N => Data_N,
166 Link_M => Link_M,
167 Link_N => Link_N);
168
169 Registers.Write
170 (Register => Trans.DATA_M1,
171 Value => TRANS_DATA_M_TU (64) or
172 Word32 (Data_M));
173 Registers.Write
174 (Register => Trans.DATA_N1,
175 Value => Word32 (Data_N));
176
177 Registers.Write
178 (Register => Trans.LINK_M1,
179 Value => Word32 (Link_M));
180 Registers.Write
181 (Register => Trans.LINK_N1,
182 Value => Word32 (Link_N));
183
184 if Config.Has_Pipe_MSA_Misc then
185 Registers.Write
186 (Register => Trans.MSA_MISC,
187 Value => TRANS_MSA_MISC_SYNC_CLK or
188 TRANS_MSA_MISC_BPC (Mode.BPC));
189 end if;
190 end Setup_Link;
191
192 ----------------------------------------------------------------------------
193
194 procedure Setup
195 (Pipe : Pipe_Index;
196 Port_Cfg : Port_Config)
197 is
198 use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
199
200 Trans : Transcoder_Regs renames
201 Transcoders (Get_Idx (Pipe, Port_Cfg.Port));
202 M : constant Mode_Type := Port_Cfg.Mode;
203 begin
204 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
205
206 if Config.Has_Trans_Clk_Sel and then
Arthur Heymans5d08a932018-03-28 17:00:18 +0200207 Trans.CLK_SEL /= Registers.Invalid_Register and then
208 Port_Cfg.Port in Digital_Port
Nico Huber7ad2d652016-12-07 15:19:32 +0100209 then
210 Registers.Write
211 (Register => Trans.CLK_SEL,
212 Value => TRANS_CLK_SEL_PORT (Port_Cfg.Port));
213 end if;
214
215 if Port_Cfg.Is_FDI then
216 Setup_Link (Trans, Port_Cfg.FDI, Port_Cfg.Mode);
217 elsif Port_Cfg.Display = DP then
218 Setup_Link (Trans, Port_Cfg.DP, Port_Cfg.Mode);
219 end if;
220
221 Registers.Write (Trans.HTOTAL, Encode (M.H_Visible, M.H_Total));
222 Registers.Write (Trans.HBLANK, Encode (M.H_Visible, M.H_Total));
223 Registers.Write (Trans.HSYNC, Encode (M.H_Sync_Begin, M.H_Sync_End));
224 Registers.Write (Trans.VTOTAL, Encode (M.V_Visible, M.V_Total));
225 Registers.Write (Trans.VBLANK, Encode (M.V_Visible, M.V_Total));
226 Registers.Write (Trans.VSYNC, Encode (M.V_Sync_Begin, M.V_Sync_End));
227 end Setup;
228
229 ----------------------------------------------------------------------------
230
231 procedure On
232 (Pipe : Pipe_Index;
233 Port_Cfg : Port_Config;
Nico Huberabb16d92018-05-29 01:44:26 +0200234 Dither : Boolean;
235 Scale : Boolean)
Nico Huber7ad2d652016-12-07 15:19:32 +0100236 is
237 Trans : Transcoder_Regs renames
238 Transcoders (Get_Idx (Pipe, Port_Cfg.Port));
Angel Pons450c24c2020-05-13 00:49:52 +0200239 Lane_Count : constant DP_Lane_Count :=
240 (if Port_Cfg.Is_FDI then Port_Cfg.FDI.Lane_Count else Port_Cfg.DP.Lane_Count);
Nico Huberabb16d92018-05-29 01:44:26 +0200241 EDP_Select : constant Word32 :=
Nico Hubera8157042019-07-25 14:05:17 +0200242 (if Pipe = Primary and
243 (not Config.Use_PDW_For_EDP_Scaling or else not Scale)
244 then
Nico Huberabb16d92018-05-29 01:44:26 +0200245 DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON
246 else
247 DDI_FUNC_CTL_EDP_SELECT (Pipe));
Nico Huber7ad2d652016-12-07 15:19:32 +0100248 begin
Arthur Heymans5d08a932018-03-28 17:00:18 +0200249 if Config.Has_Pipe_DDI_Func and Port_Cfg.Port in Digital_Port then
Nico Huber7ad2d652016-12-07 15:19:32 +0100250 Registers.Write
251 (Register => Trans.DDI_FUNC_CTL,
252 Value => DDI_FUNC_CTL_ENABLE or
253 DDI_FUNC_CTL_DDI_SELECT (Port_Cfg.Port) or
254 DDI_FUNC_CTL_MODE_SELECT (Port_Cfg.Display) or
255 DDI_FUNC_CTL_BPC (Port_Cfg.Mode.BPC) or
256 DDI_FUNC_CTL_VSYNC (Port_Cfg.Mode.V_Sync_Active_High) or
257 DDI_FUNC_CTL_HSYNC (Port_Cfg.Mode.H_Sync_Active_High) or
Nico Huberabb16d92018-05-29 01:44:26 +0200258 EDP_Select or
Angel Pons450c24c2020-05-13 00:49:52 +0200259 DDI_FUNC_CTL_PORT_WIDTH (Lane_Count));
Nico Huber7ad2d652016-12-07 15:19:32 +0100260 end if;
261
262 Registers.Write
263 (Register => Trans.CONF,
264 Value => TRANS_CONF_ENABLE or
265 (if not Config.Has_Pipeconf_Misc then
266 BPC_Conf (Port_Cfg.Mode.BPC, Dither) else 0));
267 Registers.Posting_Read (Trans.CONF);
268 end On;
269
270 ----------------------------------------------------------------------------
271
272 procedure Trans_Off (Trans : Transcoder_Regs)
273 is
274 Enabled : Boolean;
275 begin
276 Registers.Is_Set_Mask (Trans.CONF, TRANS_CONF_ENABLE, Enabled);
277
278 if Enabled then
279 Registers.Unset_Mask (Trans.CONF, TRANS_CONF_ENABLE);
280 end if;
281
282 -- Workaround for Broadwell:
283 -- Status may be wrong if pipe hasn't been enabled since reset.
284 if not Config.Pipe_Enabled_Workaround or else Enabled then
285 -- synchronously wait until pipe is truly off
286 Registers.Wait_Unset_Mask
287 (Register => Trans.CONF,
288 Mask => TRANS_CONF_ENABLED_STATUS,
289 TOut_MS => 40);
290 end if;
291
292 if Config.Has_Pipe_DDI_Func then
293 Registers.Write (Trans.DDI_FUNC_CTL, 0);
294 end if;
295 end Trans_Off;
296
297 procedure Off (Pipe : Pipe_Index)
298 is
299 DDI_Func_Ctl : Word32;
300 begin
301 if Config.Has_EDP_Transcoder then
302 Registers.Read (Registers.PIPE_EDP_DDI_FUNC_CTL, DDI_Func_Ctl);
303 DDI_Func_Ctl := DDI_Func_Ctl and DDI_FUNC_CTL_EDP_SELECT_MASK;
304
305 if (Pipe = Primary and
306 DDI_Func_Ctl = DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON) or
Nico Huberabb16d92018-05-29 01:44:26 +0200307 DDI_Func_Ctl = DDI_FUNC_CTL_EDP_SELECT (Pipe)
Nico Huber7ad2d652016-12-07 15:19:32 +0100308 then
309 Trans_Off (Transcoders (Trans_EDP));
310 end if;
311 end if;
312
313 Trans_Off (Transcoders (Default_Transcoder (Pipe)));
314 end Off;
315
316 procedure Clk_Off (Pipe : Pipe_Index)
317 is
318 use type Registers.Registers_Invalid_Index;
319
320 Trans : Transcoder_Regs renames Transcoders (Default_Transcoder (Pipe));
321 begin
322 if Config.Has_Trans_Clk_Sel and then
323 Trans.CLK_SEL /= Registers.Invalid_Register
324 then
325 Registers.Write (Trans.CLK_SEL, TRANS_CLK_SEL_PORT_NONE);
326 end if;
327 end Clk_Off;
328
Angel Pons3f86b0b2020-07-18 00:22:32 +0200329 ----------------------------------------------------------------------------
330
331 SRD_CTL_ENABLE : constant := 1 * 2 ** 31;
332 SRD_STATUS_STATE_MASK : constant := 7 * 2 ** 29;
333
334 type SRD_Regs is record
335 CTL : Registers.Registers_Index;
336 STATUS : Registers.Registers_Index;
337 end record;
338 type SRD_Per_Pipe_Regs is array (Transcoder_Index) of SRD_Regs;
339
340 SRD : constant SRD_Per_Pipe_Regs := SRD_Per_Pipe_Regs'
341 (Trans_EDP => SRD_Regs'
342 (CTL => Registers.SRD_CTL_EDP,
343 STATUS => Registers.SRD_STATUS_EDP),
344 Trans_A => SRD_Regs'
345 (CTL => Registers.SRD_CTL_A,
346 STATUS => Registers.SRD_STATUS_A),
347 Trans_B => SRD_Regs'
348 (CTL => Registers.SRD_CTL_B,
349 STATUS => Registers.SRD_STATUS_B),
350 Trans_C => SRD_Regs'
351 (CTL => Registers.SRD_CTL_C,
352 STATUS => Registers.SRD_STATUS_C));
353
354 ----------------------------------------------------------------------------
355
356 procedure PSR_Off
357 is
358 Enabled : Boolean;
359 begin
360 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
361
362 if Config.Has_Per_Pipe_SRD then
363 for P in Transcoder_Index loop
364 Registers.Is_Set_Mask (SRD (P).CTL, SRD_CTL_ENABLE, Enabled);
365 if Enabled then
366 Registers.Unset_Mask (SRD (P).CTL, SRD_CTL_ENABLE);
367 Registers.Wait_Unset_Mask (SRD (P).STATUS, SRD_STATUS_STATE_MASK);
368
369 pragma Debug (Debug.Put_Line ("Disabled PSR."));
370 end if;
371 end loop;
372 else
373 Registers.Is_Set_Mask (Registers.SRD_CTL, SRD_CTL_ENABLE, Enabled);
374 if Enabled then
375 Registers.Unset_Mask (Registers.SRD_CTL, SRD_CTL_ENABLE);
376 Registers.Wait_Unset_Mask (Registers.SRD_STATUS, SRD_STATUS_STATE_MASK);
377
378 pragma Debug (Debug.Put_Line ("Disabled PSR."));
379 end if;
380 end if;
381 end PSR_Off;
382
383 ----------------------------------------------------------------------------
384
Nico Huber7ad2d652016-12-07 15:19:32 +0100385end HW.GFX.GMA.Transcoder;