blob: 91ef6b6f9b9a2be9fe8ee61f80827273427d45b1 [file] [log] [blame]
Nico Huber7ad2d652016-12-07 15:19:32 +01001--
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
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
18with HW.GFX.GMA.Config;
19with 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;
42
43 type TRANS_CLK_SEL_PORT_Array is
44 array (Digital_Port) of Word32;
45 TRANS_CLK_SEL_PORT : constant TRANS_CLK_SEL_PORT_Array :=
46 (DIGI_A => 0 * 2 ** 29, -- DDI A is not selectable
47 DIGI_B => 2 * 2 ** 29,
48 DIGI_C => 3 * 2 ** 29,
49 DIGI_D => 4 * 2 ** 29,
50 DIGI_E => 5 * 2 ** 29);
51
52 TRANS_CONF_ENABLE : constant := 1 * 2 ** 31;
53 TRANS_CONF_ENABLED_STATUS : constant := 1 * 2 ** 30;
54 TRANS_CONF_ENABLE_DITHER : constant := 1 * 2 ** 4;
55
56 type BPC_Array is array (BPC_Type) of Word32;
57 TRANS_CONF_BPC : constant BPC_Array :=
58 (6 => 2 * 2 ** 5,
59 8 => 0 * 2 ** 5,
60 10 => 1 * 2 ** 5,
61 12 => 3 * 2 ** 5,
62 others => 0 * 2 ** 5); -- default to 8 BPC
63
64 function BPC_Conf (BPC : BPC_Type; Dither : Boolean) return Word32 is
65 begin
66 return
67 (if Config.Has_Pipeconf_BPC then TRANS_CONF_BPC (BPC) else 0) or
68 (if Dither then TRANS_CONF_ENABLE_DITHER else 0);
69 end BPC_Conf;
70
71 ----------------------------------------------------------------------------
72
73 DDI_FUNC_CTL_ENABLE : constant := 1 * 2 ** 31;
74 DDI_FUNC_CTL_MODE_SELECT_MASK : constant := 7 * 2 ** 24;
75 DDI_FUNC_CTL_MODE_SELECT_HDMI : constant := 0 * 2 ** 24;
76 DDI_FUNC_CTL_MODE_SELECT_DVI : constant := 1 * 2 ** 24;
77 DDI_FUNC_CTL_MODE_SELECT_DP_SST : constant := 2 * 2 ** 24;
78 DDI_FUNC_CTL_MODE_SELECT_DP_MST : constant := 3 * 2 ** 24;
79 DDI_FUNC_CTL_MODE_SELECT_FDI : constant := 4 * 2 ** 24;
80 DDI_FUNC_CTL_EDP_SELECT_MASK : constant := 7 * 2 ** 12;
81 DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON : constant := 0 * 2 ** 12;
82 DDI_FUNC_CTL_EDP_SELECT_A : constant := 4 * 2 ** 12;
83 DDI_FUNC_CTL_EDP_SELECT_B : constant := 5 * 2 ** 12;
84 DDI_FUNC_CTL_EDP_SELECT_C : constant := 6 * 2 ** 12;
85
86 type DDI_Select_Array is array (Digital_Port) of Word32;
87 DDI_FUNC_CTL_DDI_SELECT : constant DDI_Select_Array :=
88 (DIGI_A => 0 * 2 ** 28,
89 DIGI_B => 1 * 2 ** 28,
90 DIGI_C => 2 * 2 ** 28,
91 DIGI_D => 3 * 2 ** 28,
92 DIGI_E => 4 * 2 ** 28);
93
94 type DDI_Mode_Array is array (Display_Type) of Word32;
95 DDI_FUNC_CTL_MODE_SELECT : constant DDI_Mode_Array :=
96 (VGA => DDI_FUNC_CTL_MODE_SELECT_FDI,
97 HDMI => DDI_FUNC_CTL_MODE_SELECT_DVI,
98 DP => DDI_FUNC_CTL_MODE_SELECT_DP_SST,
99 others => 0);
100
101 type HV_Sync_Array is array (Boolean) of Word32;
102 DDI_FUNC_CTL_VSYNC : constant HV_Sync_Array :=
103 (False => 0 * 2 ** 17,
104 True => 1 * 2 ** 17);
105 DDI_FUNC_CTL_HSYNC : constant HV_Sync_Array :=
106 (False => 0 * 2 ** 16,
107 True => 1 * 2 ** 16);
108
109 type EDP_Select_Array is array (Pipe_Index) of Word32;
110 DDI_FUNC_CTL_EDP_SELECT : constant EDP_Select_Array :=
111 (Primary => DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON, -- we never use
112 -- panel fitter
113 Secondary => DDI_FUNC_CTL_EDP_SELECT_B,
114 Tertiary => DDI_FUNC_CTL_EDP_SELECT_C);
115 DDI_FUNC_CTL_EDP_SELECT_ONOFF : constant EDP_Select_Array :=
116 (Primary => DDI_FUNC_CTL_EDP_SELECT_A,
117 Secondary => DDI_FUNC_CTL_EDP_SELECT_B,
118 Tertiary => DDI_FUNC_CTL_EDP_SELECT_C);
119
120 type Port_Width_Array is array (DP_Lane_Count) of Word32;
121 DDI_FUNC_CTL_PORT_WIDTH : constant Port_Width_Array :=
122 (DP_Lane_Count_1 => 0 * 2 ** 1,
123 DP_Lane_Count_2 => 1 * 2 ** 1,
124 DP_Lane_Count_4 => 3 * 2 ** 1);
125
126 DDI_FUNC_CTL_BPC : constant BPC_Array :=
127 (6 => 2 * 2 ** 20,
128 8 => 0 * 2 ** 20,
129 10 => 1 * 2 ** 20,
130 12 => 3 * 2 ** 20,
131 others => 0 * 2 ** 20); -- default to 8 BPC
132
133 ----------------------------------------------------------------------------
134
135 TRANS_MSA_MISC_SYNC_CLK : constant := 1 * 2 ** 0;
136 TRANS_MSA_MISC_BPC : constant BPC_Array :=
137 (6 => 0 * 2 ** 5,
138 8 => 1 * 2 ** 5,
139 10 => 2 * 2 ** 5,
140 12 => 3 * 2 ** 5,
141 16 => 4 * 2 ** 5,
142 others => 1 * 2 ** 5); -- default to 8 BPC
143
144 function TRANS_DATA_M_TU (Transfer_Unit : Positive) return Word32 is
145 begin
146 return Shift_Left (Word32 (Transfer_Unit - 1), 25);
147 end TRANS_DATA_M_TU;
148
149 ----------------------------------------------------------------------------
150
151 function Encode (LSW, MSW : Pos16) return Word32
152 is
Nico Huber31a52172017-03-05 14:17:34 +0100153 pragma Warnings (GNAT, Off, """Integer_16"" is already use-visible *",
154 Reason => "Needed for older compiler versions");
Nico Huber7ad2d652016-12-07 15:19:32 +0100155 use type HW.Pos16;
Nico Huber31a52172017-03-05 14:17:34 +0100156 pragma Warnings (GNAT, On, """Integer_16"" is already use-visible *");
Nico Huber7ad2d652016-12-07 15:19:32 +0100157 begin
158 return Shift_Left (Word32 (MSW - 1), 16) or Word32 (LSW - 1);
159 end Encode;
160
161 ----------------------------------------------------------------------------
162
163 procedure Setup_Link
164 (Trans : Transcoder_Regs;
165 Link : DP_Link;
166 Mode : Mode_Type)
167 with
168 Global => (In_Out => Registers.Register_State),
169 Depends => (Registers.Register_State =>+ (Trans, Link, Mode))
170 is
171 Data_M, Link_M : DP_Info.M_Type;
172 Data_N, Link_N : DP_Info.N_Type;
173 begin
174 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
175
176 DP_Info.Calculate_M_N
177 (Link => Link,
178 Mode => Mode,
179 Data_M => Data_M,
180 Data_N => Data_N,
181 Link_M => Link_M,
182 Link_N => Link_N);
183
184 Registers.Write
185 (Register => Trans.DATA_M1,
186 Value => TRANS_DATA_M_TU (64) or
187 Word32 (Data_M));
188 Registers.Write
189 (Register => Trans.DATA_N1,
190 Value => Word32 (Data_N));
191
192 Registers.Write
193 (Register => Trans.LINK_M1,
194 Value => Word32 (Link_M));
195 Registers.Write
196 (Register => Trans.LINK_N1,
197 Value => Word32 (Link_N));
198
199 if Config.Has_Pipe_MSA_Misc then
200 Registers.Write
201 (Register => Trans.MSA_MISC,
202 Value => TRANS_MSA_MISC_SYNC_CLK or
203 TRANS_MSA_MISC_BPC (Mode.BPC));
204 end if;
205 end Setup_Link;
206
207 ----------------------------------------------------------------------------
208
209 procedure Setup
210 (Pipe : Pipe_Index;
211 Port_Cfg : Port_Config)
212 is
213 use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
214
215 Trans : Transcoder_Regs renames
216 Transcoders (Get_Idx (Pipe, Port_Cfg.Port));
217 M : constant Mode_Type := Port_Cfg.Mode;
218 begin
219 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
220
221 if Config.Has_Trans_Clk_Sel and then
222 Trans.CLK_SEL /= Registers.Invalid_Register
223 then
224 Registers.Write
225 (Register => Trans.CLK_SEL,
226 Value => TRANS_CLK_SEL_PORT (Port_Cfg.Port));
227 end if;
228
229 if Port_Cfg.Is_FDI then
230 Setup_Link (Trans, Port_Cfg.FDI, Port_Cfg.Mode);
231 elsif Port_Cfg.Display = DP then
232 Setup_Link (Trans, Port_Cfg.DP, Port_Cfg.Mode);
233 end if;
234
235 Registers.Write (Trans.HTOTAL, Encode (M.H_Visible, M.H_Total));
236 Registers.Write (Trans.HBLANK, Encode (M.H_Visible, M.H_Total));
237 Registers.Write (Trans.HSYNC, Encode (M.H_Sync_Begin, M.H_Sync_End));
238 Registers.Write (Trans.VTOTAL, Encode (M.V_Visible, M.V_Total));
239 Registers.Write (Trans.VBLANK, Encode (M.V_Visible, M.V_Total));
240 Registers.Write (Trans.VSYNC, Encode (M.V_Sync_Begin, M.V_Sync_End));
241 end Setup;
242
243 ----------------------------------------------------------------------------
244
245 procedure On
246 (Pipe : Pipe_Index;
247 Port_Cfg : Port_Config;
248 Dither : Boolean)
249 is
250 Trans : Transcoder_Regs renames
251 Transcoders (Get_Idx (Pipe, Port_Cfg.Port));
252 begin
253 if Config.Has_Pipe_DDI_Func then
254 Registers.Write
255 (Register => Trans.DDI_FUNC_CTL,
256 Value => DDI_FUNC_CTL_ENABLE or
257 DDI_FUNC_CTL_DDI_SELECT (Port_Cfg.Port) or
258 DDI_FUNC_CTL_MODE_SELECT (Port_Cfg.Display) or
259 DDI_FUNC_CTL_BPC (Port_Cfg.Mode.BPC) or
260 DDI_FUNC_CTL_VSYNC (Port_Cfg.Mode.V_Sync_Active_High) or
261 DDI_FUNC_CTL_HSYNC (Port_Cfg.Mode.H_Sync_Active_High) or
262 DDI_FUNC_CTL_EDP_SELECT (Pipe) or
263 DDI_FUNC_CTL_PORT_WIDTH (Port_Cfg.DP.Lane_Count));
264 end if;
265
266 Registers.Write
267 (Register => Trans.CONF,
268 Value => TRANS_CONF_ENABLE or
269 (if not Config.Has_Pipeconf_Misc then
270 BPC_Conf (Port_Cfg.Mode.BPC, Dither) else 0));
271 Registers.Posting_Read (Trans.CONF);
272 end On;
273
274 ----------------------------------------------------------------------------
275
276 procedure Trans_Off (Trans : Transcoder_Regs)
277 is
278 Enabled : Boolean;
279 begin
280 Registers.Is_Set_Mask (Trans.CONF, TRANS_CONF_ENABLE, Enabled);
281
282 if Enabled then
283 Registers.Unset_Mask (Trans.CONF, TRANS_CONF_ENABLE);
284 end if;
285
286 -- Workaround for Broadwell:
287 -- Status may be wrong if pipe hasn't been enabled since reset.
288 if not Config.Pipe_Enabled_Workaround or else Enabled then
289 -- synchronously wait until pipe is truly off
290 Registers.Wait_Unset_Mask
291 (Register => Trans.CONF,
292 Mask => TRANS_CONF_ENABLED_STATUS,
293 TOut_MS => 40);
294 end if;
295
296 if Config.Has_Pipe_DDI_Func then
297 Registers.Write (Trans.DDI_FUNC_CTL, 0);
298 end if;
299 end Trans_Off;
300
301 procedure Off (Pipe : Pipe_Index)
302 is
303 DDI_Func_Ctl : Word32;
304 begin
305 if Config.Has_EDP_Transcoder then
306 Registers.Read (Registers.PIPE_EDP_DDI_FUNC_CTL, DDI_Func_Ctl);
307 DDI_Func_Ctl := DDI_Func_Ctl and DDI_FUNC_CTL_EDP_SELECT_MASK;
308
309 if (Pipe = Primary and
310 DDI_Func_Ctl = DDI_FUNC_CTL_EDP_SELECT_ALWAYS_ON) or
311 DDI_Func_Ctl = DDI_FUNC_CTL_EDP_SELECT_ONOFF (Pipe)
312 then
313 Trans_Off (Transcoders (Trans_EDP));
314 end if;
315 end if;
316
317 Trans_Off (Transcoders (Default_Transcoder (Pipe)));
318 end Off;
319
320 procedure Clk_Off (Pipe : Pipe_Index)
321 is
322 use type Registers.Registers_Invalid_Index;
323
324 Trans : Transcoder_Regs renames Transcoders (Default_Transcoder (Pipe));
325 begin
326 if Config.Has_Trans_Clk_Sel and then
327 Trans.CLK_SEL /= Registers.Invalid_Register
328 then
329 Registers.Write (Trans.CLK_SEL, TRANS_CLK_SEL_PORT_NONE);
330 end if;
331 end Clk_Off;
332
333end HW.GFX.GMA.Transcoder;