blob: 84eb4b0be2e83da1bcc19a28677b138cba4f0f3f [file] [log] [blame]
Tim Wawrzynczak5473d292023-02-06 16:46:33 -07001--
2-- Copyright (C) 2022 Google, LLC
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
Tim Wawrzynczak5473d292023-02-06 16:46:33 -070015with HW.GFX.DP_Info;
16with HW.GFX.GMA.PCode;
17
18with HW.Debug;
19with GNAT.Source_Info;
20
21use type HW.Word64;
22
23package body HW.GFX.GMA.Connectors.TC is
24
25 function HIP_INDEX_REG (P : USBC_Port) return Registers.Registers_Index
26 is
27 (if P <= DDI_TC4
28 then Registers.HIP_INDEX_REG0
29 else Registers.HIP_INDEX_REG1);
30
31 function HIP_INDEX_VAL (P : USBC_Port; Val : Word32) return Word32 is
32 (Val * 2 ** (8 * ((GPU_Port'Pos (P) - GPU_Port'Pos (DDI_TC1)) mod 4)));
33
Tim Wawrzynczak5473d292023-02-06 16:46:33 -070034 DKL_DP_MODE : constant Port_Regs_Array :=
35 (DDI_TC1 => Registers.DKL_DP_MODE_1,
36 DDI_TC2 => Registers.DKL_DP_MODE_2,
37 DDI_TC3 => Registers.DKL_DP_MODE_3,
38 DDI_TC4 => Registers.DKL_DP_MODE_4,
39 DDI_TC5 => Registers.DKL_DP_MODE_5,
40 DDI_TC6 => Registers.DKL_DP_MODE_6);
41
Nico Huberac2a1412026-07-02 10:41:59 +020042 function DP_PIN_ASSIGNMENT_SHIFT (P : USBC_Port) return Natural is
Tim Wawrzynczak5473d292023-02-06 16:46:33 -070043 (case P is
44 when DDI_TC1 => 0,
45 when DDI_TC2 => 4,
46 when DDI_TC3 => 8,
47 when DDI_TC4 => 12,
48 when DDI_TC5 => 16,
49 when DDI_TC6 => 20);
50
51 DP_PIN_ASSIGNMENT_MASK : constant := 16#f#;
52
53 TGL_PCODE_TCCOLD : constant := 16#26#;
54 TCCOLD_BLOCK_REQ : constant := 16#00#;
55 TCCOLD_UNBLOCK_REQ : constant := 16#01#;
56 TCCOLD_BLOCK_RESULT_FAIL : constant := 16#01#;
57
Tim Wawrzynczak5473d292023-02-06 16:46:33 -070058 type Buffer_Trans is record
59 Vswing_Control : Word32;
60 Preshoot_Control : Word32;
61 Deemphasis_Control : Word32;
62 end record;
63
Nico Huberac2a1412026-07-02 10:41:59 +020064 type Buffer_Trans_Range is new Natural range 0 .. 9;
Tim Wawrzynczak5473d292023-02-06 16:46:33 -070065 type Buffer_Trans_Array is array (Buffer_Trans_Range) of Buffer_Trans;
66 TGL_Buffer_Trans_DP_HBR2 : constant Buffer_Trans_Array :=
67 ((16#7#, 16#0#, 16#00#),
68 (16#5#, 16#0#, 16#05#),
69 (16#2#, 16#0#, 16#0B#),
70 (16#0#, 16#0#, 16#19#),
71 (16#5#, 16#0#, 16#00#),
72 (16#2#, 16#0#, 16#08#),
73 (16#0#, 16#0#, 16#14#),
74 (16#2#, 16#0#, 16#00#),
75 (16#0#, 16#0#, 16#0B#),
76 (16#0#, 16#0#, 16#00#));
77 TGL_Buffer_Trans_DP_HBR : constant Buffer_Trans_Array :=
78 ((16#7#, 16#0#, 16#00#),
79 (16#5#, 16#0#, 16#05#),
80 (16#2#, 16#0#, 16#0B#),
81 (16#0#, 16#0#, 16#18#),
82 (16#5#, 16#0#, 16#00#),
83 (16#2#, 16#0#, 16#08#),
84 (16#0#, 16#0#, 16#14#),
85 (16#2#, 16#0#, 16#00#),
86 (16#0#, 16#0#, 16#0B#),
87 (16#0#, 16#0#, 16#00#));
88 Buffer_Trans_HDMI : constant Buffer_Trans_Array :=
89 ((16#7#, 16#0#, 16#0#),
90 (16#6#, 16#0#, 16#0#),
91 (16#4#, 16#0#, 16#0#),
92 (16#2#, 16#0#, 16#0#),
93 (16#0#, 16#0#, 16#0#),
94 (16#0#, 16#0#, 16#5#),
95 (16#0#, 16#0#, 16#6#),
96 (16#0#, 16#0#, 16#7#),
97 (16#0#, 16#0#, 16#8#),
98 (16#0#, 16#0#, 16#A#));
99 ADL_Buffer_Trans_DP_HBR2 : constant Buffer_Trans_Array :=
100 ((16#7#, 16#0#, 16#00#),
101 (16#5#, 16#0#, 16#04#),
102 (16#2#, 16#0#, 16#0a#),
103 (16#0#, 16#0#, 16#18#),
104 (16#5#, 16#0#, 16#00#),
105 (16#2#, 16#0#, 16#06#),
106 (16#0#, 16#0#, 16#14#),
107 (16#2#, 16#0#, 16#00#),
108 (16#0#, 16#0#, 16#09#),
109 (16#0#, 16#0#, 16#00#));
110 ADL_Buffer_Trans_DP_HBR : constant Buffer_Trans_Array :=
111 ((16#7#, 16#0#, 16#01#),
112 (16#5#, 16#0#, 16#06#),
113 (16#2#, 16#0#, 16#0b#),
114 (16#0#, 16#0#, 16#17#),
115 (16#5#, 16#0#, 16#00#),
116 (16#2#, 16#0#, 16#08#),
117 (16#0#, 16#0#, 16#14#),
118 (16#2#, 16#0#, 16#00#),
119 (16#0#, 16#0#, 16#0b#),
120 (16#0#, 16#0#, 16#00#));
121
122 type Vswing_Regs_Record is record
123 DKL_TX_PMD_LANE_SUS : Registers.Registers_Index;
124 DKL_TX_DPCNTL0 : Registers.Registers_Index;
125 DKL_TX_DPCNTL1 : Registers.Registers_Index;
126 DKL_TX_DPCNTL2 : Registers.Registers_Index;
127 end record;
128
129 Vswing_Regs : constant array (USBC_Port) of Vswing_Regs_Record :=
130 (DDI_TC1 =>
131 (Registers.DKL_TX_PMD_LANE_SUS_1,
132 Registers.DKL_TX_DPCNTL0_1,
133 Registers.DKL_TX_DPCNTL1_1,
134 Registers.DKL_TX_DPCNTL2_1),
135 DDI_TC2 =>
136 (Registers.DKL_TX_PMD_LANE_SUS_2,
137 Registers.DKL_TX_DPCNTL0_2,
138 Registers.DKL_TX_DPCNTL1_2,
139 Registers.DKL_TX_DPCNTL2_2),
140 DDI_TC3 =>
141 (Registers.DKL_TX_PMD_LANE_SUS_3,
142 Registers.DKL_TX_DPCNTL0_3,
143 Registers.DKL_TX_DPCNTL1_3,
144 Registers.DKL_TX_DPCNTL2_3),
145 DDI_TC4 =>
146 (Registers.DKL_TX_PMD_LANE_SUS_4,
147 Registers.DKL_TX_DPCNTL0_4,
148 Registers.DKL_TX_DPCNTL1_4,
149 Registers.DKL_TX_DPCNTL2_4),
150 DDI_TC5 =>
151 (Registers.DKL_TX_PMD_LANE_SUS_5,
152 Registers.DKL_TX_DPCNTL0_5,
153 Registers.DKL_TX_DPCNTL1_5,
154 Registers.DKL_TX_DPCNTL2_5),
155 DDI_TC6 =>
156 (Registers.DKL_TX_PMD_LANE_SUS_6,
157 Registers.DKL_TX_DPCNTL0_6,
158 Registers.DKL_TX_DPCNTL1_6,
159 Registers.DKL_TX_DPCNTL2_6));
160
161 procedure Set_HIP_For_Port (P : USBC_Port; N : Natural) is
162 begin
163 Registers.Write (HIP_INDEX_REG (P), HIP_INDEX_VAL (P, Word32 (N)));
164 end Set_HIP_For_Port;
165
Nico Huberac2a1412026-07-02 10:41:59 +0200166 subtype Pin_Assignment_Type is Natural range 0 .. 6;
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700167 procedure Get_Pin_Assignment
168 (P : in USBC_Port;
169 Assignment : out Pin_Assignment_Type)
170 is
171 Tmp : Word32;
172 A : Word32;
173 begin
174 Registers.Read (Fia_Regs (P).PORT_TX_DFLEXPA1, Tmp);
175 A := Shift_Right (Tmp, DP_PIN_ASSIGNMENT_SHIFT (P));
176 A := A and DP_PIN_ASSIGNMENT_MASK;
177
Nico Huberac2a1412026-07-02 10:41:59 +0200178 if Natural (A) in Pin_Assignment_Type then
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700179 Assignment := Pin_Assignment_Type (A);
180 else
181 Assignment := Pin_Assignment_Type'First;
182 end if;
183 end Get_Pin_Assignment;
184
185 ---------------------------------------------------------------------
186
187 procedure Program_DP_Mode (P : USBC_Port; Lane_Count : Natural)
188 is
189 MG_DP_MODE_CFG_DP_X1_MODE : constant := 1 * 2 ** 6;
190 MG_DP_MODE_CFG_DP_X2_MODE : constant := 1 * 2 ** 7;
191 DP_X_MODE_MASK : constant Word32 :=
192 MG_DP_MODE_CFG_DP_X1_MODE or MG_DP_MODE_CFG_DP_X2_MODE;
193 Assignment : Pin_Assignment_Type;
194 Ln0, Ln1 : Word32;
195 begin
196 Set_HIP_For_Port (P, 0);
197 Registers.Read (DKL_DP_MODE (P), Ln0);
198 Set_HIP_For_Port (P, 1);
199 Registers.Read (DKL_DP_MODE (P), Ln1);
200
201 Ln0 := Ln0 and not DP_X_MODE_MASK;
202 Ln1 := Ln1 and not DP_X_MODE_MASK;
203
204 Get_Pin_Assignment (P, Assignment);
205 case Assignment is
206 when 0 =>
207 if Lane_Count = 1 then
208 Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X1_MODE;
209 else
210 Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X2_MODE;
211 Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X2_MODE;
212 end if;
213 when 1 =>
214 if Lane_Count = 4 then
215 Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X2_MODE;
216 Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X2_MODE;
217 end if;
218 when 2 =>
219 if Lane_Count = 2 then
220 Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X2_MODE;
221 Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X2_MODE;
222 end if;
223 when 3 | 4 | 5 | 6 =>
224 if Lane_Count = 1 then
225 Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X1_MODE;
226 Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X1_MODE;
227 else
228 Ln0 := Ln0 or MG_DP_MODE_CFG_DP_X2_MODE;
229 Ln1 := Ln1 or MG_DP_MODE_CFG_DP_X2_MODE;
230 end if;
231 end case;
232
233 Set_HIP_For_Port (P, 0);
234 Registers.Unset_And_Set_Mask (DKL_DP_MODE (P), DP_X_MODE_MASK, Ln0);
235 Set_HIP_For_Port (P, 1);
236 Registers.Unset_And_Set_Mask (DKL_DP_MODE (P), DP_X_MODE_MASK, Ln1);
237 end Program_DP_Mode;
238
239 ---------------------------------------------------------------------
240
241 procedure TC_Cold_Request
242 (Request : in TC_Cold_Request_Type;
243 Success : out Boolean)
244 is
245 Result : Word64;
246 begin
247 for Try in 1 .. 3 loop
248 PCode.Mailbox_Read
249 (MBox => TGL_PCODE_TCCOLD,
250 Command => (if Request = Block
251 then TCCOLD_BLOCK_REQ
252 else TCCOLD_UNBLOCK_REQ),
253 Wait_Ready => True,
254 Reply => Result,
255 Success => Success);
256
257 if Success then
258 Success := (Result and TCCOLD_BLOCK_RESULT_FAIL) = 0;
259 end if;
260
261 exit when Success;
262
263 -- Wait 1 millisecond and try again
264 Time.U_Delay (1_000);
265 end loop;
266 end TC_Cold_Request;
267
268 ---------------------------------------------------------------------
269
Nico Huberc74eafd2024-07-23 12:38:02 +0200270 procedure Set_Lane_Count (Port : USBC_Port; Lanes : DP_Lane_Count) is
271 begin
272 Registers.Unset_And_Set_Mask
273 (Register => Fia_Regs (Port).PORT_TX_DFLEXDPMLE1,
274 Mask_Unset => DFLEXDPMLE1_DPMLETC_MASK (Port),
275 Mask_Set =>
276 (case Lanes is
277 -- ML0 is not lane-reversed, ML3 is reverse
278 when DP_Lane_Count_1 => DFLEXDPMLE1_DPMLETC_ML0 (Port),
279 -- ML1_0 is not reversed, ML3_2 is reverse
280 when DP_Lane_Count_2 => DFLEXDPMLE1_DPMLETC_ML1_0 (Port),
281 -- symmetric
282 when DP_Lane_Count_4 => DFLEXDPMLE1_DPMLETC_ML3_0 (Port)));
283 end Set_Lane_Count;
284
285 procedure Get_Lane_Assignment_Count
286 (Port : in USBC_Port;
287 Lanes : out DP_Lane_Count)
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700288 is
Nico Huberc74eafd2024-07-23 12:38:02 +0200289 Lane_Mask : Word32;
290 Tmp : Word32;
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700291 begin
Nico Huberc74eafd2024-07-23 12:38:02 +0200292 Registers.Read (Fia_Regs (Port).PORT_TX_DFLEXDPSP, Tmp);
293 Lane_Mask := Shift_Right (Tmp and DP_LANE_ASSIGNMENT_MASK (Port),
294 DP_LANE_ASSIGNMENT_SHIFT (Port));
295 Lanes :=
296 (case Lane_Mask is
297 when 16#1# | 16#2# | 16#4# | 16#8# => DP_Lane_Count_1,
298 when 16#3# | 16#c# => DP_Lane_Count_2,
299 when 16#f# => DP_Lane_Count_4,
300 when others => DP_Lane_Count_1);
301 end Get_Lane_Assignment_Count;
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700302
303 ---------------------------------------------------------------------
304
305 procedure Set_Vswing_And_Deemphasis
306 (Port : USBC_Port;
307 Buf_Trans : Buffer_Trans)
308 is
309 -- Preshoot Coeff, Deemphasis Coeff, VSwing Control,
310 DPcnt_Mask : constant Word32 := 16#3_ff07#;
311 DPcnt_Val : constant Word32 :=
312 Buf_Trans.Vswing_Control or
313 Shift_Left (Buf_Trans.Deemphasis_Control, 8) or
314 Shift_Left (Buf_Trans.Preshoot_Control, 13);
315 DKL_TX_DP20BITMODE : constant := 1 * 2 ** 2;
316 begin
317 for Lane in 0 .. 1 loop
318 Set_HIP_For_Port (Port, Lane);
319 Registers.Write (Vswing_Regs (Port).DKL_TX_PMD_LANE_SUS, 0);
320 Registers.Unset_And_Set_Mask
321 (Vswing_Regs (Port).DKL_TX_DPCNTL0, DPcnt_Mask, DPcnt_Val);
322 Registers.Unset_And_Set_Mask
323 (Vswing_Regs (Port).DKL_TX_DPCNTL1, DPcnt_Mask, DPcnt_Val);
324 Registers.Unset_Mask
325 (Vswing_Regs (Port).DKL_TX_DPCNTL2, DKL_TX_DP20BITMODE);
326 end loop;
327
328 end Set_Vswing_And_Deemphasis;
329
330 ---------------------------------------------------------------------
331
332 procedure Set_Signal_Levels
333 (Port : USBC_Port;
334 Link : DP_Link;
335 Train_Set : DP_Info.Train_Set)
336 is
337 function To_Buf_Trans_Index
338 (Set : DP_Info.Train_Set) return Buffer_Trans_Range
339 is
340 begin
341 case Set.Voltage_Swing is
342 when DP_Info.VS_Level_0 =>
343 case Set.Pre_Emph is
344 when DP_Info.Emph_Level_0 => return 0;
345 when DP_Info.Emph_Level_1 => return 1;
346 when DP_Info.Emph_Level_2 => return 2;
347 when DP_Info.Emph_Level_3 => return 3;
348 end case;
349 when DP_Info.VS_Level_1 =>
350 case Set.Pre_Emph is
351 when DP_Info.Emph_Level_0 => return 4;
352 when DP_Info.Emph_Level_1 => return 5;
353 when DP_Info.Emph_Level_2 => return 6;
354 when others => return 0;
355 end case;
356 when DP_Info.VS_Level_2 =>
357 case Set.Pre_Emph is
358 when DP_Info.Emph_Level_0 => return 7;
359 when DP_Info.Emph_Level_1 => return 8;
360 when others => return 0;
361 end case;
362 when DP_Info.VS_Level_3 =>
363 case Set.Pre_Emph is
364 when DP_Info.Emph_Level_0 => return 9;
365 when others => return 0;
366 end case;
367 end case;
368 end To_Buf_Trans_Index;
369
370 Was_Enabled : Boolean;
371 Buf_Trans : Buffer_Trans;
372 Entry_Index : constant Buffer_Trans_Range :=
373 To_Buf_Trans_Index (Train_Set);
374 begin
375 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
376
377 Registers.Is_Set_Mask
378 (Register => DDI_BUF_CTL (Port),
379 Mask => DDI_BUF_CTL_BUFFER_ENABLE,
380 Result => Was_Enabled);
381
382 if Config.Has_TGL_Buffer_Translations then
383 if Link.Bandwidth > DP_Bandwidth_2_7 then
384 Buf_Trans := TGL_Buffer_Trans_DP_HBR2 (Entry_Index);
385 else
386 Buf_Trans := TGL_Buffer_Trans_DP_HBR (Entry_Index);
387 end if;
388 else
389 if Link.Bandwidth > DP_Bandwidth_2_7 then
390 Buf_Trans := ADL_Buffer_Trans_DP_HBR2 (Entry_Index);
391 else
392 Buf_Trans := ADL_Buffer_Trans_DP_HBR (Entry_Index);
393 end if;
394 end if;
395
396 Set_Vswing_And_Deemphasis (Port, Buf_Trans);
397
398 Registers.Unset_And_Set_Mask
399 (Register => DDI_BUF_CTL (Port),
400 Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
401 DDI_BUF_CTL_PORT_REVERSAL or
402 DDI_BUF_CTL_PORT_WIDTH_MASK,
403 Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE or
404 DDI_BUF_CTL_PORT_WIDTH (Link.Lane_Count));
405 Registers.Posting_Read (DDI_BUF_CTL (Port));
406
407 if not Was_Enabled then
408 Registers.Wait_Unset_Mask (DDI_BUF_CTL (Port), DDI_BUF_CTL_IDLE_STATUS);
409 end if;
410 end Set_Signal_Levels;
411
412 procedure Enable_HDMI (Port : USBC_Port)
413 is
414 HDMI_Lane_Count : constant := 4;
415 Buf_Trans : constant Buffer_Trans :=
416 Buffer_Trans_HDMI (Buffer_Trans_HDMI'Last);
417 begin
418 Program_DP_Mode (Port, HDMI_Lane_Count);
419 Set_Vswing_And_Deemphasis (Port, Buf_Trans);
420
421 Registers.Unset_And_Set_Mask
422 (Register => DDI_BUF_CTL (Port),
423 Mask_Unset => DDI_BUF_CTL_TRANS_SELECT_MASK or
424 DDI_BUF_CTL_PORT_REVERSAL or
425 DDI_BUF_CTL_PORT_WIDTH_MASK,
426 Mask_Set => DDI_BUF_CTL_BUFFER_ENABLE);
427
428 Registers.Wait_Unset_Mask
429 (Register => DDI_BUF_CTL (Port),
430 Mask => DDI_BUF_CTL_IDLE_STATUS,
431 TOut_MS => 1);
432 end Enable_HDMI;
433
434end HW.GFX.GMA.Connectors.TC;