Linux 4.19.133
[linux/fpc-iii.git] / drivers / gpu / drm / amd / powerplay / hwmgr / processpptables.c
blobb9e08b06ed5dbbdc180b5730b745251919540352
1 /*
2 * Copyright 2015 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
23 #include "pp_debug.h"
24 #include <linux/types.h>
25 #include <linux/kernel.h>
26 #include <linux/slab.h>
27 #include <drm/amdgpu_drm.h>
28 #include "processpptables.h"
29 #include <atom-types.h>
30 #include <atombios.h>
31 #include "pptable.h"
32 #include "power_state.h"
33 #include "hwmgr.h"
34 #include "hardwaremanager.h"
37 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12
38 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14
39 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16
40 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18
41 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20
42 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22
43 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8 24
44 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V9 26
46 #define NUM_BITS_CLOCK_INFO_ARRAY_INDEX 6
48 static uint16_t get_vce_table_offset(struct pp_hwmgr *hwmgr,
49 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
51 uint16_t vce_table_offset = 0;
53 if (le16_to_cpu(powerplay_table->usTableSize) >=
54 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
55 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
56 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
58 if (powerplay_table3->usExtendendedHeaderOffset > 0) {
59 const ATOM_PPLIB_EXTENDEDHEADER *extended_header =
60 (const ATOM_PPLIB_EXTENDEDHEADER *)
61 (((unsigned long)powerplay_table3) +
62 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
63 if (le16_to_cpu(extended_header->usSize) >=
64 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2)
65 vce_table_offset = le16_to_cpu(extended_header->usVCETableOffset);
69 return vce_table_offset;
72 static uint16_t get_vce_clock_info_array_offset(struct pp_hwmgr *hwmgr,
73 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
75 uint16_t table_offset = get_vce_table_offset(hwmgr,
76 powerplay_table);
78 if (table_offset > 0)
79 return table_offset + 1;
81 return 0;
84 static uint16_t get_vce_clock_info_array_size(struct pp_hwmgr *hwmgr,
85 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
87 uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr,
88 powerplay_table);
89 uint16_t table_size = 0;
91 if (table_offset > 0) {
92 const VCEClockInfoArray *p = (const VCEClockInfoArray *)
93 (((unsigned long) powerplay_table) + table_offset);
94 table_size = sizeof(uint8_t) + p->ucNumEntries * sizeof(VCEClockInfo);
97 return table_size;
100 static uint16_t get_vce_clock_voltage_limit_table_offset(struct pp_hwmgr *hwmgr,
101 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
103 uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr,
104 powerplay_table);
106 if (table_offset > 0)
107 return table_offset + get_vce_clock_info_array_size(hwmgr,
108 powerplay_table);
110 return 0;
113 static uint16_t get_vce_clock_voltage_limit_table_size(struct pp_hwmgr *hwmgr,
114 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
116 uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
117 uint16_t table_size = 0;
119 if (table_offset > 0) {
120 const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *ptable =
121 (const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)(((unsigned long) powerplay_table) + table_offset);
123 table_size = sizeof(uint8_t) + ptable->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record);
125 return table_size;
128 static uint16_t get_vce_state_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
130 uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
132 if (table_offset > 0)
133 return table_offset + get_vce_clock_voltage_limit_table_size(hwmgr, powerplay_table);
135 return 0;
138 static const ATOM_PPLIB_VCE_State_Table *get_vce_state_table(
139 struct pp_hwmgr *hwmgr,
140 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
142 uint16_t table_offset = get_vce_state_table_offset(hwmgr, powerplay_table);
144 if (table_offset > 0)
145 return (const ATOM_PPLIB_VCE_State_Table *)(((unsigned long) powerplay_table) + table_offset);
147 return NULL;
150 static uint16_t get_uvd_table_offset(struct pp_hwmgr *hwmgr,
151 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
153 uint16_t uvd_table_offset = 0;
155 if (le16_to_cpu(powerplay_table->usTableSize) >=
156 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
157 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
158 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
159 if (powerplay_table3->usExtendendedHeaderOffset > 0) {
160 const ATOM_PPLIB_EXTENDEDHEADER *extended_header =
161 (const ATOM_PPLIB_EXTENDEDHEADER *)
162 (((unsigned long)powerplay_table3) +
163 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
164 if (le16_to_cpu(extended_header->usSize) >=
165 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3)
166 uvd_table_offset = le16_to_cpu(extended_header->usUVDTableOffset);
169 return uvd_table_offset;
172 static uint16_t get_uvd_clock_info_array_offset(struct pp_hwmgr *hwmgr,
173 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
175 uint16_t table_offset = get_uvd_table_offset(hwmgr,
176 powerplay_table);
178 if (table_offset > 0)
179 return table_offset + 1;
180 return 0;
183 static uint16_t get_uvd_clock_info_array_size(struct pp_hwmgr *hwmgr,
184 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
186 uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr,
187 powerplay_table);
188 uint16_t table_size = 0;
190 if (table_offset > 0) {
191 const UVDClockInfoArray *p = (const UVDClockInfoArray *)
192 (((unsigned long) powerplay_table)
193 + table_offset);
194 table_size = sizeof(UCHAR) +
195 p->ucNumEntries * sizeof(UVDClockInfo);
198 return table_size;
201 static uint16_t get_uvd_clock_voltage_limit_table_offset(
202 struct pp_hwmgr *hwmgr,
203 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
205 uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr,
206 powerplay_table);
208 if (table_offset > 0)
209 return table_offset +
210 get_uvd_clock_info_array_size(hwmgr, powerplay_table);
212 return 0;
215 static uint16_t get_samu_table_offset(struct pp_hwmgr *hwmgr,
216 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
218 uint16_t samu_table_offset = 0;
220 if (le16_to_cpu(powerplay_table->usTableSize) >=
221 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
222 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
223 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
224 if (powerplay_table3->usExtendendedHeaderOffset > 0) {
225 const ATOM_PPLIB_EXTENDEDHEADER *extended_header =
226 (const ATOM_PPLIB_EXTENDEDHEADER *)
227 (((unsigned long)powerplay_table3) +
228 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
229 if (le16_to_cpu(extended_header->usSize) >=
230 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4)
231 samu_table_offset = le16_to_cpu(extended_header->usSAMUTableOffset);
235 return samu_table_offset;
238 static uint16_t get_samu_clock_voltage_limit_table_offset(
239 struct pp_hwmgr *hwmgr,
240 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
242 uint16_t table_offset = get_samu_table_offset(hwmgr,
243 powerplay_table);
245 if (table_offset > 0)
246 return table_offset + 1;
248 return 0;
251 static uint16_t get_acp_table_offset(struct pp_hwmgr *hwmgr,
252 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
254 uint16_t acp_table_offset = 0;
256 if (le16_to_cpu(powerplay_table->usTableSize) >=
257 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
258 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
259 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
260 if (powerplay_table3->usExtendendedHeaderOffset > 0) {
261 const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader =
262 (const ATOM_PPLIB_EXTENDEDHEADER *)
263 (((unsigned long)powerplay_table3) +
264 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
265 if (le16_to_cpu(pExtendedHeader->usSize) >=
266 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6)
267 acp_table_offset = le16_to_cpu(pExtendedHeader->usACPTableOffset);
271 return acp_table_offset;
274 static uint16_t get_acp_clock_voltage_limit_table_offset(
275 struct pp_hwmgr *hwmgr,
276 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
278 uint16_t tableOffset = get_acp_table_offset(hwmgr, powerplay_table);
280 if (tableOffset > 0)
281 return tableOffset + 1;
283 return 0;
286 static uint16_t get_cacp_tdp_table_offset(
287 struct pp_hwmgr *hwmgr,
288 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
290 uint16_t cacTdpTableOffset = 0;
292 if (le16_to_cpu(powerplay_table->usTableSize) >=
293 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
294 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
295 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
296 if (powerplay_table3->usExtendendedHeaderOffset > 0) {
297 const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader =
298 (const ATOM_PPLIB_EXTENDEDHEADER *)
299 (((unsigned long)powerplay_table3) +
300 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
301 if (le16_to_cpu(pExtendedHeader->usSize) >=
302 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7)
303 cacTdpTableOffset = le16_to_cpu(pExtendedHeader->usPowerTuneTableOffset);
307 return cacTdpTableOffset;
310 static int get_cac_tdp_table(struct pp_hwmgr *hwmgr,
311 struct phm_cac_tdp_table **ptable,
312 const ATOM_PowerTune_Table *table,
313 uint16_t us_maximum_power_delivery_limit)
315 unsigned long table_size;
316 struct phm_cac_tdp_table *tdp_table;
318 table_size = sizeof(unsigned long) + sizeof(struct phm_cac_tdp_table);
320 tdp_table = kzalloc(table_size, GFP_KERNEL);
321 if (NULL == tdp_table)
322 return -ENOMEM;
324 tdp_table->usTDP = le16_to_cpu(table->usTDP);
325 tdp_table->usConfigurableTDP = le16_to_cpu(table->usConfigurableTDP);
326 tdp_table->usTDC = le16_to_cpu(table->usTDC);
327 tdp_table->usBatteryPowerLimit = le16_to_cpu(table->usBatteryPowerLimit);
328 tdp_table->usSmallPowerLimit = le16_to_cpu(table->usSmallPowerLimit);
329 tdp_table->usLowCACLeakage = le16_to_cpu(table->usLowCACLeakage);
330 tdp_table->usHighCACLeakage = le16_to_cpu(table->usHighCACLeakage);
331 tdp_table->usMaximumPowerDeliveryLimit = us_maximum_power_delivery_limit;
333 *ptable = tdp_table;
335 return 0;
338 static uint16_t get_sclk_vdd_gfx_table_offset(struct pp_hwmgr *hwmgr,
339 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
341 uint16_t sclk_vdd_gfx_table_offset = 0;
343 if (le16_to_cpu(powerplay_table->usTableSize) >=
344 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
345 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
346 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
347 if (powerplay_table3->usExtendendedHeaderOffset > 0) {
348 const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader =
349 (const ATOM_PPLIB_EXTENDEDHEADER *)
350 (((unsigned long)powerplay_table3) +
351 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
352 if (le16_to_cpu(pExtendedHeader->usSize) >=
353 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8)
354 sclk_vdd_gfx_table_offset =
355 le16_to_cpu(pExtendedHeader->usSclkVddgfxTableOffset);
359 return sclk_vdd_gfx_table_offset;
362 static uint16_t get_sclk_vdd_gfx_clock_voltage_dependency_table_offset(
363 struct pp_hwmgr *hwmgr,
364 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
366 uint16_t tableOffset = get_sclk_vdd_gfx_table_offset(hwmgr, powerplay_table);
368 if (tableOffset > 0)
369 return tableOffset;
371 return 0;
375 static int get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr,
376 struct phm_clock_voltage_dependency_table **ptable,
377 const ATOM_PPLIB_Clock_Voltage_Dependency_Table *table)
380 unsigned long table_size, i;
381 struct phm_clock_voltage_dependency_table *dep_table;
383 table_size = sizeof(unsigned long) +
384 sizeof(struct phm_clock_voltage_dependency_table)
385 * table->ucNumEntries;
387 dep_table = kzalloc(table_size, GFP_KERNEL);
388 if (NULL == dep_table)
389 return -ENOMEM;
391 dep_table->count = (unsigned long)table->ucNumEntries;
393 for (i = 0; i < dep_table->count; i++) {
394 dep_table->entries[i].clk =
395 ((unsigned long)table->entries[i].ucClockHigh << 16) |
396 le16_to_cpu(table->entries[i].usClockLow);
397 dep_table->entries[i].v =
398 (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
401 *ptable = dep_table;
403 return 0;
406 static int get_valid_clk(struct pp_hwmgr *hwmgr,
407 struct phm_clock_array **ptable,
408 const struct phm_clock_voltage_dependency_table *table)
410 unsigned long table_size, i;
411 struct phm_clock_array *clock_table;
413 table_size = sizeof(unsigned long) + sizeof(unsigned long) * table->count;
414 clock_table = kzalloc(table_size, GFP_KERNEL);
415 if (NULL == clock_table)
416 return -ENOMEM;
418 clock_table->count = (unsigned long)table->count;
420 for (i = 0; i < clock_table->count; i++)
421 clock_table->values[i] = (unsigned long)table->entries[i].clk;
423 *ptable = clock_table;
425 return 0;
428 static int get_clock_voltage_limit(struct pp_hwmgr *hwmgr,
429 struct phm_clock_and_voltage_limits *limits,
430 const ATOM_PPLIB_Clock_Voltage_Limit_Table *table)
432 limits->sclk = ((unsigned long)table->entries[0].ucSclkHigh << 16) |
433 le16_to_cpu(table->entries[0].usSclkLow);
434 limits->mclk = ((unsigned long)table->entries[0].ucMclkHigh << 16) |
435 le16_to_cpu(table->entries[0].usMclkLow);
436 limits->vddc = (unsigned long)le16_to_cpu(table->entries[0].usVddc);
437 limits->vddci = (unsigned long)le16_to_cpu(table->entries[0].usVddci);
439 return 0;
443 static void set_hw_cap(struct pp_hwmgr *hwmgr, bool enable,
444 enum phm_platform_caps cap)
446 if (enable)
447 phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap);
448 else
449 phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap);
452 static int set_platform_caps(struct pp_hwmgr *hwmgr,
453 unsigned long powerplay_caps)
455 set_hw_cap(
456 hwmgr,
457 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_POWERPLAY),
458 PHM_PlatformCaps_PowerPlaySupport
461 set_hw_cap(
462 hwmgr,
463 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SBIOSPOWERSOURCE),
464 PHM_PlatformCaps_BiosPowerSourceControl
467 set_hw_cap(
468 hwmgr,
469 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s),
470 PHM_PlatformCaps_EnableASPML0s
473 set_hw_cap(
474 hwmgr,
475 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1),
476 PHM_PlatformCaps_EnableASPML1
479 set_hw_cap(
480 hwmgr,
481 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS),
482 PHM_PlatformCaps_EnableBackbias
485 set_hw_cap(
486 hwmgr,
487 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC),
488 PHM_PlatformCaps_AutomaticDCTransition
491 set_hw_cap(
492 hwmgr,
493 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY),
494 PHM_PlatformCaps_GeminiPrimary
497 set_hw_cap(
498 hwmgr,
499 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC),
500 PHM_PlatformCaps_StepVddc
503 set_hw_cap(
504 hwmgr,
505 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VOLTAGECONTROL),
506 PHM_PlatformCaps_EnableVoltageControl
509 set_hw_cap(
510 hwmgr,
511 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL),
512 PHM_PlatformCaps_EnableSideportControl
515 set_hw_cap(
516 hwmgr,
517 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1),
518 PHM_PlatformCaps_TurnOffPll_ASPML1
521 set_hw_cap(
522 hwmgr,
523 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HTLINKCONTROL),
524 PHM_PlatformCaps_EnableHTLinkControl
527 set_hw_cap(
528 hwmgr,
529 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_MVDDCONTROL),
530 PHM_PlatformCaps_EnableMVDDControl
533 set_hw_cap(
534 hwmgr,
535 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL),
536 PHM_PlatformCaps_ControlVDDCI
539 set_hw_cap(
540 hwmgr,
541 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT),
542 PHM_PlatformCaps_RegulatorHot
545 set_hw_cap(
546 hwmgr,
547 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT),
548 PHM_PlatformCaps_BootStateOnAlert
551 set_hw_cap(
552 hwmgr,
553 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT),
554 PHM_PlatformCaps_DontWaitForVBlankOnAlert
557 set_hw_cap(
558 hwmgr,
559 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACO),
560 PHM_PlatformCaps_BACO
563 set_hw_cap(
564 hwmgr,
565 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE),
566 PHM_PlatformCaps_NewCACVoltage
569 set_hw_cap(
570 hwmgr,
571 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY),
572 PHM_PlatformCaps_RevertGPIO5Polarity
575 set_hw_cap(
576 hwmgr,
577 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17),
578 PHM_PlatformCaps_Thermal2GPIO17
581 set_hw_cap(
582 hwmgr,
583 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VRHOT_GPIO_CONFIGURABLE),
584 PHM_PlatformCaps_VRHotGPIOConfigurable
587 set_hw_cap(
588 hwmgr,
589 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TEMP_INVERSION),
590 PHM_PlatformCaps_TempInversion
593 set_hw_cap(
594 hwmgr,
595 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_EVV),
596 PHM_PlatformCaps_EVV
599 set_hw_cap(
600 hwmgr,
601 0 != (powerplay_caps & ATOM_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL),
602 PHM_PlatformCaps_CombinePCCWithThermalSignal
605 set_hw_cap(
606 hwmgr,
607 0 != (powerplay_caps & ATOM_PP_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE),
608 PHM_PlatformCaps_LoadPostProductionFirmware
611 set_hw_cap(
612 hwmgr,
613 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DISABLE_USING_ACTUAL_TEMPERATURE_FOR_POWER_CALC),
614 PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc
617 return 0;
620 static PP_StateClassificationFlags make_classification_flags(
621 struct pp_hwmgr *hwmgr,
622 USHORT classification,
623 USHORT classification2)
625 PP_StateClassificationFlags result = 0;
627 if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT)
628 result |= PP_StateClassificationFlag_Boot;
630 if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL)
631 result |= PP_StateClassificationFlag_Thermal;
633 if (classification &
634 ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
635 result |= PP_StateClassificationFlag_LimitedPowerSource;
637 if (classification & ATOM_PPLIB_CLASSIFICATION_REST)
638 result |= PP_StateClassificationFlag_Rest;
640 if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED)
641 result |= PP_StateClassificationFlag_Forced;
643 if (classification & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
644 result |= PP_StateClassificationFlag_3DPerformance;
647 if (classification & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE)
648 result |= PP_StateClassificationFlag_ACOverdriveTemplate;
650 if (classification & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
651 result |= PP_StateClassificationFlag_Uvd;
653 if (classification & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
654 result |= PP_StateClassificationFlag_UvdHD;
656 if (classification & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
657 result |= PP_StateClassificationFlag_UvdSD;
659 if (classification & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
660 result |= PP_StateClassificationFlag_HD2;
662 if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI)
663 result |= PP_StateClassificationFlag_ACPI;
665 if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
666 result |= PP_StateClassificationFlag_LimitedPowerSource_2;
669 if (classification2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
670 result |= PP_StateClassificationFlag_ULV;
672 if (classification2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
673 result |= PP_StateClassificationFlag_UvdMVC;
675 return result;
678 static int init_non_clock_fields(struct pp_hwmgr *hwmgr,
679 struct pp_power_state *ps,
680 uint8_t version,
681 const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info) {
682 unsigned long rrr_index;
683 unsigned long tmp;
685 ps->classification.ui_label = (le16_to_cpu(pnon_clock_info->usClassification) &
686 ATOM_PPLIB_CLASSIFICATION_UI_MASK) >> ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
687 ps->classification.flags = make_classification_flags(hwmgr,
688 le16_to_cpu(pnon_clock_info->usClassification),
689 le16_to_cpu(pnon_clock_info->usClassification2));
691 ps->classification.temporary_state = false;
692 ps->classification.to_be_deleted = false;
693 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
694 ATOM_PPLIB_SINGLE_DISPLAY_ONLY;
696 ps->validation.singleDisplayOnly = (0 != tmp);
698 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
699 ATOM_PPLIB_DISALLOW_ON_DC;
701 ps->validation.disallowOnDC = (0 != tmp);
703 ps->pcie.lanes = ((le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
704 ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
705 ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
707 ps->pcie.lanes = 0;
709 ps->display.disableFrameModulation = false;
711 rrr_index = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
712 ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK) >>
713 ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT;
715 if (rrr_index != ATOM_PPLIB_LIMITED_REFRESHRATE_UNLIMITED) {
716 static const uint8_t look_up[(ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK >> ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT) + 1] = \
717 { 0, 50, 0 };
719 ps->display.refreshrateSource = PP_RefreshrateSource_Explicit;
720 ps->display.explicitRefreshrate = look_up[rrr_index];
721 ps->display.limitRefreshrate = true;
723 if (ps->display.explicitRefreshrate == 0)
724 ps->display.limitRefreshrate = false;
725 } else
726 ps->display.limitRefreshrate = false;
728 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
729 ATOM_PPLIB_ENABLE_VARIBRIGHT;
731 ps->display.enableVariBright = (0 != tmp);
733 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
734 ATOM_PPLIB_SWSTATE_MEMORY_DLL_OFF;
736 ps->memory.dllOff = (0 != tmp);
738 ps->memory.m3arb = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
739 ATOM_PPLIB_M3ARB_MASK) >> ATOM_PPLIB_M3ARB_SHIFT;
741 ps->temperatures.min = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
742 pnon_clock_info->ucMinTemperature;
744 ps->temperatures.max = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
745 pnon_clock_info->ucMaxTemperature;
747 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
748 ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING;
750 ps->software.disableLoadBalancing = tmp;
752 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
753 ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS;
755 ps->software.enableSleepForTimestamps = (0 != tmp);
757 ps->validation.supportedPowerLevels = pnon_clock_info->ucRequiredPower;
759 if (ATOM_PPLIB_NONCLOCKINFO_VER1 < version) {
760 ps->uvd_clocks.VCLK = pnon_clock_info->ulVCLK;
761 ps->uvd_clocks.DCLK = pnon_clock_info->ulDCLK;
762 } else {
763 ps->uvd_clocks.VCLK = 0;
764 ps->uvd_clocks.DCLK = 0;
767 return 0;
770 static ULONG size_of_entry_v2(ULONG num_dpm_levels)
772 return (sizeof(UCHAR) + sizeof(UCHAR) +
773 (num_dpm_levels * sizeof(UCHAR)));
776 static const ATOM_PPLIB_STATE_V2 *get_state_entry_v2(
777 const StateArray * pstate_arrays,
778 ULONG entry_index)
780 ULONG i;
781 const ATOM_PPLIB_STATE_V2 *pstate;
783 pstate = pstate_arrays->states;
784 if (entry_index <= pstate_arrays->ucNumEntries) {
785 for (i = 0; i < entry_index; i++)
786 pstate = (ATOM_PPLIB_STATE_V2 *)(
787 (unsigned long)pstate +
788 size_of_entry_v2(pstate->ucNumDPMLevels));
790 return pstate;
793 static const unsigned char soft_dummy_pp_table[] = {
794 0xe1, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x4a, 0x00, 0x6c, 0x00, 0x00,
795 0x00, 0x00, 0x00, 0x42, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
796 0x00, 0x4e, 0x00, 0x88, 0x00, 0x00, 0x9e, 0x00, 0x17, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
797 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
798 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
799 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
800 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x18, 0x05, 0x00,
801 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
802 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
803 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00,
804 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00,
805 0x8e, 0x01, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x08, 0x30, 0x75, 0x00, 0x80, 0x00, 0xa0, 0x8c,
806 0x00, 0x7e, 0x00, 0x71, 0xa5, 0x00, 0x7c, 0x00, 0xe5, 0xc8, 0x00, 0x70, 0x00, 0x91, 0xf4, 0x00,
807 0x64, 0x00, 0x40, 0x19, 0x01, 0x5a, 0x00, 0x0e, 0x28, 0x01, 0x52, 0x00, 0x80, 0x38, 0x01, 0x4a,
808 0x00, 0x00, 0x09, 0x30, 0x75, 0x00, 0x30, 0x75, 0x00, 0x40, 0x9c, 0x00, 0x40, 0x9c, 0x00, 0x59,
809 0xd8, 0x00, 0x59, 0xd8, 0x00, 0x91, 0xf4, 0x00, 0x91, 0xf4, 0x00, 0x0e, 0x28, 0x01, 0x0e, 0x28,
810 0x01, 0x90, 0x5f, 0x01, 0x90, 0x5f, 0x01, 0x00, 0x77, 0x01, 0x00, 0x77, 0x01, 0xca, 0x91, 0x01,
811 0xca, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x01,
812 0x7c, 0x00, 0x02, 0x70, 0x00, 0x03, 0x64, 0x00, 0x04, 0x5a, 0x00, 0x05, 0x52, 0x00, 0x06, 0x4a,
813 0x00, 0x07, 0x08, 0x08, 0x00, 0x08, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03,
814 0x02, 0x04, 0x02, 0x00, 0x08, 0x40, 0x9c, 0x00, 0x30, 0x75, 0x00, 0x74, 0xb5, 0x00, 0xa0, 0x8c,
815 0x00, 0x60, 0xea, 0x00, 0x74, 0xb5, 0x00, 0x0e, 0x28, 0x01, 0x60, 0xea, 0x00, 0x90, 0x5f, 0x01,
816 0x40, 0x19, 0x01, 0xb2, 0xb0, 0x01, 0x90, 0x5f, 0x01, 0xc0, 0xd4, 0x01, 0x00, 0x77, 0x01, 0x5e,
817 0xff, 0x01, 0xca, 0x91, 0x01, 0x08, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x01, 0x7c, 0x00, 0x02, 0x70,
818 0x00, 0x03, 0x64, 0x00, 0x04, 0x5a, 0x00, 0x05, 0x52, 0x00, 0x06, 0x4a, 0x00, 0x07, 0x00, 0x08,
819 0x80, 0x00, 0x30, 0x75, 0x00, 0x7e, 0x00, 0x40, 0x9c, 0x00, 0x7c, 0x00, 0x59, 0xd8, 0x00, 0x70,
820 0x00, 0xdc, 0x0b, 0x01, 0x64, 0x00, 0x80, 0x38, 0x01, 0x5a, 0x00, 0x80, 0x38, 0x01, 0x52, 0x00,
821 0x80, 0x38, 0x01, 0x4a, 0x00, 0x80, 0x38, 0x01, 0x08, 0x30, 0x75, 0x00, 0x80, 0x00, 0xa0, 0x8c,
822 0x00, 0x7e, 0x00, 0x71, 0xa5, 0x00, 0x7c, 0x00, 0xe5, 0xc8, 0x00, 0x74, 0x00, 0x91, 0xf4, 0x00,
823 0x66, 0x00, 0x40, 0x19, 0x01, 0x58, 0x00, 0x0e, 0x28, 0x01, 0x52, 0x00, 0x80, 0x38, 0x01, 0x4a,
824 0x00
827 static const ATOM_PPLIB_POWERPLAYTABLE *get_powerplay_table(
828 struct pp_hwmgr *hwmgr)
830 const void *table_addr = hwmgr->soft_pp_table;
831 uint8_t frev, crev;
832 uint16_t size;
834 if (!table_addr) {
835 if (hwmgr->chip_id == CHIP_RAVEN) {
836 table_addr = &soft_dummy_pp_table[0];
837 hwmgr->soft_pp_table = &soft_dummy_pp_table[0];
838 hwmgr->soft_pp_table_size = sizeof(soft_dummy_pp_table);
839 } else {
840 table_addr = smu_atom_get_data_table(hwmgr->adev,
841 GetIndexIntoMasterTable(DATA, PowerPlayInfo),
842 &size, &frev, &crev);
843 hwmgr->soft_pp_table = table_addr;
844 hwmgr->soft_pp_table_size = size;
848 return (const ATOM_PPLIB_POWERPLAYTABLE *)table_addr;
851 int pp_tables_get_response_times(struct pp_hwmgr *hwmgr,
852 uint32_t *vol_rep_time, uint32_t *bb_rep_time)
854 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_tab = get_powerplay_table(hwmgr);
856 PP_ASSERT_WITH_CODE(NULL != powerplay_tab,
857 "Missing PowerPlay Table!", return -EINVAL);
859 *vol_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usVoltageTime);
860 *bb_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usBackbiasTime);
862 return 0;
865 int pp_tables_get_num_of_entries(struct pp_hwmgr *hwmgr,
866 unsigned long *num_of_entries)
868 const StateArray *pstate_arrays;
869 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
871 if (powerplay_table == NULL)
872 return -1;
874 if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
875 pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
876 le16_to_cpu(powerplay_table->usStateArrayOffset));
878 *num_of_entries = (unsigned long)(pstate_arrays->ucNumEntries);
879 } else
880 *num_of_entries = (unsigned long)(powerplay_table->ucNumStates);
882 return 0;
885 int pp_tables_get_entry(struct pp_hwmgr *hwmgr,
886 unsigned long entry_index,
887 struct pp_power_state *ps,
888 pp_tables_hw_clock_info_callback func)
890 int i;
891 const StateArray *pstate_arrays;
892 const ATOM_PPLIB_STATE_V2 *pstate_entry_v2;
893 const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info;
894 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
895 int result = 0;
896 int res = 0;
898 const ClockInfoArray *pclock_arrays;
900 const NonClockInfoArray *pnon_clock_arrays;
902 const ATOM_PPLIB_STATE *pstate_entry;
904 if (powerplay_table == NULL)
905 return -1;
907 ps->classification.bios_index = entry_index;
909 if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
910 pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
911 le16_to_cpu(powerplay_table->usStateArrayOffset));
913 if (entry_index > pstate_arrays->ucNumEntries)
914 return -1;
916 pstate_entry_v2 = get_state_entry_v2(pstate_arrays, entry_index);
917 pclock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) +
918 le16_to_cpu(powerplay_table->usClockInfoArrayOffset));
920 pnon_clock_arrays = (NonClockInfoArray *)(((unsigned long)powerplay_table) +
921 le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset));
923 pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)(pnon_clock_arrays->nonClockInfo) +
924 (pstate_entry_v2->nonClockInfoIndex * pnon_clock_arrays->ucEntrySize));
926 result = init_non_clock_fields(hwmgr, ps, pnon_clock_arrays->ucEntrySize, pnon_clock_info);
928 for (i = 0; i < pstate_entry_v2->ucNumDPMLevels; i++) {
929 const void *pclock_info = (const void *)(
930 (unsigned long)(pclock_arrays->clockInfo) +
931 (pstate_entry_v2->clockInfoIndex[i] * pclock_arrays->ucEntrySize));
932 res = func(hwmgr, &ps->hardware, i, pclock_info);
933 if ((0 == result) && (0 != res))
934 result = res;
936 } else {
937 if (entry_index > powerplay_table->ucNumStates)
938 return -1;
940 pstate_entry = (ATOM_PPLIB_STATE *)((unsigned long)powerplay_table + powerplay_table->usStateArrayOffset +
941 entry_index * powerplay_table->ucStateEntrySize);
943 pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)powerplay_table +
944 le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset) +
945 pstate_entry->ucNonClockStateIndex *
946 powerplay_table->ucNonClockSize);
948 result = init_non_clock_fields(hwmgr, ps,
949 powerplay_table->ucNonClockSize,
950 pnon_clock_info);
952 for (i = 0; i < powerplay_table->ucStateEntrySize-1; i++) {
953 const void *pclock_info = (const void *)((unsigned long)powerplay_table +
954 le16_to_cpu(powerplay_table->usClockInfoArrayOffset) +
955 pstate_entry->ucClockStateIndices[i] *
956 powerplay_table->ucClockInfoSize);
958 int res = func(hwmgr, &ps->hardware, i, pclock_info);
960 if ((0 == result) && (0 != res))
961 result = res;
965 if ((0 == result) && (0 != (ps->classification.flags & PP_StateClassificationFlag_Boot))) {
966 if (hwmgr->chip_family < AMDGPU_FAMILY_RV)
967 result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(ps->hardware));
970 return result;
973 static int init_powerplay_tables(
974 struct pp_hwmgr *hwmgr,
975 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table
978 return 0;
982 static int init_thermal_controller(
983 struct pp_hwmgr *hwmgr,
984 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
986 hwmgr->thermal_controller.ucType =
987 powerplay_table->sThermalController.ucType;
988 hwmgr->thermal_controller.ucI2cLine =
989 powerplay_table->sThermalController.ucI2cLine;
990 hwmgr->thermal_controller.ucI2cAddress =
991 powerplay_table->sThermalController.ucI2cAddress;
993 hwmgr->thermal_controller.fanInfo.bNoFan =
994 (0 != (powerplay_table->sThermalController.ucFanParameters &
995 ATOM_PP_FANPARAMETERS_NOFAN));
997 hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution =
998 powerplay_table->sThermalController.ucFanParameters &
999 ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
1001 hwmgr->thermal_controller.fanInfo.ulMinRPM
1002 = powerplay_table->sThermalController.ucFanMinRPM * 100UL;
1003 hwmgr->thermal_controller.fanInfo.ulMaxRPM
1004 = powerplay_table->sThermalController.ucFanMaxRPM * 100UL;
1006 set_hw_cap(hwmgr,
1007 ATOM_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType,
1008 PHM_PlatformCaps_ThermalController);
1010 hwmgr->thermal_controller.use_hw_fan_control = 1;
1012 return 0;
1015 static int init_overdrive_limits_V1_4(struct pp_hwmgr *hwmgr,
1016 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
1017 const ATOM_FIRMWARE_INFO_V1_4 *fw_info)
1019 hwmgr->platform_descriptor.overdriveLimit.engineClock =
1020 le32_to_cpu(fw_info->ulASICMaxEngineClock);
1022 hwmgr->platform_descriptor.overdriveLimit.memoryClock =
1023 le32_to_cpu(fw_info->ulASICMaxMemoryClock);
1025 hwmgr->platform_descriptor.maxOverdriveVDDC =
1026 le32_to_cpu(fw_info->ul3DAccelerationEngineClock) & 0x7FF;
1028 hwmgr->platform_descriptor.minOverdriveVDDC =
1029 le16_to_cpu(fw_info->usBootUpVDDCVoltage);
1031 hwmgr->platform_descriptor.maxOverdriveVDDC =
1032 le16_to_cpu(fw_info->usBootUpVDDCVoltage);
1034 hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1035 return 0;
1038 static int init_overdrive_limits_V2_1(struct pp_hwmgr *hwmgr,
1039 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
1040 const ATOM_FIRMWARE_INFO_V2_1 *fw_info)
1042 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3;
1043 const ATOM_PPLIB_EXTENDEDHEADER *header;
1045 if (le16_to_cpu(powerplay_table->usTableSize) <
1046 sizeof(ATOM_PPLIB_POWERPLAYTABLE3))
1047 return 0;
1049 powerplay_table3 = (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
1051 if (0 == powerplay_table3->usExtendendedHeaderOffset)
1052 return 0;
1054 header = (ATOM_PPLIB_EXTENDEDHEADER *)(((unsigned long) powerplay_table) +
1055 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
1057 hwmgr->platform_descriptor.overdriveLimit.engineClock = le32_to_cpu(header->ulMaxEngineClock);
1058 hwmgr->platform_descriptor.overdriveLimit.memoryClock = le32_to_cpu(header->ulMaxMemoryClock);
1061 hwmgr->platform_descriptor.minOverdriveVDDC = 0;
1062 hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
1063 hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1065 return 0;
1068 static int init_overdrive_limits(struct pp_hwmgr *hwmgr,
1069 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1071 int result = 0;
1072 uint8_t frev, crev;
1073 uint16_t size;
1075 const ATOM_COMMON_TABLE_HEADER *fw_info = NULL;
1077 hwmgr->platform_descriptor.overdriveLimit.engineClock = 0;
1078 hwmgr->platform_descriptor.overdriveLimit.memoryClock = 0;
1079 hwmgr->platform_descriptor.minOverdriveVDDC = 0;
1080 hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
1081 hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1083 if (hwmgr->chip_id == CHIP_RAVEN)
1084 return 0;
1086 /* We assume here that fw_info is unchanged if this call fails.*/
1087 fw_info = smu_atom_get_data_table(hwmgr->adev,
1088 GetIndexIntoMasterTable(DATA, FirmwareInfo),
1089 &size, &frev, &crev);
1091 if ((fw_info->ucTableFormatRevision == 1)
1092 && (fw_info->usStructureSize >= sizeof(ATOM_FIRMWARE_INFO_V1_4)))
1093 result = init_overdrive_limits_V1_4(hwmgr,
1094 powerplay_table,
1095 (const ATOM_FIRMWARE_INFO_V1_4 *)fw_info);
1097 else if ((fw_info->ucTableFormatRevision == 2)
1098 && (fw_info->usStructureSize >= sizeof(ATOM_FIRMWARE_INFO_V2_1)))
1099 result = init_overdrive_limits_V2_1(hwmgr,
1100 powerplay_table,
1101 (const ATOM_FIRMWARE_INFO_V2_1 *)fw_info);
1103 return result;
1106 static int get_uvd_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1107 struct phm_uvd_clock_voltage_dependency_table **ptable,
1108 const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *table,
1109 const UVDClockInfoArray *array)
1111 unsigned long table_size, i;
1112 struct phm_uvd_clock_voltage_dependency_table *uvd_table;
1114 table_size = sizeof(unsigned long) +
1115 sizeof(struct phm_uvd_clock_voltage_dependency_table) *
1116 table->numEntries;
1118 uvd_table = kzalloc(table_size, GFP_KERNEL);
1119 if (NULL == uvd_table)
1120 return -ENOMEM;
1122 uvd_table->count = table->numEntries;
1124 for (i = 0; i < table->numEntries; i++) {
1125 const UVDClockInfo *entry =
1126 &array->entries[table->entries[i].ucUVDClockInfoIndex];
1127 uvd_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1128 uvd_table->entries[i].vclk = ((unsigned long)entry->ucVClkHigh << 16)
1129 | le16_to_cpu(entry->usVClkLow);
1130 uvd_table->entries[i].dclk = ((unsigned long)entry->ucDClkHigh << 16)
1131 | le16_to_cpu(entry->usDClkLow);
1134 *ptable = uvd_table;
1136 return 0;
1139 static int get_vce_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1140 struct phm_vce_clock_voltage_dependency_table **ptable,
1141 const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table,
1142 const VCEClockInfoArray *array)
1144 unsigned long table_size, i;
1145 struct phm_vce_clock_voltage_dependency_table *vce_table = NULL;
1147 table_size = sizeof(unsigned long) +
1148 sizeof(struct phm_vce_clock_voltage_dependency_table)
1149 * table->numEntries;
1151 vce_table = kzalloc(table_size, GFP_KERNEL);
1152 if (NULL == vce_table)
1153 return -ENOMEM;
1155 vce_table->count = table->numEntries;
1156 for (i = 0; i < table->numEntries; i++) {
1157 const VCEClockInfo *entry = &array->entries[table->entries[i].ucVCEClockInfoIndex];
1159 vce_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1160 vce_table->entries[i].evclk = ((unsigned long)entry->ucEVClkHigh << 16)
1161 | le16_to_cpu(entry->usEVClkLow);
1162 vce_table->entries[i].ecclk = ((unsigned long)entry->ucECClkHigh << 16)
1163 | le16_to_cpu(entry->usECClkLow);
1166 *ptable = vce_table;
1168 return 0;
1171 static int get_samu_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1172 struct phm_samu_clock_voltage_dependency_table **ptable,
1173 const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *table)
1175 unsigned long table_size, i;
1176 struct phm_samu_clock_voltage_dependency_table *samu_table;
1178 table_size = sizeof(unsigned long) +
1179 sizeof(struct phm_samu_clock_voltage_dependency_table) *
1180 table->numEntries;
1182 samu_table = kzalloc(table_size, GFP_KERNEL);
1183 if (NULL == samu_table)
1184 return -ENOMEM;
1186 samu_table->count = table->numEntries;
1188 for (i = 0; i < table->numEntries; i++) {
1189 samu_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1190 samu_table->entries[i].samclk = ((unsigned long)table->entries[i].ucSAMClockHigh << 16)
1191 | le16_to_cpu(table->entries[i].usSAMClockLow);
1194 *ptable = samu_table;
1196 return 0;
1199 static int get_acp_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1200 struct phm_acp_clock_voltage_dependency_table **ptable,
1201 const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *table)
1203 unsigned table_size, i;
1204 struct phm_acp_clock_voltage_dependency_table *acp_table;
1206 table_size = sizeof(unsigned long) +
1207 sizeof(struct phm_acp_clock_voltage_dependency_table) *
1208 table->numEntries;
1210 acp_table = kzalloc(table_size, GFP_KERNEL);
1211 if (NULL == acp_table)
1212 return -ENOMEM;
1214 acp_table->count = (unsigned long)table->numEntries;
1216 for (i = 0; i < table->numEntries; i++) {
1217 acp_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1218 acp_table->entries[i].acpclk = ((unsigned long)table->entries[i].ucACPClockHigh << 16)
1219 | le16_to_cpu(table->entries[i].usACPClockLow);
1222 *ptable = acp_table;
1224 return 0;
1227 static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr,
1228 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1230 ATOM_PPLIB_Clock_Voltage_Dependency_Table *table;
1231 ATOM_PPLIB_Clock_Voltage_Limit_Table *limit_table;
1232 int result = 0;
1234 uint16_t vce_clock_info_array_offset;
1235 uint16_t uvd_clock_info_array_offset;
1236 uint16_t table_offset;
1238 hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
1239 hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
1240 hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
1241 hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
1242 hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
1243 hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
1244 hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
1245 hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL;
1246 hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL;
1247 hwmgr->dyn_state.ppm_parameter_table = NULL;
1248 hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL;
1250 vce_clock_info_array_offset = get_vce_clock_info_array_offset(
1251 hwmgr, powerplay_table);
1252 table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr,
1253 powerplay_table);
1254 if (vce_clock_info_array_offset > 0 && table_offset > 0) {
1255 const VCEClockInfoArray *array = (const VCEClockInfoArray *)
1256 (((unsigned long) powerplay_table) +
1257 vce_clock_info_array_offset);
1258 const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table =
1259 (const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)
1260 (((unsigned long) powerplay_table) + table_offset);
1261 result = get_vce_clock_voltage_limit_table(hwmgr,
1262 &hwmgr->dyn_state.vce_clock_voltage_dependency_table,
1263 table, array);
1266 uvd_clock_info_array_offset = get_uvd_clock_info_array_offset(hwmgr, powerplay_table);
1267 table_offset = get_uvd_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
1269 if (uvd_clock_info_array_offset > 0 && table_offset > 0) {
1270 const UVDClockInfoArray *array = (const UVDClockInfoArray *)
1271 (((unsigned long) powerplay_table) +
1272 uvd_clock_info_array_offset);
1273 const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *ptable =
1274 (const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *)
1275 (((unsigned long) powerplay_table) + table_offset);
1276 result = get_uvd_clock_voltage_limit_table(hwmgr,
1277 &hwmgr->dyn_state.uvd_clock_voltage_dependency_table, ptable, array);
1280 table_offset = get_samu_clock_voltage_limit_table_offset(hwmgr,
1281 powerplay_table);
1283 if (table_offset > 0) {
1284 const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *ptable =
1285 (const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *)
1286 (((unsigned long) powerplay_table) + table_offset);
1287 result = get_samu_clock_voltage_limit_table(hwmgr,
1288 &hwmgr->dyn_state.samu_clock_voltage_dependency_table, ptable);
1291 table_offset = get_acp_clock_voltage_limit_table_offset(hwmgr,
1292 powerplay_table);
1294 if (table_offset > 0) {
1295 const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *ptable =
1296 (const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *)
1297 (((unsigned long) powerplay_table) + table_offset);
1298 result = get_acp_clock_voltage_limit_table(hwmgr,
1299 &hwmgr->dyn_state.acp_clock_voltage_dependency_table, ptable);
1302 table_offset = get_cacp_tdp_table_offset(hwmgr, powerplay_table);
1303 if (table_offset > 0) {
1304 UCHAR rev_id = *(UCHAR *)(((unsigned long)powerplay_table) + table_offset);
1306 if (rev_id > 0) {
1307 const ATOM_PPLIB_POWERTUNE_Table_V1 *tune_table =
1308 (const ATOM_PPLIB_POWERTUNE_Table_V1 *)
1309 (((unsigned long) powerplay_table) + table_offset);
1310 result = get_cac_tdp_table(hwmgr, &hwmgr->dyn_state.cac_dtp_table,
1311 &tune_table->power_tune_table,
1312 le16_to_cpu(tune_table->usMaximumPowerDeliveryLimit));
1313 hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
1314 le16_to_cpu(tune_table->usTjMax);
1315 } else {
1316 const ATOM_PPLIB_POWERTUNE_Table *tune_table =
1317 (const ATOM_PPLIB_POWERTUNE_Table *)
1318 (((unsigned long) powerplay_table) + table_offset);
1319 result = get_cac_tdp_table(hwmgr,
1320 &hwmgr->dyn_state.cac_dtp_table,
1321 &tune_table->power_tune_table, 255);
1325 if (le16_to_cpu(powerplay_table->usTableSize) >=
1326 sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) {
1327 const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 =
1328 (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table;
1329 if (0 != powerplay_table4->usVddcDependencyOnSCLKOffset) {
1330 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1331 (((unsigned long) powerplay_table4) +
1332 powerplay_table4->usVddcDependencyOnSCLKOffset);
1333 result = get_clock_voltage_dependency_table(hwmgr,
1334 &hwmgr->dyn_state.vddc_dependency_on_sclk, table);
1337 if (result == 0 && (0 != powerplay_table4->usVddciDependencyOnMCLKOffset)) {
1338 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1339 (((unsigned long) powerplay_table4) +
1340 powerplay_table4->usVddciDependencyOnMCLKOffset);
1341 result = get_clock_voltage_dependency_table(hwmgr,
1342 &hwmgr->dyn_state.vddci_dependency_on_mclk, table);
1345 if (result == 0 && (0 != powerplay_table4->usVddcDependencyOnMCLKOffset)) {
1346 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1347 (((unsigned long) powerplay_table4) +
1348 powerplay_table4->usVddcDependencyOnMCLKOffset);
1349 result = get_clock_voltage_dependency_table(hwmgr,
1350 &hwmgr->dyn_state.vddc_dependency_on_mclk, table);
1353 if (result == 0 && (0 != powerplay_table4->usMaxClockVoltageOnDCOffset)) {
1354 limit_table = (ATOM_PPLIB_Clock_Voltage_Limit_Table *)
1355 (((unsigned long) powerplay_table4) +
1356 powerplay_table4->usMaxClockVoltageOnDCOffset);
1357 result = get_clock_voltage_limit(hwmgr,
1358 &hwmgr->dyn_state.max_clock_voltage_on_dc, limit_table);
1361 if (result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_mclk) &&
1362 (0 != hwmgr->dyn_state.vddc_dependency_on_mclk->count))
1363 result = get_valid_clk(hwmgr, &hwmgr->dyn_state.valid_mclk_values,
1364 hwmgr->dyn_state.vddc_dependency_on_mclk);
1366 if(result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_sclk) &&
1367 (0 != hwmgr->dyn_state.vddc_dependency_on_sclk->count))
1368 result = get_valid_clk(hwmgr,
1369 &hwmgr->dyn_state.valid_sclk_values,
1370 hwmgr->dyn_state.vddc_dependency_on_sclk);
1372 if (result == 0 && (0 != powerplay_table4->usMvddDependencyOnMCLKOffset)) {
1373 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1374 (((unsigned long) powerplay_table4) +
1375 powerplay_table4->usMvddDependencyOnMCLKOffset);
1376 result = get_clock_voltage_dependency_table(hwmgr,
1377 &hwmgr->dyn_state.mvdd_dependency_on_mclk, table);
1381 table_offset = get_sclk_vdd_gfx_clock_voltage_dependency_table_offset(hwmgr,
1382 powerplay_table);
1384 if (table_offset > 0) {
1385 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1386 (((unsigned long) powerplay_table) + table_offset);
1387 result = get_clock_voltage_dependency_table(hwmgr,
1388 &hwmgr->dyn_state.vdd_gfx_dependency_on_sclk, table);
1391 return result;
1394 static int get_cac_leakage_table(struct pp_hwmgr *hwmgr,
1395 struct phm_cac_leakage_table **ptable,
1396 const ATOM_PPLIB_CAC_Leakage_Table *table)
1398 struct phm_cac_leakage_table *cac_leakage_table;
1399 unsigned long table_size, i;
1401 if (hwmgr == NULL || table == NULL || ptable == NULL)
1402 return -EINVAL;
1404 table_size = sizeof(ULONG) +
1405 (sizeof(struct phm_cac_leakage_table) * table->ucNumEntries);
1407 cac_leakage_table = kzalloc(table_size, GFP_KERNEL);
1409 if (cac_leakage_table == NULL)
1410 return -ENOMEM;
1412 cac_leakage_table->count = (ULONG)table->ucNumEntries;
1414 for (i = 0; i < cac_leakage_table->count; i++) {
1415 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1416 PHM_PlatformCaps_EVV)) {
1417 cac_leakage_table->entries[i].Vddc1 = le16_to_cpu(table->entries[i].usVddc1);
1418 cac_leakage_table->entries[i].Vddc2 = le16_to_cpu(table->entries[i].usVddc2);
1419 cac_leakage_table->entries[i].Vddc3 = le16_to_cpu(table->entries[i].usVddc3);
1420 } else {
1421 cac_leakage_table->entries[i].Vddc = le16_to_cpu(table->entries[i].usVddc);
1422 cac_leakage_table->entries[i].Leakage = le32_to_cpu(table->entries[i].ulLeakageValue);
1426 *ptable = cac_leakage_table;
1428 return 0;
1431 static int get_platform_power_management_table(struct pp_hwmgr *hwmgr,
1432 ATOM_PPLIB_PPM_Table *atom_ppm_table)
1434 struct phm_ppm_table *ptr = kzalloc(sizeof(struct phm_ppm_table), GFP_KERNEL);
1436 if (NULL == ptr)
1437 return -ENOMEM;
1439 ptr->ppm_design = atom_ppm_table->ucPpmDesign;
1440 ptr->cpu_core_number = le16_to_cpu(atom_ppm_table->usCpuCoreNumber);
1441 ptr->platform_tdp = le32_to_cpu(atom_ppm_table->ulPlatformTDP);
1442 ptr->small_ac_platform_tdp = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDP);
1443 ptr->platform_tdc = le32_to_cpu(atom_ppm_table->ulPlatformTDC);
1444 ptr->small_ac_platform_tdc = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDC);
1445 ptr->apu_tdp = le32_to_cpu(atom_ppm_table->ulApuTDP);
1446 ptr->dgpu_tdp = le32_to_cpu(atom_ppm_table->ulDGpuTDP);
1447 ptr->dgpu_ulv_power = le32_to_cpu(atom_ppm_table->ulDGpuUlvPower);
1448 ptr->tj_max = le32_to_cpu(atom_ppm_table->ulTjmax);
1449 hwmgr->dyn_state.ppm_parameter_table = ptr;
1451 return 0;
1454 static int init_dpm2_parameters(struct pp_hwmgr *hwmgr,
1455 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1457 int result = 0;
1459 if (le16_to_cpu(powerplay_table->usTableSize) >=
1460 sizeof(ATOM_PPLIB_POWERPLAYTABLE5)) {
1461 const ATOM_PPLIB_POWERPLAYTABLE5 *ptable5 =
1462 (const ATOM_PPLIB_POWERPLAYTABLE5 *)powerplay_table;
1463 const ATOM_PPLIB_POWERPLAYTABLE4 *ptable4 =
1464 (const ATOM_PPLIB_POWERPLAYTABLE4 *)
1465 (&ptable5->basicTable4);
1466 const ATOM_PPLIB_POWERPLAYTABLE3 *ptable3 =
1467 (const ATOM_PPLIB_POWERPLAYTABLE3 *)
1468 (&ptable4->basicTable3);
1469 const ATOM_PPLIB_EXTENDEDHEADER *extended_header;
1470 uint16_t table_offset;
1471 ATOM_PPLIB_PPM_Table *atom_ppm_table;
1473 hwmgr->platform_descriptor.TDPLimit = le32_to_cpu(ptable5->ulTDPLimit);
1474 hwmgr->platform_descriptor.nearTDPLimit = le32_to_cpu(ptable5->ulNearTDPLimit);
1476 hwmgr->platform_descriptor.TDPODLimit = le16_to_cpu(ptable5->usTDPODLimit);
1477 hwmgr->platform_descriptor.TDPAdjustment = 0;
1479 hwmgr->platform_descriptor.VidAdjustment = 0;
1480 hwmgr->platform_descriptor.VidAdjustmentPolarity = 0;
1481 hwmgr->platform_descriptor.VidMinLimit = 0;
1482 hwmgr->platform_descriptor.VidMaxLimit = 1500000;
1483 hwmgr->platform_descriptor.VidStep = 6250;
1485 hwmgr->platform_descriptor.nearTDPLimitAdjusted = le32_to_cpu(ptable5->ulNearTDPLimit);
1487 if (hwmgr->platform_descriptor.TDPODLimit != 0)
1488 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1489 PHM_PlatformCaps_PowerControl);
1491 hwmgr->platform_descriptor.SQRampingThreshold = le32_to_cpu(ptable5->ulSQRampingThreshold);
1493 hwmgr->platform_descriptor.CACLeakage = le32_to_cpu(ptable5->ulCACLeakage);
1495 hwmgr->dyn_state.cac_leakage_table = NULL;
1497 if (0 != ptable5->usCACLeakageTableOffset) {
1498 const ATOM_PPLIB_CAC_Leakage_Table *pCAC_leakage_table =
1499 (ATOM_PPLIB_CAC_Leakage_Table *)(((unsigned long)ptable5) +
1500 le16_to_cpu(ptable5->usCACLeakageTableOffset));
1501 result = get_cac_leakage_table(hwmgr,
1502 &hwmgr->dyn_state.cac_leakage_table, pCAC_leakage_table);
1505 hwmgr->platform_descriptor.LoadLineSlope = le16_to_cpu(ptable5->usLoadLineSlope);
1507 hwmgr->dyn_state.ppm_parameter_table = NULL;
1509 if (0 != ptable3->usExtendendedHeaderOffset) {
1510 extended_header = (const ATOM_PPLIB_EXTENDEDHEADER *)
1511 (((unsigned long)powerplay_table) +
1512 le16_to_cpu(ptable3->usExtendendedHeaderOffset));
1513 if ((extended_header->usPPMTableOffset > 0) &&
1514 le16_to_cpu(extended_header->usSize) >=
1515 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) {
1516 table_offset = le16_to_cpu(extended_header->usPPMTableOffset);
1517 atom_ppm_table = (ATOM_PPLIB_PPM_Table *)
1518 (((unsigned long)powerplay_table) + table_offset);
1519 if (0 == get_platform_power_management_table(hwmgr, atom_ppm_table))
1520 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1521 PHM_PlatformCaps_EnablePlatformPowerManagement);
1525 return result;
1528 static int init_phase_shedding_table(struct pp_hwmgr *hwmgr,
1529 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1531 if (le16_to_cpu(powerplay_table->usTableSize) >=
1532 sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) {
1533 const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 =
1534 (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table;
1536 if (0 != powerplay_table4->usVddcPhaseShedLimitsTableOffset) {
1537 const ATOM_PPLIB_PhaseSheddingLimits_Table *ptable =
1538 (ATOM_PPLIB_PhaseSheddingLimits_Table *)
1539 (((unsigned long)powerplay_table4) +
1540 le16_to_cpu(powerplay_table4->usVddcPhaseShedLimitsTableOffset));
1541 struct phm_phase_shedding_limits_table *table;
1542 unsigned long size, i;
1545 size = sizeof(unsigned long) +
1546 (sizeof(struct phm_phase_shedding_limits_table) *
1547 ptable->ucNumEntries);
1549 table = kzalloc(size, GFP_KERNEL);
1551 if (table == NULL)
1552 return -ENOMEM;
1554 table->count = (unsigned long)ptable->ucNumEntries;
1556 for (i = 0; i < table->count; i++) {
1557 table->entries[i].Voltage = (unsigned long)le16_to_cpu(ptable->entries[i].usVoltage);
1558 table->entries[i].Sclk = ((unsigned long)ptable->entries[i].ucSclkHigh << 16)
1559 | le16_to_cpu(ptable->entries[i].usSclkLow);
1560 table->entries[i].Mclk = ((unsigned long)ptable->entries[i].ucMclkHigh << 16)
1561 | le16_to_cpu(ptable->entries[i].usMclkLow);
1563 hwmgr->dyn_state.vddc_phase_shed_limits_table = table;
1567 return 0;
1570 static int get_number_of_vce_state_table_entries(
1571 struct pp_hwmgr *hwmgr)
1573 const ATOM_PPLIB_POWERPLAYTABLE *table =
1574 get_powerplay_table(hwmgr);
1575 const ATOM_PPLIB_VCE_State_Table *vce_table =
1576 get_vce_state_table(hwmgr, table);
1578 if (vce_table)
1579 return vce_table->numEntries;
1581 return 0;
1584 static int get_vce_state_table_entry(struct pp_hwmgr *hwmgr,
1585 unsigned long i,
1586 struct amd_vce_state *vce_state,
1587 void **clock_info,
1588 unsigned long *flag)
1590 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
1592 const ATOM_PPLIB_VCE_State_Table *vce_state_table = get_vce_state_table(hwmgr, powerplay_table);
1594 unsigned short vce_clock_info_array_offset = get_vce_clock_info_array_offset(hwmgr, powerplay_table);
1596 const VCEClockInfoArray *vce_clock_info_array = (const VCEClockInfoArray *)(((unsigned long) powerplay_table) + vce_clock_info_array_offset);
1598 const ClockInfoArray *clock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) + powerplay_table->usClockInfoArrayOffset);
1600 const ATOM_PPLIB_VCE_State_Record *record = &vce_state_table->entries[i];
1602 const VCEClockInfo *vce_clock_info = &vce_clock_info_array->entries[record->ucVCEClockInfoIndex];
1604 unsigned long clockInfoIndex = record->ucClockInfoIndex & 0x3F;
1606 *flag = (record->ucClockInfoIndex >> NUM_BITS_CLOCK_INFO_ARRAY_INDEX);
1608 vce_state->evclk = ((uint32_t)vce_clock_info->ucEVClkHigh << 16) | vce_clock_info->usEVClkLow;
1609 vce_state->ecclk = ((uint32_t)vce_clock_info->ucECClkHigh << 16) | vce_clock_info->usECClkLow;
1611 *clock_info = (void *)((unsigned long)(clock_arrays->clockInfo) + (clockInfoIndex * clock_arrays->ucEntrySize));
1613 return 0;
1617 static int pp_tables_initialize(struct pp_hwmgr *hwmgr)
1619 int result;
1620 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table;
1622 if (hwmgr->chip_id == CHIP_RAVEN)
1623 return 0;
1625 hwmgr->need_pp_table_upload = true;
1627 powerplay_table = get_powerplay_table(hwmgr);
1629 result = init_powerplay_tables(hwmgr, powerplay_table);
1631 PP_ASSERT_WITH_CODE((result == 0),
1632 "init_powerplay_tables failed", return result);
1634 result = set_platform_caps(hwmgr,
1635 le32_to_cpu(powerplay_table->ulPlatformCaps));
1637 PP_ASSERT_WITH_CODE((result == 0),
1638 "set_platform_caps failed", return result);
1640 result = init_thermal_controller(hwmgr, powerplay_table);
1642 PP_ASSERT_WITH_CODE((result == 0),
1643 "init_thermal_controller failed", return result);
1645 result = init_overdrive_limits(hwmgr, powerplay_table);
1647 PP_ASSERT_WITH_CODE((result == 0),
1648 "init_overdrive_limits failed", return result);
1650 result = init_clock_voltage_dependency(hwmgr,
1651 powerplay_table);
1653 PP_ASSERT_WITH_CODE((result == 0),
1654 "init_clock_voltage_dependency failed", return result);
1656 result = init_dpm2_parameters(hwmgr, powerplay_table);
1658 PP_ASSERT_WITH_CODE((result == 0),
1659 "init_dpm2_parameters failed", return result);
1661 result = init_phase_shedding_table(hwmgr, powerplay_table);
1663 PP_ASSERT_WITH_CODE((result == 0),
1664 "init_phase_shedding_table failed", return result);
1666 return result;
1669 static int pp_tables_uninitialize(struct pp_hwmgr *hwmgr)
1671 if (hwmgr->chip_id == CHIP_RAVEN)
1672 return 0;
1674 kfree(hwmgr->dyn_state.vddc_dependency_on_sclk);
1675 hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
1677 kfree(hwmgr->dyn_state.vddci_dependency_on_mclk);
1678 hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
1680 kfree(hwmgr->dyn_state.vddc_dependency_on_mclk);
1681 hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
1683 kfree(hwmgr->dyn_state.mvdd_dependency_on_mclk);
1684 hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
1686 kfree(hwmgr->dyn_state.valid_mclk_values);
1687 hwmgr->dyn_state.valid_mclk_values = NULL;
1689 kfree(hwmgr->dyn_state.valid_sclk_values);
1690 hwmgr->dyn_state.valid_sclk_values = NULL;
1692 kfree(hwmgr->dyn_state.cac_leakage_table);
1693 hwmgr->dyn_state.cac_leakage_table = NULL;
1695 kfree(hwmgr->dyn_state.vddc_phase_shed_limits_table);
1696 hwmgr->dyn_state.vddc_phase_shed_limits_table = NULL;
1698 kfree(hwmgr->dyn_state.vce_clock_voltage_dependency_table);
1699 hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
1701 kfree(hwmgr->dyn_state.uvd_clock_voltage_dependency_table);
1702 hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
1704 kfree(hwmgr->dyn_state.samu_clock_voltage_dependency_table);
1705 hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL;
1707 kfree(hwmgr->dyn_state.acp_clock_voltage_dependency_table);
1708 hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL;
1710 kfree(hwmgr->dyn_state.cac_dtp_table);
1711 hwmgr->dyn_state.cac_dtp_table = NULL;
1713 kfree(hwmgr->dyn_state.ppm_parameter_table);
1714 hwmgr->dyn_state.ppm_parameter_table = NULL;
1716 kfree(hwmgr->dyn_state.vdd_gfx_dependency_on_sclk);
1717 hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL;
1719 return 0;
1722 const struct pp_table_func pptable_funcs = {
1723 .pptable_init = pp_tables_initialize,
1724 .pptable_fini = pp_tables_uninitialize,
1725 .pptable_get_number_of_vce_state_table_entries =
1726 get_number_of_vce_state_table_entries,
1727 .pptable_get_vce_state_table_entry =
1728 get_vce_state_table_entry,