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