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