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