blob: cac0cab5df57c28b0cf31f8e4a3b6e54c6b0828c [file] [log] [blame]
Tim Wawrzynczak605660b2022-06-08 12:48:19 -06001--
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.GMA.DP_Aux_Ch;
16with HW.GFX.DP_Training;
17with HW.GFX.GMA.Combo_Phy;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060018with HW.GFX.GMA.Config;
Tim Wawrzynczak5473d292023-02-06 16:46:33 -070019with HW.GFX.GMA.Config_Helpers;
20with HW.GFX.GMA.Connectors.TC;
Nico Huberc74eafd2024-07-23 12:38:02 +020021with HW.GFX.GMA.Connectors.TC.Ownership;
Tim Wawrzynczak5473d292023-02-06 16:46:33 -070022with HW.GFX.GMA.Connectors.Combo_Phy;
23with HW.GFX.GMA.DP_Aux_Request;
24with HW.GFX.GMA.DP_Info;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060025with HW.GFX.GMA.Panel;
Tim Wawrzynczak5473d292023-02-06 16:46:33 -070026with HW.GFX.GMA.Power_And_Clocks;
27with HW.GFX.GMA.Registers;
28with HW.GFX.GMA.Transcoder;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060029
30with HW.Debug;
31with GNAT.Source_Info;
32
33package body HW.GFX.GMA.Connectors is
34
Tim Wawrzynczak5473d292023-02-06 16:46:33 -070035 type Pipe_Regs is array (Pipe_Index) of Registers.Registers_Index;
36 DP_TP_CTL : constant Pipe_Regs :=
37 (Primary => Registers.TGL_DP_TP_CTL_A,
38 Secondary => Registers.TGL_DP_TP_CTL_B,
39 Tertiary => Registers.TGL_DP_TP_CTL_C);
40 DP_TP_CTL_TRANSPORT_ENABLE : constant := 1 * 2 ** 31;
41 DP_TP_CTL_MODE_SST : constant := 0 * 2 ** 27;
42 DP_TP_CTL_MODE_MST : constant := 1 * 2 ** 27;
43 DP_TP_CTL_FORCE_ACT : constant := 1 * 2 ** 25;
44 DP_TP_CTL_ENHANCED_FRAME_ENABLE : constant := 1 * 2 ** 18;
45 DP_TP_CTL_LINK_TRAIN_MASK : constant := 7 * 2 ** 8;
46 DP_TP_CTL_LINK_TRAIN_PAT1 : constant := 0 * 2 ** 8;
47 DP_TP_CTL_LINK_TRAIN_PAT2 : constant := 1 * 2 ** 8;
48 DP_TP_CTL_LINK_TRAIN_IDLE : constant := 2 * 2 ** 8;
49 DP_TP_CTL_LINK_TRAIN_NORMAL : constant := 3 * 2 ** 8;
50 DP_TP_CTL_LINK_TRAIN_PAT3 : constant := 4 * 2 ** 8;
51 DP_TP_CTL_LINK_TRAIN_PAT4 : constant := 5 * 2 ** 8;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060052
Tim Wawrzynczak5473d292023-02-06 16:46:33 -070053 DP_TP_STATUS : constant Pipe_Regs :=
54 (Primary => Registers.TGL_DP_TP_STATUS_A,
55 Secondary => Registers.TGL_DP_TP_STATUS_B,
56 Tertiary => Registers.TGL_DP_TP_STATUS_C);
57 DP_TP_STATUS_MIN_IDLES_SENT : constant := 1 * 2 ** 25;
58
59 DDI_BUF_CTL_BUFFER_ENABLE : constant := 1 * 2 ** 31;
60 DDI_BUF_CTL_PORT_WIDTH_MASK : constant := 7 * 2 ** 1;
61 DDI_BUF_CTL_PORT_WIDTH_1_LANE : constant := 0 * 2 ** 1;
62 DDI_BUF_CTL_PORT_WIDTH_2_LANES : constant := 1 * 2 ** 1;
63 DDI_BUF_CTL_PORT_WIDTH_4_LANES : constant := 3 * 2 ** 1;
64 DDI_BUF_CTL_PORT_REVERSAL : constant := 1 * 2 ** 16;
65 DDI_BUF_CTL_IDLE_STATUS : constant := 1 * 2 ** 7;
66 DDI_BUF_CTL_TRANS_SELECT_MASK : constant := 16#f# * 2 ** 24;
67
68 DDI_CLK_SEL_SHIFT : constant array (Combo_Port) of Natural :=
69 (DIGI_A => 0,
70 DIGI_B => 2,
71 DIGI_C => 4);
72
73 function DDI_CLK_OFF (Port : TGL_Digital_Port) return Word32
74 is
75 (case Port is
76 when DIGI_A => 1 * 2 ** 10,
77 when DIGI_B => 1 * 2 ** 11,
78 when DIGI_C => 1 * 2 ** 24,
79 when DDI_TC1 => 1 * 2 ** 12,
80 when DDI_TC2 => 1 * 2 ** 13,
81 when DDI_TC3 => 1 * 2 ** 14,
82 when DDI_TC4 => 1 * 2 ** 21,
83 when DDI_TC5 => 1 * 2 ** 22,
84 when DDI_TC6 => 1 * 2 ** 23,
85 when others => 0);
86
87 function DDI_BUF_CTL (Port : TGL_Digital_Port) return Registers.Registers_Index
88 is
89 (case Port is
90 when DIGI_A => Registers.DDI_BUF_CTL_A,
91 when DIGI_B => Registers.DDI_BUF_CTL_B,
92 when DIGI_C => Registers.DDI_BUF_CTL_C,
93 when DDI_TC1 => Registers.DDI_BUF_CTL_USBC1,
94 when DDI_TC2 => Registers.DDI_BUF_CTL_USBC2,
95 when DDI_TC3 => Registers.DDI_BUF_CTL_USBC3,
96 when DDI_TC4 => Registers.DDI_BUF_CTL_USBC4,
97 when DDI_TC5 => Registers.DDI_BUF_CTL_USBC5,
98 when DDI_TC6 => Registers.DDI_BUF_CTL_USBC6,
99 when others => Registers.DDI_BUF_CTL_A);
100
101 DDI_CLK_SEL : constant array (USBC_Port) of Registers.Registers_Index :=
102 (DDI_TC1 => Registers.DDI_CLK_SEL_USBC1,
103 DDI_TC2 => Registers.DDI_CLK_SEL_USBC2,
104 DDI_TC3 => Registers.DDI_CLK_SEL_USBC3,
105 DDI_TC4 => Registers.DDI_CLK_SEL_USBC4,
106 DDI_TC5 => Registers.DDI_CLK_SEL_USBC5,
107 DDI_TC6 => Registers.DDI_CLK_SEL_USBC6);
108
109 type Training_Port_Info is record
110 Port : TGL_Digital_Port;
111 Pipe : Pipe_Index;
112 eDP : Boolean;
113 end record;
114
115 function To_DP (Port_Info : Training_Port_Info) return DP_Port is
116 (case Port_Info.Port is
117 when DIGI_A => DP_A,
118 when DIGI_B => DP_B,
119 when DIGI_C => DP_C,
120 when DDI_TC1 => DP_D,
121 when DDI_TC2 => DP_E,
122 when DDI_TC3 => DP_F,
123 when DDI_TC4 => DP_G,
124 when DDI_TC5 => DP_H,
125 when DDI_TC6 => DP_I,
126 when others => DP_A);
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600127
Nico Hubera8254482024-07-03 12:23:00 +0200128 ---------------------------------------------------------------------
129
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700130 procedure Off (Pipe : Pipe_Index; Port : TGL_Digital_Port)
131 is
132 Enabled : Boolean;
133 begin
134 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
135 Registers.Is_Set_Mask
136 (Register => DDI_BUF_CTL (Port),
137 Mask => DDI_BUF_CTL_BUFFER_ENABLE,
138 Result => Enabled);
139
140 if Enabled then
141 Registers.Unset_Mask
142 (Register => DDI_BUF_CTL (Port),
143 Mask => DDI_BUF_CTL_BUFFER_ENABLE);
144 end if;
145
146 Registers.Unset_Mask
147 (Register => DP_TP_CTL (Pipe),
148 Mask => DP_TP_CTL_TRANSPORT_ENABLE);
149
150 if Enabled then
151 Registers.Wait_Set_Mask
152 (Register => DDI_BUF_CTL (Port),
153 Mask => DDI_BUF_CTL_IDLE_STATUS);
154 end if;
155
Nico Huberac2a1412026-07-02 10:41:59 +0200156 Registers.Set_Mask
157 (Register => Registers.DPCLKA_CFGCR0,
158 Mask => DDI_CLK_OFF (Port));
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700159 end Off;
160
161 procedure Off (Port_Info : Training_Port_Info) is
162 begin
163 Off (Port_Info.Pipe, Port_Info.Port);
164 end Off;
165
166 ---------------------------------------------------------------------
167
168 procedure Set_TP_CTL
169 (Pipe : Pipe_Index;
170 Link : DP_Link;
171 Pattern : DP_Info.Training_Pattern)
172 is
173 type DP_TP_CTL_LINK_TRAIN_ARRAY is
174 array (DP_Info.Training_Pattern) of Word32;
175 DP_TP_CTL_LINK_TRAIN : constant DP_TP_CTL_LINK_TRAIN_ARRAY :=
176 DP_TP_CTL_LINK_TRAIN_ARRAY'
177 (DP_Info.TP_1 => DP_TP_CTL_LINK_TRAIN_PAT1,
178 DP_Info.TP_2 => DP_TP_CTL_LINK_TRAIN_PAT2,
179 DP_Info.TP_3 => DP_TP_CTL_LINK_TRAIN_PAT3,
180 DP_Info.TP_Idle => DP_TP_CTL_LINK_TRAIN_IDLE,
181 DP_Info.TP_None => DP_TP_CTL_LINK_TRAIN_NORMAL);
182
183 DP_TP_CTL_Enhanced_Frame : Word32 := 0;
184 begin
185 if Link.Enhanced_Framing then
186 DP_TP_CTL_Enhanced_Frame := DP_TP_CTL_ENHANCED_FRAME_ENABLE;
187 end if;
188
189 Registers.Write
190 (Register => DP_TP_CTL (Pipe),
191 Value => DP_TP_CTL_TRANSPORT_ENABLE or
192 DP_TP_CTL_Enhanced_Frame or
193 DP_TP_CTL_MODE_SST or
194 DP_TP_CTL_LINK_TRAIN (Pattern));
195 Registers.Posting_Read (DP_TP_CTL (Pipe));
196 end Set_TP_CTL;
197
198 procedure Set_Training_Pattern
199 (Port_Info : Training_Port_Info;
200 Link : DP_Link;
201 Pattern : DP_Info.Training_Pattern)
202 is
203 use type DP_Info.Training_Pattern;
204 Pipe : Pipe_Index renames Port_Info.Pipe;
205 begin
206 if Pattern < DP_Info.TP_Idle then
207 Set_TP_CTL (Pipe, Link, Pattern);
208 else
209 Set_TP_CTL (Pipe, Link, DP_Info.TP_Idle);
210 Registers.Wait_Set_Mask
211 (Register => DP_TP_STATUS (Pipe),
212 Mask => DP_TP_STATUS_MIN_IDLES_SENT);
213 Set_TP_CTL (Pipe, Link, DP_Info.TP_None);
214 end if;
215 end Set_Training_Pattern;
216
217 ---------------------------------------------------------------------
218
219 pragma Warnings (GNATprove, Off, "unused variable ""Port_Info""",
220 Reason => "Needed for a common interface");
221 function Max_V_Swing
222 (Port_Info : Training_Port_Info) return DP_Info.DP_Voltage_Swing
223 is
224 (DP_Info.VS_Level_3);
225
226 function Max_Pre_Emph
227 (Port_Info : Training_Port_Info;
228 Train_Set : DP_Info.Train_Set)
229 return DP_Info.DP_Pre_Emph
230 is
231 begin
232 return
233 (case Train_Set.Voltage_Swing is
234 when DP_Info.VS_Level_0 => DP_Info.Emph_Level_3,
235 when DP_Info.VS_Level_1 => DP_Info.Emph_Level_2,
236 when DP_Info.VS_Level_2 => DP_Info.Emph_Level_1,
237 when others => DP_Info.Emph_Level_0);
238 end Max_Pre_Emph;
239 pragma Warnings (GNATprove, On, "unused variable ""Port_Info""");
240
241 ---------------------------------------------------------------------
242
243 procedure Set_Signal_Levels
244 (Port_Info : Training_Port_Info;
245 Link : DP_Link;
246 Train_Set : DP_Info.Train_Set)
247 is
248 Port : TGL_Digital_Port renames Port_Info.Port;
249 begin
250 if Port in Combo_Port then
251 Combo_Phy.Set_Signal_Levels (Port, Port_Info.eDP, Link, Train_Set);
252 elsif Port in USBC_Port then
253 TC.Set_Signal_Levels (Port, Link, Train_Set);
254 end if;
255 end Set_Signal_Levels;
256
257 ---------------------------------------------------------------------
258
259 procedure Map_PLL_To_Port
260 (Port : TGL_Digital_Port;
261 PLL_Hint : Word32)
262 is
263 CLOCK_SELECT_MASK : constant := 16#f000_0000#;
264 CLOCK_SELECT_TYPEC : constant := 16#8000_0000#;
265 DDI_CLK_SEL_MASK : constant := 3;
266 Clk_Sel_Shift : Natural;
267 begin
268 if Port in USBC_Port then
269 Registers.Unset_And_Set_Mask
270 (Register => DDI_CLK_SEL (Port),
271 Mask_Unset => CLOCK_SELECT_MASK,
272 Mask_Set => CLOCK_SELECT_TYPEC);
273 end if;
274
275 if Port in Combo_Port then
276 Clk_Sel_Shift := DDI_CLK_SEL_SHIFT (Port);
277 Registers.Unset_And_Set_Mask
278 (Register => Registers.DPCLKA_CFGCR0,
279 Mask_Unset => Shift_Left (DDI_CLK_SEL_MASK, Clk_Sel_Shift),
280 Mask_Set => Shift_Left (PLL_Hint, Clk_Sel_Shift));
281 Registers.Posting_Read (Registers.DPCLKA_CFGCR0);
282 end if;
283 end Map_PLL_To_Port;
284
285 ---------------------------------------------------------------------
286
287 pragma Warnings (GNAT, Off, """Port_Cfg"" is not modified",
288 Reason => "Needed for a common interface");
Nico Hubera8254482024-07-03 12:23:00 +0200289 procedure Prepare
290 (Port : in Active_Port_Type;
291 Port_Cfg : in out Port_Config;
292 Success : out Boolean)
293 is
294 begin
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700295 if Port_Cfg.Port in USBC_Port then
Nico Huberc74eafd2024-07-23 12:38:02 +0200296 TC.Ownership.Connect
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700297 (Port => Port_Cfg.Port,
298 DP_Alt => Port in Physical_USBC_Ports,
299 Lanes => Port_Cfg.DP.Lane_Count,
300 Success => Success);
301 else
302 Success := True;
303 end if;
304 end Prepare;
305 pragma Warnings (GNAT, On, """Port_Cfg"" is not modified");
Nico Hubera8254482024-07-03 12:23:00 +0200306
307 ---------------------------------------------------------------------
308
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600309 procedure Pre_On
310 (Pipe : in Pipe_Index;
311 Port_Cfg : in Port_Config;
312 PLL_Hint : in Word32;
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700313 Success : out Boolean)
314 is
315 package Training is new DP_Training
316 (TPS3_Supported => True,
317 T => Training_Port_Info,
318 Aux_T => DP_Port,
319 Aux_Ch => HW.GFX.GMA.DP_Aux_Ch,
320 DP_Info => DP_Info,
321 To_Aux => To_DP,
322 Max_V_Swing => Max_V_Swing,
323 Max_Pre_Emph => Max_Pre_Emph,
324 Set_Pattern => Set_Training_Pattern,
325 Set_Signal_Levels => Set_Signal_Levels,
326 Off => Off);
327 Port : TGL_Digital_Port;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600328 begin
329 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700330
331 if Port_Cfg.Port not in TGL_Digital_Port then
332 Success := False;
333 return;
334 end if;
335
336 Port := Port_Cfg.Port;
337 Map_PLL_To_Port (Port, PLL_Hint);
338
339 Registers.Unset_Mask
340 (Register => Registers.DPCLKA_CFGCR0,
341 Mask => DDI_CLK_OFF (Port));
342
343 if Port_Cfg.Display = DP then
344 if Port in USBC_Port then
345 TC.Program_DP_Mode
346 (Port, Natural (Lane_Count_As_Integer (Port_Cfg.DP.Lane_Count)));
347 end if;
348 Transcoder.Enable_Pipe_Clock (Pipe, Port_Cfg);
349 Transcoder.Configure (Pipe, Port_Cfg, Scale => False);
350
351 Training.Train_DP
352 (Port => (Port, Pipe, eDP => Port_Cfg.Is_eDP),
353 Link => Port_Cfg.DP,
354 Success => Success);
355 elsif Port_Cfg.Display = HDMI then
356 Transcoder.Enable_Pipe_Clock (Pipe, Port_Cfg);
357 Transcoder.Configure (Pipe, Port_Cfg, Scale => False);
358
359 Success := True;
360 else
361 Success := False;
362 end if;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600363 end Pre_On;
364
365 procedure Post_On
366 (Pipe : in Pipe_Index;
367 Port_Cfg : in Port_Config;
368 PLL_Hint : in Word32;
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700369 Success : out Boolean)
370 is
371 Port : GPU_Port renames Port_Cfg.Port;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600372 begin
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600373 Success := True;
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700374
375 if Port_Cfg.Display = HDMI then
376 if Port in Combo_Port then
377 Combo_Phy.Enable_HDMI (Port);
378 elsif Port in USBC_Port then
379 TC.Enable_HDMI (Port);
380 end if;
381 end if;
382
383 Panel.Backlight_On (Port_Cfg.Panel);
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600384 end Post_On;
385
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700386 ---------------------------------------------------------------------
387
Nico Huberbfea6a32024-03-07 15:22:36 +0000388 procedure Pre_Off (Pipe : Pipe_Index; Port_Cfg : Port_Config) is
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600389 begin
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600390 Panel.Backlight_Off (Port_Cfg.Panel);
391 Panel.Off (Port_Cfg.Panel);
392 end Pre_Off;
393
Nico Huberbfea6a32024-03-07 15:22:36 +0000394 procedure Post_Off (Pipe : Pipe_Index; Port_Cfg : Port_Config) is
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600395 begin
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700396 if Port_Cfg.Port in Combo_Port then
397 Off (Pipe, Port_Cfg.Port);
398 end if;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600399 end Post_Off;
400
401 procedure Pre_All_Off is
402 begin
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600403 for P in Valid_Panels loop
404 Panel.Backlight_Off (P);
405 Panel.Off (P);
406 end loop;
407 end Pre_All_Off;
408
409 procedure Post_All_Off is
410 begin
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700411 for Port in Combo_Port loop
412 Off (Pipe_Index'First, Port); -- pipe index is arbitrary
413 end loop;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600414 end Post_All_Off;
415
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700416 procedure Post_Reset_Off is
417 begin
418 for Port in Combo_Port loop
419 Off (Pipe_Index'First, Port);
420 end loop;
421 end Post_Reset_Off;
422
423 procedure Initialize is
424 begin
425 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
426
427 GMA.Combo_Phy.Initialize;
428 end Initialize;
429
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600430end HW.GFX.GMA.Connectors;