blob: 3425053d74e7020aafd5343e60154b6175caeca6 [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 Wawrzynczak605660b2022-06-08 12:48:19 -060015with GNAT.Source_Info;
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -060016with HW.Debug;
17with HW.GFX.GMA.Combo_Phy;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060018with HW.GFX.GMA.Config;
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -060019with HW.GFX.GMA.PCode;
20with HW.GFX.GMA.Registers;
21with HW.GFX.GMA.Transcoder;
Tim Wawrzynczak5473d292023-02-06 16:46:33 -070022with HW.GFX.GMA.Connectors.TC;
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -060023
24use type HW.Word64;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060025
26package body HW.GFX.GMA.Power_And_Clocks is
27
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -060028 subtype CDClk_Range is Config.CDClk_Range;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060029
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -060030 type Power_Domain is
31 (PW1, PW2, PW3, PW4, PW5,
32 DDI_A, DDI_B, DDI_C,
33 DDI_USBC1, DDI_USBC2, DDI_USBC3, DDI_USBC4, DDI_USBC5, DDI_USBC6,
34 AUX_A, AUX_B, AUX_C,
35 AUX_USBC1, AUX_USBC2, AUX_USBC3, AUX_USBC4, AUX_USBC5, AUX_USBC6);
36 type Power_Domain_Types is (Power_Well, Power_DDI, Power_AUX);
37 subtype Dynamic_Domain is Power_Domain range PW2 .. Power_Domain'Last;
38 subtype PW_Domain is Power_Domain range PW1 .. PW5;
39 subtype Dynamic_Well is Power_Domain range PW2 .. PW_Domain'Last;
40 subtype Port_Domain is Power_Domain range DDI_A .. AUX_USBC6;
41 subtype DDI_Domain is Power_Domain range DDI_A .. DDI_USBC6;
Tim Wawrzynczak5473d292023-02-06 16:46:33 -070042 subtype DDI_USBC_Domain is Power_Domain range DDI_USBC1 .. DDI_USBC6;
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -060043 subtype AUX_Domain is Power_Domain range AUX_A .. AUX_USBC6;
44 subtype AUX_USBC_Domain is Power_Domain range AUX_USBC1 .. AUX_USBC6;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060045
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -060046 function PW_Index (PW : PW_Domain) return Natural
47 is
48 (Power_Domain'Pos (PW) - Power_Domain'Pos (PW_Domain'First));
49
50 function DDI_Index (DDI : DDI_Domain) return Natural
51 is
52 (Power_Domain'Pos (DDI) - Power_Domain'Pos (DDI_Domain'First));
53
54 function AUX_Index (AUX : AUX_Domain) return Natural
55 is
56 (Power_Domain'Pos (AUX) - Power_Domain'Pos (AUX_Domain'First));
57
58 function AUX_USBC_Index (AUX: AUX_USBC_Domain) return Natural
59 is
60 (Power_Domain'Pos (AUX) - Power_Domain'Pos (AUX_USBC_Domain'First));
61
62 ----------------------------------------------------------------------------
63
64 function Power_Domain_Type (PD : Power_Domain) return Power_Domain_Types
65 is
66 (if PD in PW_Domain then Power_Well
67 elsif PD in DDI_Domain then Power_DDI
68 else Power_AUX);
69
70 type Power_Well_Regs is array (Power_Domain_Types) of Registers.Registers_Index;
71 PWR_CTL_BIOS : constant Power_Well_Regs :=
72 (Power_Well => Registers.PWR_WELL_CTL_BIOS,
73 Power_DDI => Registers.PWR_DDI_CTL_BIOS,
74 Power_AUX => Registers.PWR_AUX_CTL_BIOS);
75 PWR_CTL_DRIVER : constant Power_Well_Regs :=
76 (Power_Well => Registers.PWR_WELL_CTL_DRIVER,
77 Power_DDI => Registers.PWR_DDI_CTL_DRIVER,
78 Power_AUX => Registers.PWR_AUX_CTL_DRIVER);
79
80 function Power_State_Mask (PD : Power_Domain) return Word32
81 is
82 (case PD is
83 when PW_Domain'Range => 1 * 2 ** (2 * PW_Index (PD)),
84 when DDI_Domain'Range => 1 * 2 ** (2 * DDI_Index (PD)),
85 when AUX_Domain'Range => 1 * 2 ** (2 * AUX_Index (PD)));
86
87 function Power_Request_Mask (PD : Power_Domain) return Word32 is
88 begin
89 return Shift_Left (Power_State_Mask (PD), 1);
90 end Power_Request_Mask;
91
92 ----------------------------------------------------------------------------
93
94 PCH_DPMGUNIT_CLOCK_GATE_DISABLE : constant := 1 * 2 ** 15;
95 NDE_RSTWRN_OPT_RST_PCH_Handshake_En : constant := 1 * 2 ** 4;
96
97 ----------------------------------------------------------------------------
98
99 DBUF_CTL_DBUF_POWER_REQUEST : constant := 1 * 2 ** 31;
100 DBUF_CTL_TRACKER_STATE_SERVICE_MASK : constant := 16#f8_0000#;
101 DBUF_CTL_TRACKER_STATE_SERVICE_SHIFT : constant := 19;
102 DBUF_CTL_DBUF_POWER_STATE : constant := 1 * 2 ** 30;
103
104 type DBUF_Slices is (S1, S2);
105 DBUF_CTL : constant array (DBUF_Slices) of Registers.Registers_Index :=
106 (Registers.DBUF_CTL_S0,
107 Registers.DBUF_CTL_S1);
108
109 ----------------------------------------------------------------------------
110
111 MBUS_ABOX_CTL_BW_CREDITS_MASK : constant := 16#3# * 2 ** 20;
112 MBUS_ABOX_CTL_B_CREDITS_MASK : constant := 16#f# * 2 ** 16;
113 MBUS_ABOX_CTL_BT_CREDITS_POOL1_MASK : constant := 16#1f# * 2 ** 0;
114 MBUS_ABOX_CTL_BT_CREDITS_POOL2_MASK : constant := 16#1f# * 2 ** 8;
115 MBUS_ABOX_CTL_BW_CREDITS_SHIFT : constant := 20;
116 MBUS_ABOX_CTL_B_CREDITS_SHIFT : constant := 16;
117 MBUS_ABOX_CTL_BT_CREDITS_POOL1_SHIFT : constant := 0;
118 MBUS_ABOX_CTL_BT_CREDITS_POOL2_SHIFT : constant := 8;
119
120 MBUS_ABOX_MASK : constant Word32 :=
121 (MBUS_ABOX_CTL_BW_CREDITS_MASK or
122 MBUS_ABOX_CTL_B_CREDITS_MASK or
123 MBUS_ABOX_CTL_BT_CREDITS_POOL1_MASK or
124 MBUS_ABOX_CTL_BT_CREDITS_POOL2_MASK);
125 MBUS_ABOX_CREDITS : constant Word32 :=
126 ( 1 * 2 ** MBUS_ABOX_CTL_BW_CREDITS_SHIFT or
127 1 * 2 ** MBUS_ABOX_CTL_B_CREDITS_SHIFT or
128 16 * 2 ** MBUS_ABOX_CTL_BT_CREDITS_POOL1_SHIFT or
129 16 * 2 ** MBUS_ABOX_CTL_BT_CREDITS_POOL2_SHIFT);
130
131 MBUS_ABOX_CTL : constant array (0 .. 2) of Registers.Registers_Index :=
132 (Registers.MBUS_ABOX_CTL,
133 Registers.MBUS_ABOX1_CTL,
134 Registers.MBUS_ABOX2_CTL);
135
136 ----------------------------------------------------------------------------
137
138 DCPR_MASK_MAXLATENCY_MEMUP_CLR : constant := 1 * 2 ** 27;
139 DCPR_MASK_LPMODE : constant := 1 * 2 ** 26;
140 DCPR_SEND_RESP_IMM : constant := 1 * 2 ** 25;
141 DCPR_CLEAR_MEMSTAT_DIS : constant := 1 * 2 ** 24;
142
143 ----------------------------------------------------------------------------
144
145 function HIP_INDEX_REG (Aux : AUX_USBC_Domain) return Registers.Registers_Index
146 is
147 (if Aux <= AUX_USBC4
148 then Registers.HIP_INDEX_REG0
149 else Registers.HIP_INDEX_REG1);
150
151 function HIP_INDEX_VAL (Aux : AUX_USBC_Domain; Val : Word32) return Word32
152 is
153 (Val * 2 ** (8 * (AUX_USBC_Index (Aux) mod 4)));
154
155 type DKL_Regs is array (AUX_USBC_Domain) of Registers.Registers_Index;
156 DKL_CMN_UC_DW_27 : constant DKL_Regs :=
157 (AUX_USBC1 => Registers.DKL_CMN_UC_DW_27_1,
158 AUX_USBC2 => Registers.DKL_CMN_UC_DW_27_2,
159 AUX_USBC3 => Registers.DKL_CMN_UC_DW_27_3,
160 AUX_USBC4 => Registers.DKL_CMN_UC_DW_27_4,
161 AUX_USBC5 => Registers.DKL_CMN_UC_DW_27_5,
162 AUX_USBC6 => Registers.DKL_CMN_UC_DW_27_6);
163
164 ----------------------------------------------------------------------------
165
166 FUSE_STATUS_PG0_DIST_STATUS : constant := 1 * 2 ** 27;
167 FUSE_STATUS_PGx_DIST_STATUS : constant array (PW_Domain) of Word32 :=
168 (PW1 => 1 * 2 ** 26,
169 PW2 => 1 * 2 ** 25,
170 PW3 => 1 * 2 ** 24,
171 PW4 => 1 * 2 ** 23,
172 PW5 => 1 * 2 ** 22);
173
174 ----------------------------------------------------------------------------
175
176 TGL_PCODE_MEM_SUBSYSTEM_INFO : constant := 16#d#;
177 TGL_PCODE_MEM_SS_READ_GLOBAL_INFO : constant := 0 * 2 ** 8;
178 TGL_PCODE_CDCLK_CONTROL : constant := 7;
179 TGL_CDCLK_PREPARE_FOR_CHANGE : constant := 3;
180 TGL_CDCLK_READY_FOR_CHANGE : constant := 1;
181
182 ----------------------------------------------------------------------------
183
184 CDCLK_PLL_ENABLE_PLL_RATIO_MASK : constant := 16#ff#;
185 CDCLK_PLL_ENABLE_PLL_ENABLE : constant := 1 * 2 ** 31;
186 CDCLK_PLL_ENABLE_PLL_LOCK : constant := 1 * 2 ** 30;
187 CDCLK_CD2X_DIV_SEL_MASK : constant := 3 * 2 ** 22;
188 CDCLK_CD2X_DIV_SEL_1 : constant := 0 * 2 ** 22;
189 CDCLK_CD2X_DIV_SEL_2 : constant := 2 * 2 ** 22;
190 CDCLK_CD2X_PIPE_NONE : constant := 7 * 2 ** 19;
191 CDCLK_CTL_CD_FREQ_DECIMAL_MASK : constant := 16#7ff#;
192
193 ----------------------------------------------------------------------------
194
195 type AUX_CTL_Array is array (AUX_USBC_Domain) of Registers.Registers_Index;
196 AUX_CTL_Regs : constant AUX_CTL_Array :=
197 (AUX_USBC1 => Registers.DDI_AUX_CTL_USBC1,
198 AUX_USBC2 => Registers.DDI_AUX_CTL_USBC2,
199 AUX_USBC3 => Registers.DDI_AUX_CTL_USBC3,
200 AUX_USBC4 => Registers.DDI_AUX_CTL_USBC4,
201 AUX_USBC5 => Registers.DDI_AUX_CTL_USBC5,
202 AUX_USBC6 => Registers.DDI_AUX_CTL_USBC6);
203
204 ----------------------------------------------------------------------------
205
206 function To_GPU_Port (PD : Port_Domain) return GPU_Port
207 is
208 (case PD is
209 when DDI_A | AUX_A => DIGI_A,
210 when DDI_B | AUX_B => DIGI_B,
211 when DDI_C | AUX_C => DIGI_C,
212 when DDI_USBC1 | AUX_USBC1 => DDI_TC1,
213 when DDI_USBC2 | AUX_USBC2 => DDI_TC2,
214 when DDI_USBC3 | AUX_USBC3 => DDI_TC3,
215 when DDI_USBC4 | AUX_USBC4 => DDI_TC4,
216 when DDI_USBC5 | AUX_USBC5 => DDI_TC5,
217 when DDI_USBC6 | AUX_USBC6 => DDI_TC6);
218
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700219 procedure Pre_PD_On (PD : in Power_Domain; Success : out Boolean)
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600220 is
221 DP_AUX_CH_CTL_TBT_IO : constant := 1 * 2 ** 11;
222 begin
223 if PD in AUX_USBC_Domain then
224 -- Disable TBT IO mode for AUX
225 Registers.Unset_Mask
226 (Register => AUX_CTL_Regs (PD),
227 Mask => DP_AUX_CH_CTL_TBT_IO);
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700228 Connectors.TC.Claimed (To_GPU_Port (PD), Success);
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600229 elsif PD = PW1 then
230 Registers.Wait_Set_Mask
231 (Register => Registers.FUSE_STATUS,
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700232 Mask => FUSE_STATUS_PG0_DIST_STATUS,
233 Success => Success);
234 else
235 Success := True;
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600236 end if;
237 end Pre_PD_On;
238
239 procedure Post_PD_On (PD : Power_Domain)
240 is
241 DKL_CMN_UC_DW_27_UC_HEALTH : constant := 1 * 2 ** 15;
242 begin
243 if PD in PW_Domain then
244 Registers.Wait_Set_Mask
245 (Register => Registers.FUSE_STATUS,
246 Mask => FUSE_STATUS_PGx_DIST_STATUS (PD),
247 TOut_MS => 1);
248 elsif PD in AUX_USBC_Domain then
249 Registers.Write (HIP_INDEX_REG (PD), HIP_INDEX_VAL (PD, 2));
250 Registers.Wait_Set_Mask
251 (Register => DKL_CMN_UC_DW_27 (PD),
252 Mask => DKL_CMN_UC_DW_27_UC_HEALTH,
253 TOut_MS => 1);
254 end if;
255 end Post_PD_On;
256
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700257 procedure Pre_PD_Off (PD : Power_Domain) is
258 begin
259 if PD in DDI_USBC_Domain then
260 -- Could be moved to a higher level, but right now it's
261 -- convenient to do it here: When requested to turn the
262 -- power off, we know exactly that we don't want to use
263 -- the port (anymore).
264 Connectors.TC.Disconnect (To_GPU_Port (PD));
265 end if;
266 end Pre_PD_Off;
267
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600268 procedure PD_On (PD : Power_Domain)
269 is
270 Ctl1, Ctl2 : Word32;
271 PD_Type : constant Power_Domain_Types := Power_Domain_Type (PD);
272 Success : Boolean;
273 begin
274 Registers.Read (PWR_CTL_BIOS (PD_Type), Ctl1);
275 Registers.Read (PWR_CTL_DRIVER (PD_Type), Ctl2);
276
277 if ((Ctl1 or Ctl2) and Power_Request_Mask (PD)) = 0 then
278 Registers.Wait_Unset_Mask
279 (Register => PWR_CTL_DRIVER (PD_Type),
280 Mask => Power_State_Mask (PD),
281 TOut_MS => 1);
282 end if;
283
284 if (Ctl2 and Power_Request_Mask (PD)) = 0 then
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700285 Pre_PD_On (PD, Success);
286 if not Success then
287 pragma Debug (Debug.Put_Line ("Connection flow failed!"));
288 return;
289 end if;
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600290
291 Registers.Set_Mask (PWR_CTL_DRIVER (PD_Type), Power_Request_Mask (PD));
292
293 Registers.Wait_Set_Mask
294 (Register => PWR_CTL_DRIVER (PD_Type),
295 Mask => Power_State_Mask (PD),
296 TOut_MS => 1,
297 Success => Success);
298 pragma Debug (not Success, Debug.Put_Line ("Failed to enable power domain!"));
299
300 if Success then
301 Post_PD_On (PD);
302 end if;
303 end if;
304 end PD_On;
305
306 procedure PD_Off (PD : Power_Domain)
307 is
308 Ctl1, Ctl2 : Word32;
309 PD_Type : constant Power_Domain_Types := Power_Domain_Type (PD);
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600310 begin
311 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600312
313 Registers.Read (PWR_CTL_BIOS (PD_Type), Ctl1);
314 Registers.Read (PWR_CTL_DRIVER (PD_Type), Ctl2);
315
316 if ((Ctl1 or Ctl2) and Power_Request_Mask (PD)) /= 0 then
317 Registers.Wait_Set_Mask
318 (Register => PWR_CTL_DRIVER (PD_Type),
319 Mask => Power_State_Mask (PD),
320 TOut_MS => 1);
321
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700322 Pre_PD_Off (PD);
323
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600324 Registers.Unset_Mask (PWR_CTL_DRIVER (PD_Type), Power_Request_Mask (PD));
325 Registers.Unset_Mask (PWR_CTL_BIOS (PD_Type), Power_Request_Mask (PD));
326 end if;
327 end PD_Off;
328
329 function Need_PW (PW : Dynamic_Well; Configs : Pipe_Configs) return Boolean
330 is
331 function Any_TC_Port return Boolean is
332 (for some Pipe in Pipe_Index =>
333 Configs (Pipe).Port /= Disabled and then
334 Config_Helpers.To_GPU_Port (Pipe, Configs (Pipe).Port) in USBC_Port);
335
336 function Any_Pipe_From (First : Pipe_Index) return Boolean is
337 (for some Pipe in First .. Pipe_Index'Last => Configs (Pipe).Port /= Disabled);
338
339 function VGA return Boolean is
340 (Configs (Primary).Framebuffer.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET);
341 begin
342 case PW is
343 when PW2 | PW3 =>
344 return Any_Pipe_From (Secondary) or Any_TC_Port or VGA;
345 when PW4 =>
346 return Any_Pipe_From (Tertiary);
347 when PW5 =>
348 return False; -- Fourth pipe not supported yet.
349 end case;
350 end Need_PW;
351
352 function Need_PD (PD : Dynamic_Domain; Configs : Pipe_Configs) return Boolean
353 is
354 function Any_Port_Is (Port : GPU_Port) return Boolean is
355 (for some Pipe in Pipe_Index =>
356 Configs (Pipe).Port /= Disabled and then
357 Config_Helpers.To_GPU_Port (Pipe, Configs (Pipe).Port) = Port);
358 begin
359 return
360 (case PD is
361 when Dynamic_Well'Range => Need_PW (PD, Configs),
362 when Port_Domain'Range => Any_Port_Is (To_GPU_Port (PD)));
363 end Need_PD;
364
365 procedure Get_RefClk (Refclk : out Refclk_Range)
366 is
367 DSSM : Word32;
368 DSSM_REFERENCE_FREQUENCY_MASK : constant := 16#e000_0000#;
369 DSSM_REFERENCE_FREQUENCY_24MHZ : constant := 16#0000_0000#;
370 DSSM_REFERENCE_FREQUENCY_19_2MHZ : constant := 16#2000_0000#;
371 DSSM_REFERENCE_FREQUENCY_38_4MHZ : constant := 16#4000_0000#;
372 begin
373 Registers.Read (Registers.DSSM, DSSM);
374 Refclk :=
375 (case DSSM and DSSM_REFERENCE_FREQUENCY_MASK is
376 when DSSM_REFERENCE_FREQUENCY_24MHZ => 24_000_000,
377 when DSSM_REFERENCE_FREQUENCY_19_2MHZ => 19_200_000,
378 when DSSM_REFERENCE_FREQUENCY_38_4MHZ => 38_400_000,
379 when others => 24_000_000);
380 end Get_Refclk;
381
382 procedure Get_RawClk (Rawclk : out Frequency_Type)
383 is
384 Raw_Frequency_24_MHz : Boolean;
385 SFUSE_STRAP_RAW_FREQUENCY : constant := 1 * 2 ** 8;
386 begin
387 Rawclk := Config.Default_RawClk_Freq;
388 Registers.Is_Set_Mask
389 (Register => Registers.SFUSE_STRAP,
390 Mask => SFUSE_STRAP_RAW_FREQUENCY,
391 Result => Raw_Frequency_24_MHz);
392
393 if not Raw_Frequency_24_MHz then
394 Rawclk := 19_200_000;
395 end if;
396 end Get_RawClk;
397
398 procedure Get_Max_CDClk (CDClk : out CDClk_Range)
399 is
400 Refclk_Freq : Refclk_Range;
401 begin
402 Get_Refclk (Refclk_Freq);
403 CDClk :=
404 (case Refclk_Freq is
405 when 24_000_000 => 648_000_000,
406 when others => 652_800_000);
407 end Get_Max_CDClk;
408
409 procedure Normalize_CDClk
410 (CDClk : in Int64;
411 Normalized : out CDClk_Range)
412 with
413 Post => Normalized >= 172_800_000
414 is
415 Refclk_Freq : Refclk_Range;
416 begin
417 Get_Refclk (Refclk_Freq);
418 Normalized :=
419 (case Refclk_Freq is
420 when 19_200_000 | 38_400_000 =>
421 (if CDClk <= 172_800_000 then 172_800_000
422 elsif CDClk <= 192_000_000 then 192_000_000
423 elsif CDClk <= 307_200_000 then 307_200_000
424 elsif CDClk <= 326_400_000 then 326_400_000
425 elsif CDClk <= 556_800_000 then 556_800_000
426 else 652_800_000),
427 when others =>
428 (if CDClk <= 180_000_000 then 180_000_000
429 elsif CDClk <= 192_000_000 then 192_000_000
430 elsif CDClk <= 312_000_000 then 312_000_000
431 elsif CDClk <= 324_000_000 then 324_000_000
432 elsif CDClk <= 552_000_000 then 552_000_000
433 else 648_000_000));
434 end Normalize_CDClk;
435
436 procedure Get_Cur_CDClk (CDClk : out CDClk_Range)
437 with
438 Post => CDClk >= 172_800_000
439 is
440 CDCLK_CTL : Word32;
441 begin
442 Registers.Read (Registers.CDCLK_CTL, CDCLK_CTL);
443 CDCLK_CTL := CDCLK_CTL and CDCLK_CTL_CD_FREQ_DECIMAL_MASK;
444 Normalize_CDClk (Int64 (CDCLK_CTL) * 500_000 + 1_000_000, CDClk);
445 end Get_Cur_CDClk;
446
447 procedure Set_CDClk (CDClk_In : CDClk_Range)
448 is
449 subtype PLL_Ratio_Range is Word32 range 0 .. 68;
450 function Ratio_For_19_2_MHz (CDClk : CDClk_Range) return PLL_Ratio_Range is
451 begin
452 case CDClk is
453 when 172_800_000 => return 18;
454 when 192_000_000 => return 20;
455 when 307_200_000 => return 32;
456 when 326_400_000 | 652_800_000 => return 68;
457 when 556_800_000 => return 58;
458 when others => return 0;
459 end case;
460 end Ratio_For_19_2_MHz;
461
462 function Ratio_For_24_MHz (CDCLk : CDClk_Range) return PLL_Ratio_Range is
463 begin
464 case CDClk is
465 when 180_800_000 => return 15;
466 when 192_000_000 => return 16;
467 when 312_000_000 => return 26;
468 when 324_000_000 | 648_000_000 => return 54;
469 when 552_000_000 => return 46;
470 when others => return 0;
471 end case;
472 end Ratio_For_24_MHz;
473
474 function CDCLK_CTL_CD_FREQ_DECIMAL (Freq : CDClk_Range) return Word32
475 with
476 Pre => Freq > 1_000_000
477 is
478 begin
479 -- Weirdest representation: CDClk - 1MHz in 10.1 (10 + 1 fractional bit)
480 return Word32 (Div_Round_Closest (Pos64 (Freq) - 1_000_000, 500_000));
481 end CDCLK_CTL_CD_FREQ_DECIMAL;
482
483 Success : Boolean;
484 CD2X : Word32;
485 PLL_Ratio : PLL_Ratio_Range;
486 CDClk : CDClk_Range;
487 Refclk_Freq : Refclk_Range;
488 VCO : Pos64;
489 begin
490 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
491
492 Normalize_CDClk (CDClk_Range'Min (CDClk_In, Config.Max_CDClk), CDClk);
493 Get_Refclk (Refclk_Freq);
494 PLL_Ratio := (case Refclk_Freq is
495 when 19_200_000 => Ratio_For_19_2_MHz (CDClk),
496 when 38_400_000 => Ratio_For_19_2_MHz (CDClk) / 2,
497 when 24_000_000 => Ratio_For_24_MHz (CDClk),
498 when others => 0);
499
500 if PLL_Ratio = 0 then
501 pragma Debug (Debug.Put_Line
502 ("ERROR: Invalid Refclk frequency, bad hardware?"));
503 return;
504 end if;
505
506 PCode.Mailbox_Request
507 (Mbox => TGL_PCODE_CDCLK_CONTROL,
508 Command => TGL_CDCLK_PREPARE_FOR_CHANGE,
509 Reply_Mask => TGL_CDCLK_READY_FOR_CHANGE,
510 Wait_Ready => True,
511 Success => Success);
512
513 if not Success then
514 pragma Debug (Debug.Put_Line
515 ("ERROR: PCODE not ready for frequency change."));
516 return;
517 end if;
518
519 Registers.Unset_Mask
520 (Register => Registers.CDCLK_PLL_ENABLE,
521 Mask => CDCLK_PLL_ENABLE_PLL_ENABLE);
522 Registers.Wait_Unset_Mask
523 (Register => Registers.CDCLK_PLL_ENABLE,
524 Mask => CDCLK_PLL_ENABLE_PLL_LOCK);
525
526 Registers.Write
527 (Register => Registers.CDCLK_PLL_ENABLE,
528 Value => PLL_Ratio);
529 Registers.Write
530 (Register => Registers.CDCLK_PLL_ENABLE,
531 Value => PLL_Ratio or CDCLK_PLL_ENABLE_PLL_ENABLE);
532 Registers.Wait_Set_Mask
533 (Register => Registers.CDCLK_PLL_ENABLE,
534 Mask => CDCLK_PLL_ENABLE_PLL_LOCK,
535 Success => Success);
536
537 if not Success then
538 Debug.Put_Line ("CDClk PLL failed to lock!");
539 return;
540 end if;
541
542 VCO := (Refclk_Freq / 1_000) * Pos64 (PLL_Ratio);
543 CD2X :=
544 (case (Div_Round_Closest (VCO, CDClk / 1_000)) is
545 when 2 => CDCLK_CD2X_DIV_SEL_1,
546 when 4 => CDCLK_CD2X_DIV_SEL_2,
547 when others => CDCLK_CD2X_DIV_SEL_1);
548
549 Registers.Write
550 (Register => Registers.CDCLK_CTL,
551 Value => CDCLK_CTL_CD_FREQ_DECIMAL (CDClk) or
552 CDCLK_CD2X_PIPE_NONE or CD2X);
553
554 PCode.Mailbox_Write
555 (MBox => TGL_PCODE_CDCLK_CONTROL,
556 Command => (if CDClk <= 312_000_000 then 0
557 elsif CDClk <= 326_400_000 then 1
558 elsif CDClk <= 556_800_000 then 2
559 else 3));
560 Config.CDClk := CDClk;
561
562 pragma Debug (Debug.Put ("Set CDClk to "));
563 pragma Debug (Debug.Put_Int64 (CDClk / 1_000_000));
564 pragma Debug (Debug.Put ("."));
565 pragma Debug (Debug.Put_Int64 ((CDClk mod 1_000_000) / 100_000));
566 pragma Debug (Debug.Put_Line ("MHz."));
567 end Set_CDClk;
568
569 procedure Configure_Bandwidth_Buddy
570 is
571 BW_BUDDY_DISABLE : constant := 1 * 2 ** 31;
572 BW_BUDDY_TLB_REQ_TIMER_MASK : constant := 16#3f_0000#;
573
574 type DRAM_Module_Type is (DDR4, DDR5, LPDDR4, LPDDR5);
575 type Bw_Buddy_Info is record
576 DRAM_Channels : Natural;
577 DRAM_Type : DRAM_Module_Type;
578 BW_BUDDY_MASK : Word32;
579 end record;
580 type Bw_Buddy_Info_Array is array (1 .. 8) of Bw_Buddy_Info;
581
582 Buddy_Info : constant Bw_Buddy_Info_Array :=
583 ((1, DDR4, 16#0f#),
584 (1, DDR5, 16#0f#),
585 (2, LPDDR4, 16#1c#),
586 (2, LPDDR5, 16#1c#),
587 (2, DDR4, 16#1f#),
588 (2, DDR5, 16#1e#),
589 (4, LPDDR4, 16#38#),
590 (4, LPDDR5, 16#38#));
591
592 -- TODO: use for ADL-S, RKL A0/B0
593 Buddy_Info_Wa_1409767108 : constant Bw_Buddy_Info_Array :=
594 ((1, DDR4, 1),
595 (1, DDR5, 1),
596 (1, LPDDR4, 1),
597 (1, LPDDR5, 1),
598 (2, DDR4, 3),
599 (2, DDR5, 3),
600 (2, LPDDR4, 3),
601 (2, LPDDR5, 3));
602
603 Result : Word64;
604 Module_Type: DRAM_Module_Type;
605 Channels : Natural;
606 Success : Boolean;
607 begin
608 PCode.Mailbox_Read(MBox => TGL_PCODE_MEM_SUBSYSTEM_INFO or
609 TGL_PCODE_MEM_SS_READ_GLOBAL_INFO,
610 Wait_Ready => True,
611 Reply => Result,
612 Success => Success);
613 if not Success then
614 pragma Debug (Debug.Put_Line
615 ("ERROR: PCODE didn't return memory info."));
616 return;
617 end if;
618
619 case (Result and 16#f#) is
620 when 0 => Module_Type := DDR4;
621 when 1 => Module_Type := DDR5;
622 when 2 => Module_Type := LPDDR5;
623 when 3 => Module_Type := LPDDR4;
624 when others =>
625 pragma Debug (Debug.Put_Line ("ERROR: Invalid DRAM Module Type."));
626 return;
627 end case;
628
629 Channels := Natural (Shift_Right (Result and 16#f0#, 4));
630 for I in Buddy_Info'Range loop
631 if Buddy_Info (I).DRAM_Type = Module_Type and
632 Buddy_Info (I).DRAM_Channels = Channels
633 then
634 Registers.Set_Mask
635 (Register => Registers.BW_BUDDY1_PAGE_MASK,
636 Mask => Buddy_Info (I).BW_BUDDY_MASK);
637 Registers.Set_Mask
638 (Register => Registers.BW_BUDDY2_PAGE_MASK,
639 Mask => Buddy_Info (I).BW_BUDDY_MASK);
640
641 -- Wa_22010178259:tgl,rkl
642 Registers.Unset_And_Set_Mask
643 (Register => Registers.BW_BUDDY1_CTL,
644 Mask_Unset => BW_BUDDY_TLB_REQ_TIMER_MASK,
645 Mask_Set => 8 * 2 ** 16);
646 Registers.Unset_And_Set_Mask
647 (Register => Registers.BW_BUDDY2_CTL,
648 Mask_Unset => BW_BUDDY_TLB_REQ_TIMER_MASK,
649 Mask_Set => 8 * 2 ** 16);
650
651 return;
652 end if;
653 end loop;
654
655 Registers.Write (Registers.BW_BUDDY1_CTL, BW_BUDDY_DISABLE);
656 Registers.Write (Registers.BW_BUDDY2_CTL, BW_BUDDY_DISABLE);
657 end Configure_Bandwidth_Buddy;
658
659 ----------------------------------------------------------------------------
660
661 procedure Initialize
662 is
663 RawClk : Frequency_Type;
664 begin
665 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
666
667 -- Wa_14011294188:ehl,jsl,tgl,rkl,adl-s,adl-p
668 Registers.Set_Mask
669 (Register => Registers.PCH_DSPCLK_GATE_D,
670 Mask => PCH_DPMGUNIT_CLOCK_GATE_DISABLE);
671
672 Registers.Set_Mask
673 (Register => Registers.NDE_RSTWRN_OPT,
674 Mask => NDE_RSTWRN_OPT_RST_PCH_Handshake_En);
675
676 PD_On (PW1);
677
678 Get_Cur_CDClk (Config.CDClk);
679 Get_Max_CDClk (Config.Max_CDClk);
680 if Config.CDClk < Config.Default_CDClk_Freq then
681 Set_CDClk (Config.Default_CDClk_Freq);
682 end if;
683
684 Get_RawClk (RawClk);
685 Config.Raw_Clock := RawClk;
686
687 -- TGL: Set DBUF Tracker State Service to 8
688 Registers.Unset_And_Set_Mask
689 (Register => DBUF_CTL (S1),
690 Mask_Unset => DBUF_CTL_TRACKER_STATE_SERVICE_MASK,
691 Mask_Set => 8 * 2 ** DBUF_CTL_TRACKER_STATE_SERVICE_SHIFT);
692
693 -- Enable first DBUF slice (TODO: Is this ok to use for all pipes?)
694 Registers.Set_Mask (DBUF_CTL (S1), DBUF_CTL_DBUF_POWER_REQUEST);
695 Registers.Wait_Set_Mask (DBUF_CTL (S1), DBUF_CTL_DBUF_POWER_STATE);
696
697 for I in MBUS_ABOX_CTL'Range loop
698 Registers.Unset_And_Set_Mask
699 (Register => MBUS_ABOX_CTL (I),
700 Mask_Unset => MBUS_ABOX_MASK,
701 Mask_Set => MBUS_ABOX_CREDITS);
702 end loop;
703
704 Configure_Bandwidth_Buddy;
705
706 -- Display WA #14011508470 tgl,dg1,rkl,adl-s,adl-p,dg2
707 Registers.Set_Mask
708 (Register => Registers.GEN11_CHICKEN_DCPR_2,
709 Mask => DCPR_MASK_MAXLATENCY_MEMUP_CLR or DCPR_MASK_LPMODE or
710 DCPR_SEND_RESP_IMM or DCPR_CLEAR_MEMSTAT_DIS);
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600711 end Initialize;
712
713 procedure Limit_Dotclocks
714 (Configs : in out Pipe_Configs;
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600715 CDClk_Switch : out Boolean)
716 is
717 CDClk : CDClk_Range;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600718 begin
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600719 Config_Helpers.Limit_Dotclocks (Configs, Config.Max_CDClk);
720 Normalize_CDClk (Config_Helpers.Highest_Dotclock (Configs), CDClk);
721 CDClk_Switch := Config.CDClk /= CDClk;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600722 end Limit_Dotclocks;
723
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600724 procedure Update_CDClk (Configs : in out Pipe_Configs)
725 is
726 New_CDClk : constant Frequency_Type :=
727 Config_Helpers.Highest_Dotclock (Configs);
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600728 begin
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600729 Set_CDClk (New_CDClk);
730 Config_Helpers.Limit_Dotclocks (Configs, Config.CDClk);
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600731 end Update_CDClk;
732
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600733 procedure Enable_CDClk is
734 begin
735 if Config.CDClk < Config.Default_CDClk_Freq then
736 Set_CDClk (Config.Default_CDClk_Freq);
737 end if;
738 end Enable_CDClk;
739
740 ----------------------------------------------------------------------------
741
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600742 procedure Power_Set_To (Configs : Pipe_Configs) is
743 begin
744 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600745
746 for PD in reverse Dynamic_Domain loop
747 if not Need_PD (PD, Configs) then
748 PD_Off (PD);
749 end if;
750 end loop;
751
752 for PD in Dynamic_Domain loop
753 if Need_PD (PD, Configs) then
754 PD_On (PD);
755 end if;
756 end loop;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600757 end Power_Set_To;
758
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600759 procedure Power_Up (Port : Active_Port_Type; Success : out Boolean)
760 is
761 GPU_Port : constant GMA.GPU_Port :=
762 Config_Helpers.To_GPU_Port (Pipe_Index'First, Port);
763
764 procedure On (Aux : AUX_Domain; DDI : DDI_Domain) is
765 begin
766 PD_On (PW1);
767 if GPU_Port in USBC_Port then
768 PD_On (PW2);
769 PD_On (PW3);
770 end if;
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600771 PD_On (DDI);
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700772
773 if GPU_Port in USBC_Port then
774 Connectors.TC.Claim
775 (Port => GPU_Port,
776 DP_Alt => Port in Physical_USBC_Ports,
777 Success => Success);
778 if not Success then
779 return;
780 end if;
781 end if;
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600782 PD_On (Aux);
783
Tim Wawrzynczak5473d292023-02-06 16:46:33 -0700784 Success := True;
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600785 end On;
Nico Huber41e86742024-07-17 17:10:28 +0200786 begin
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600787 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
788
789 case GPU_Port is
790 when GMA.DIGI_A => On (AUX_A, DDI_A);
791 when GMA.DIGI_B => On (AUX_B, DDI_B);
792 when GMA.DIGI_C => On (AUX_C, DDI_C);
793 when GMA.DDI_TC1 => On (AUX_USBC1, DDI_USBC1);
794 when GMA.DDI_TC2 => On (AUX_USBC2, DDI_USBC2);
795 when GMA.DDI_TC3 => On (AUX_USBC3, DDI_USBC3);
796 when GMA.DDI_TC4 => On (AUX_USBC4, DDI_USBC4);
797 when GMA.DDI_TC5 => On (AUX_USBC5, DDI_USBC5);
798 when GMA.DDI_TC6 => On (AUX_USBC6, DDI_USBC6);
799 when others => Success := True;
800 end case;
Nico Huber41e86742024-07-17 17:10:28 +0200801 end Power_Up;
802
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600803 procedure Power_Up (Old_Configs, New_Configs : Pipe_Configs) is
804 begin
805 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600806
807 -- Power wells only, Aux/DDI domains are enabled later on explicit request.
808 for PW in Dynamic_Well loop
809 if not Need_PW (PW, Old_Configs) and Need_PW (PW, New_Configs) then
810 PD_On (PW);
811 end if;
812 end loop;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600813 end Power_Up;
814
815 procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Pipe_Configs)
816 is
817 begin
818 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600819
820 for PD in reverse Dynamic_Domain loop
821 if (Need_PD (PD, Old_Configs) or Need_PD (PD, Tmp_Configs)) and
822 not Need_PD (PD, New_Configs)
823 then
824 PD_Off (PD);
825 end if;
826 end loop;
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600827 end Power_Down;
828
Tim Wawrzynczak6db27c42022-09-09 10:49:55 -0600829 procedure Pre_All_Off is
830 begin
831 Transcoder.PSR_Off;
832 end Pre_All_Off;
833
834 procedure Post_All_Off is
835 begin
836 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
837
838 for S in reverse DBUF_CTL'Range loop
839 Registers.Unset_Mask
840 (DBUF_CTL (S), DBUF_CTL_DBUF_POWER_REQUEST);
841 Registers.Wait_Unset_Mask
842 (DBUF_CTL (S), DBUF_CTL_DBUF_POWER_STATE);
843 end loop;
844
845 -- Disable CDClk PLL. FIXME: Not implemented yet.
846 Set_CDClk (CDClk_Range'First);
847
848 for PD in reverse Power_Domain loop
849 PD_Off (PD);
850 end loop;
851
852 Combo_Phy.All_Off;
853 end Post_All_Off;
854
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600855end HW.GFX.GMA.Power_And_Clocks;