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 <linux/module.h>
24 #include <linux/slab.h>
25 #include "linux/delay.h"
28 #include "fiji_smumgr.h"
30 #include "hardwaremanager.h"
31 #include "ppatomctrl.h"
33 #include "cgs_common.h"
34 #include "fiji_dyn_defaults.h"
35 #include "fiji_powertune.h"
37 #include "smu/smu_7_1_3_d.h"
38 #include "smu/smu_7_1_3_sh_mask.h"
39 #include "gmc/gmc_8_1_d.h"
40 #include "gmc/gmc_8_1_sh_mask.h"
41 #include "bif/bif_5_0_d.h"
42 #include "bif/bif_5_0_sh_mask.h"
43 #include "dce/dce_10_0_d.h"
44 #include "dce/dce_10_0_sh_mask.h"
45 #include "pppcielanes.h"
46 #include "fiji_hwmgr.h"
47 #include "tonga_processpptables.h"
48 #include "tonga_pptable.h"
51 #include "amd_pcie_helpers.h"
52 #include "cgs_linux.h"
53 #include "ppinterrupt.h"
55 #include "fiji_clockpowergating.h"
56 #include "fiji_thermal.h"
58 #define VOLTAGE_SCALE 4
59 #define SMC_RAM_END 0x40000
60 #define VDDC_VDDCI_DELTA 300
62 #define MC_SEQ_MISC0_GDDR5_SHIFT 28
63 #define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000
64 #define MC_SEQ_MISC0_GDDR5_VALUE 5
66 #define MC_CG_ARB_FREQ_F0 0x0a /* boot-up default */
67 #define MC_CG_ARB_FREQ_F1 0x0b
68 #define MC_CG_ARB_FREQ_F2 0x0c
69 #define MC_CG_ARB_FREQ_F3 0x0d
72 #define SMC_CG_IND_START 0xc0030000
73 #define SMC_CG_IND_END 0xc0040000 /* First byte after SMC_CG_IND */
75 #define VOLTAGE_SCALE 4
76 #define VOLTAGE_VID_OFFSET_SCALE1 625
77 #define VOLTAGE_VID_OFFSET_SCALE2 100
79 #define VDDC_VDDCI_DELTA 300
81 #define ixSWRST_COMMAND_1 0x1400103
82 #define MC_SEQ_CNTL__CAC_EN_MASK 0x40000000
84 /** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
86 DPM_EVENT_SRC_ANALOG
= 0, /* Internal analog trip point */
87 DPM_EVENT_SRC_EXTERNAL
= 1, /* External (GPIO 17) signal */
88 DPM_EVENT_SRC_DIGITAL
= 2, /* Internal digital trip point (DIG_THERM_DPM) */
89 DPM_EVENT_SRC_ANALOG_OR_EXTERNAL
= 3, /* Internal analog or external */
90 DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL
= 4 /* Internal digital or external */
94 /* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs
95 * not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ]
97 static const uint16_t fiji_clock_stretcher_lookup_table
[2][4] =
98 { {600, 1050, 3, 0}, {600, 1050, 6, 1} };
100 /* [FF, SS] type, [] 4 voltage ranges, and
101 * [Floor Freq, Boundary Freq, VID min , VID max]
103 static const uint32_t fiji_clock_stretcher_ddt_table
[2][4][4] =
104 { { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
105 { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
107 /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%]
108 * (coming from PWR_CKS_CNTL.stretch_amount reg spec)
110 static const uint8_t fiji_clock_stretch_amount_conversion
[2][6] =
111 { {0, 1, 3, 2, 4, 5}, {0, 2, 4, 5, 6, 5} };
113 static const unsigned long PhwFiji_Magic
= (unsigned long)(PHM_VIslands_Magic
);
115 struct fiji_power_state
*cast_phw_fiji_power_state(
116 struct pp_hw_power_state
*hw_ps
)
118 PP_ASSERT_WITH_CODE((PhwFiji_Magic
== hw_ps
->magic
),
119 "Invalid Powerstate Type!",
122 return (struct fiji_power_state
*)hw_ps
;
125 const struct fiji_power_state
*cast_const_phw_fiji_power_state(
126 const struct pp_hw_power_state
*hw_ps
)
128 PP_ASSERT_WITH_CODE((PhwFiji_Magic
== hw_ps
->magic
),
129 "Invalid Powerstate Type!",
132 return (const struct fiji_power_state
*)hw_ps
;
135 static bool fiji_is_dpm_running(struct pp_hwmgr
*hwmgr
)
137 return (1 == PHM_READ_INDIRECT_FIELD(hwmgr
->device
,
138 CGS_IND_REG__SMC
, FEATURE_STATUS
, VOLTAGE_CONTROLLER_ON
))
142 static void fiji_init_dpm_defaults(struct pp_hwmgr
*hwmgr
)
144 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
145 struct fiji_ulv_parm
*ulv
= &data
->ulv
;
147 ulv
->cg_ulv_parameter
= PPFIJI_CGULVPARAMETER_DFLT
;
148 data
->voting_rights_clients0
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT0
;
149 data
->voting_rights_clients1
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT1
;
150 data
->voting_rights_clients2
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT2
;
151 data
->voting_rights_clients3
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT3
;
152 data
->voting_rights_clients4
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT4
;
153 data
->voting_rights_clients5
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT5
;
154 data
->voting_rights_clients6
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT6
;
155 data
->voting_rights_clients7
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT7
;
157 data
->static_screen_threshold_unit
=
158 PPFIJI_STATICSCREENTHRESHOLDUNIT_DFLT
;
159 data
->static_screen_threshold
=
160 PPFIJI_STATICSCREENTHRESHOLD_DFLT
;
162 /* Unset ABM cap as it moved to DAL.
163 * Add PHM_PlatformCaps_NonABMSupportInPPLib
164 * for re-direct ABM related request to DAL
166 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
167 PHM_PlatformCaps_ABM
);
168 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
169 PHM_PlatformCaps_NonABMSupportInPPLib
);
171 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
172 PHM_PlatformCaps_DynamicACTiming
);
174 fiji_initialize_power_tune_defaults(hwmgr
);
176 data
->mclk_stutter_mode_threshold
= 60000;
177 data
->pcie_gen_performance
.max
= PP_PCIEGen1
;
178 data
->pcie_gen_performance
.min
= PP_PCIEGen3
;
179 data
->pcie_gen_power_saving
.max
= PP_PCIEGen1
;
180 data
->pcie_gen_power_saving
.min
= PP_PCIEGen3
;
181 data
->pcie_lane_performance
.max
= 0;
182 data
->pcie_lane_performance
.min
= 16;
183 data
->pcie_lane_power_saving
.max
= 0;
184 data
->pcie_lane_power_saving
.min
= 16;
186 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
187 PHM_PlatformCaps_DynamicUVDState
);
190 static int fiji_get_sclk_for_voltage_evv(struct pp_hwmgr
*hwmgr
,
191 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
192 uint16_t virtual_voltage_id
, int32_t *sclk
)
196 struct phm_ppt_v1_information
*table_info
=
197 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
199 PP_ASSERT_WITH_CODE(lookup_table
->count
!= 0, "Lookup table is empty", return -EINVAL
);
201 /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
202 for (entryId
= 0; entryId
< table_info
->vdd_dep_on_sclk
->count
; entryId
++) {
203 voltageId
= table_info
->vdd_dep_on_sclk
->entries
[entryId
].vddInd
;
204 if (lookup_table
->entries
[voltageId
].us_vdd
== virtual_voltage_id
)
208 PP_ASSERT_WITH_CODE(entryId
< table_info
->vdd_dep_on_sclk
->count
,
209 "Can't find requested voltage id in vdd_dep_on_sclk table!",
213 *sclk
= table_info
->vdd_dep_on_sclk
->entries
[entryId
].clk
;
219 * Get Leakage VDDC based on leakage ID.
221 * @param hwmgr the address of the powerplay hardware manager.
224 static int fiji_get_evv_voltages(struct pp_hwmgr
*hwmgr
)
226 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
229 uint16_t evv_default
= 1150;
232 struct phm_ppt_v1_information
*table_info
=
233 (struct phm_ppt_v1_information
*)hwmgr
->pptable
;
234 struct phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
=
235 table_info
->vdd_dep_on_sclk
;
238 for (i
= 0; i
< FIJI_MAX_LEAKAGE_COUNT
; i
++) {
239 vv_id
= ATOM_VIRTUAL_VOLTAGE_ID0
+ i
;
240 if (!fiji_get_sclk_for_voltage_evv(hwmgr
,
241 table_info
->vddc_lookup_table
, vv_id
, &sclk
)) {
242 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
243 PHM_PlatformCaps_ClockStretcher
)) {
244 for (j
= 1; j
< sclk_table
->count
; j
++) {
245 if (sclk_table
->entries
[j
].clk
== sclk
&&
246 sclk_table
->entries
[j
].cks_enable
== 0) {
253 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
254 PHM_PlatformCaps_EnableDriverEVV
))
255 result
= atomctrl_calculate_voltage_evv_on_sclk(hwmgr
,
256 VOLTAGE_TYPE_VDDC
, sclk
, vv_id
, &vddc
, i
, true);
261 result
= atomctrl_get_voltage_evv_on_sclk(hwmgr
,
262 VOLTAGE_TYPE_VDDC
, sclk
,vv_id
, &vddc
);
264 /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
265 PP_ASSERT_WITH_CODE((vddc
< 2000),
266 "Invalid VDDC value, greater than 2v!", result
= -EINVAL
;);
269 /* 1.15V is the default safe value for Fiji */
272 /* the voltage should not be zero nor equal to leakage ID */
273 if (vddc
!= 0 && vddc
!= vv_id
) {
274 data
->vddc_leakage
.actual_voltage
275 [data
->vddc_leakage
.count
] = vddc
;
276 data
->vddc_leakage
.leakage_id
277 [data
->vddc_leakage
.count
] = vv_id
;
278 data
->vddc_leakage
.count
++;
286 * Change virtual leakage voltage to actual value.
288 * @param hwmgr the address of the powerplay hardware manager.
289 * @param pointer to changing voltage
290 * @param pointer to leakage table
292 static void fiji_patch_with_vdd_leakage(struct pp_hwmgr
*hwmgr
,
293 uint16_t *voltage
, struct fiji_leakage_voltage
*leakage_table
)
297 /* search for leakage voltage ID 0xff01 ~ 0xff08 */
298 for (index
= 0; index
< leakage_table
->count
; index
++) {
299 /* if this voltage matches a leakage voltage ID */
300 /* patch with actual leakage voltage */
301 if (leakage_table
->leakage_id
[index
] == *voltage
) {
302 *voltage
= leakage_table
->actual_voltage
[index
];
307 if (*voltage
> ATOM_VIRTUAL_VOLTAGE_ID0
)
308 printk(KERN_ERR
"Voltage value looks like a Leakage ID but it's not patched \n");
312 * Patch voltage lookup table by EVV leakages.
314 * @param hwmgr the address of the powerplay hardware manager.
315 * @param pointer to voltage lookup table
316 * @param pointer to leakage table
319 static int fiji_patch_lookup_table_with_leakage(struct pp_hwmgr
*hwmgr
,
320 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
321 struct fiji_leakage_voltage
*leakage_table
)
325 for (i
= 0; i
< lookup_table
->count
; i
++)
326 fiji_patch_with_vdd_leakage(hwmgr
,
327 &lookup_table
->entries
[i
].us_vdd
, leakage_table
);
332 static int fiji_patch_clock_voltage_limits_with_vddc_leakage(
333 struct pp_hwmgr
*hwmgr
, struct fiji_leakage_voltage
*leakage_table
,
336 struct phm_ppt_v1_information
*table_info
=
337 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
338 fiji_patch_with_vdd_leakage(hwmgr
, (uint16_t *)vddc
, leakage_table
);
339 hwmgr
->dyn_state
.max_clock_voltage_on_dc
.vddc
=
340 table_info
->max_clock_voltage_on_dc
.vddc
;
344 static int fiji_patch_voltage_dependency_tables_with_lookup_table(
345 struct pp_hwmgr
*hwmgr
)
349 struct phm_ppt_v1_information
*table_info
=
350 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
352 struct phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
=
353 table_info
->vdd_dep_on_sclk
;
354 struct phm_ppt_v1_clock_voltage_dependency_table
*mclk_table
=
355 table_info
->vdd_dep_on_mclk
;
356 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
357 table_info
->mm_dep_table
;
359 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
360 voltageId
= sclk_table
->entries
[entryId
].vddInd
;
361 sclk_table
->entries
[entryId
].vddc
=
362 table_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
365 for (entryId
= 0; entryId
< mclk_table
->count
; ++entryId
) {
366 voltageId
= mclk_table
->entries
[entryId
].vddInd
;
367 mclk_table
->entries
[entryId
].vddc
=
368 table_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
371 for (entryId
= 0; entryId
< mm_table
->count
; ++entryId
) {
372 voltageId
= mm_table
->entries
[entryId
].vddcInd
;
373 mm_table
->entries
[entryId
].vddc
=
374 table_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
381 static int fiji_calc_voltage_dependency_tables(struct pp_hwmgr
*hwmgr
)
383 /* Need to determine if we need calculated voltage. */
387 static int fiji_calc_mm_voltage_dependency_table(struct pp_hwmgr
*hwmgr
)
389 /* Need to determine if we need calculated voltage from mm table. */
393 static int fiji_sort_lookup_table(struct pp_hwmgr
*hwmgr
,
394 struct phm_ppt_v1_voltage_lookup_table
*lookup_table
)
396 uint32_t table_size
, i
, j
;
397 struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record
;
398 table_size
= lookup_table
->count
;
400 PP_ASSERT_WITH_CODE(0 != lookup_table
->count
,
401 "Lookup table is empty", return -EINVAL
);
403 /* Sorting voltages */
404 for (i
= 0; i
< table_size
- 1; i
++) {
405 for (j
= i
+ 1; j
> 0; j
--) {
406 if (lookup_table
->entries
[j
].us_vdd
<
407 lookup_table
->entries
[j
- 1].us_vdd
) {
408 tmp_voltage_lookup_record
= lookup_table
->entries
[j
- 1];
409 lookup_table
->entries
[j
- 1] = lookup_table
->entries
[j
];
410 lookup_table
->entries
[j
] = tmp_voltage_lookup_record
;
418 static int fiji_complete_dependency_tables(struct pp_hwmgr
*hwmgr
)
422 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
423 struct phm_ppt_v1_information
*table_info
=
424 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
426 tmp_result
= fiji_patch_lookup_table_with_leakage(hwmgr
,
427 table_info
->vddc_lookup_table
, &(data
->vddc_leakage
));
431 tmp_result
= fiji_patch_clock_voltage_limits_with_vddc_leakage(hwmgr
,
432 &(data
->vddc_leakage
), &table_info
->max_clock_voltage_on_dc
.vddc
);
436 tmp_result
= fiji_patch_voltage_dependency_tables_with_lookup_table(hwmgr
);
440 tmp_result
= fiji_calc_voltage_dependency_tables(hwmgr
);
444 tmp_result
= fiji_calc_mm_voltage_dependency_table(hwmgr
);
448 tmp_result
= fiji_sort_lookup_table(hwmgr
, table_info
->vddc_lookup_table
);
455 static int fiji_set_private_data_based_on_pptable(struct pp_hwmgr
*hwmgr
)
457 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
458 struct phm_ppt_v1_information
*table_info
=
459 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
461 struct phm_ppt_v1_clock_voltage_dependency_table
*allowed_sclk_vdd_table
=
462 table_info
->vdd_dep_on_sclk
;
463 struct phm_ppt_v1_clock_voltage_dependency_table
*allowed_mclk_vdd_table
=
464 table_info
->vdd_dep_on_mclk
;
466 PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table
!= NULL
,
467 "VDD dependency on SCLK table is missing. \
468 This table is mandatory", return -EINVAL
);
469 PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table
->count
>= 1,
470 "VDD dependency on SCLK table has to have is missing. \
471 This table is mandatory", return -EINVAL
);
473 PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table
!= NULL
,
474 "VDD dependency on MCLK table is missing. \
475 This table is mandatory", return -EINVAL
);
476 PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table
->count
>= 1,
477 "VDD dependency on MCLK table has to have is missing. \
478 This table is mandatory", return -EINVAL
);
480 data
->min_vddc_in_pptable
= (uint16_t)allowed_sclk_vdd_table
->entries
[0].vddc
;
481 data
->max_vddc_in_pptable
= (uint16_t)allowed_sclk_vdd_table
->
482 entries
[allowed_sclk_vdd_table
->count
- 1].vddc
;
484 table_info
->max_clock_voltage_on_ac
.sclk
=
485 allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].clk
;
486 table_info
->max_clock_voltage_on_ac
.mclk
=
487 allowed_mclk_vdd_table
->entries
[allowed_mclk_vdd_table
->count
- 1].clk
;
488 table_info
->max_clock_voltage_on_ac
.vddc
=
489 allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].vddc
;
490 table_info
->max_clock_voltage_on_ac
.vddci
=
491 allowed_mclk_vdd_table
->entries
[allowed_mclk_vdd_table
->count
- 1].vddci
;
493 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.sclk
=
494 table_info
->max_clock_voltage_on_ac
.sclk
;
495 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.mclk
=
496 table_info
->max_clock_voltage_on_ac
.mclk
;
497 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.vddc
=
498 table_info
->max_clock_voltage_on_ac
.vddc
;
499 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.vddci
=
500 table_info
->max_clock_voltage_on_ac
.vddci
;
505 static uint16_t fiji_get_current_pcie_speed(struct pp_hwmgr
*hwmgr
)
507 uint32_t speedCntl
= 0;
509 /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
510 speedCntl
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__PCIE
,
511 ixPCIE_LC_SPEED_CNTL
);
512 return((uint16_t)PHM_GET_FIELD(speedCntl
,
513 PCIE_LC_SPEED_CNTL
, LC_CURRENT_DATA_RATE
));
516 static int fiji_get_current_pcie_lane_number(struct pp_hwmgr
*hwmgr
)
520 /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
521 link_width
= PHM_READ_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__PCIE
,
522 PCIE_LC_LINK_WIDTH_CNTL
, LC_LINK_WIDTH_RD
);
524 PP_ASSERT_WITH_CODE((7 >= link_width
),
525 "Invalid PCIe lane width!", return 0);
527 return decode_pcie_lane_width(link_width
);
530 /** Patch the Boot State to match VBIOS boot clocks and voltage.
532 * @param hwmgr Pointer to the hardware manager.
533 * @param pPowerState The address of the PowerState instance being created.
536 static int fiji_patch_boot_state(struct pp_hwmgr
*hwmgr
,
537 struct pp_hw_power_state
*hw_ps
)
539 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
540 struct fiji_power_state
*ps
= (struct fiji_power_state
*)hw_ps
;
541 ATOM_FIRMWARE_INFO_V2_2
*fw_info
;
544 int index
= GetIndexIntoMasterTable(DATA
, FirmwareInfo
);
546 /* First retrieve the Boot clocks and VDDC from the firmware info table.
547 * We assume here that fw_info is unchanged if this call fails.
549 fw_info
= (ATOM_FIRMWARE_INFO_V2_2
*)cgs_atom_get_data_table(
550 hwmgr
->device
, index
,
551 &size
, &frev
, &crev
);
553 /* During a test, there is no firmware info table. */
556 /* Patch the state. */
557 data
->vbios_boot_state
.sclk_bootup_value
=
558 le32_to_cpu(fw_info
->ulDefaultEngineClock
);
559 data
->vbios_boot_state
.mclk_bootup_value
=
560 le32_to_cpu(fw_info
->ulDefaultMemoryClock
);
561 data
->vbios_boot_state
.mvdd_bootup_value
=
562 le16_to_cpu(fw_info
->usBootUpMVDDCVoltage
);
563 data
->vbios_boot_state
.vddc_bootup_value
=
564 le16_to_cpu(fw_info
->usBootUpVDDCVoltage
);
565 data
->vbios_boot_state
.vddci_bootup_value
=
566 le16_to_cpu(fw_info
->usBootUpVDDCIVoltage
);
567 data
->vbios_boot_state
.pcie_gen_bootup_value
=
568 fiji_get_current_pcie_speed(hwmgr
);
569 data
->vbios_boot_state
.pcie_lane_bootup_value
=
570 (uint16_t)fiji_get_current_pcie_lane_number(hwmgr
);
572 /* set boot power state */
573 ps
->performance_levels
[0].memory_clock
= data
->vbios_boot_state
.mclk_bootup_value
;
574 ps
->performance_levels
[0].engine_clock
= data
->vbios_boot_state
.sclk_bootup_value
;
575 ps
->performance_levels
[0].pcie_gen
= data
->vbios_boot_state
.pcie_gen_bootup_value
;
576 ps
->performance_levels
[0].pcie_lane
= data
->vbios_boot_state
.pcie_lane_bootup_value
;
581 static int fiji_hwmgr_backend_fini(struct pp_hwmgr
*hwmgr
)
583 return phm_hwmgr_backend_fini(hwmgr
);
586 static int fiji_hwmgr_backend_init(struct pp_hwmgr
*hwmgr
)
588 struct fiji_hwmgr
*data
;
590 struct phm_ppt_v1_information
*table_info
=
591 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
595 data
= kzalloc(sizeof(struct fiji_hwmgr
), GFP_KERNEL
);
599 hwmgr
->backend
= data
;
601 data
->dll_default_on
= false;
602 data
->sram_end
= SMC_RAM_END
;
604 for (i
= 0; i
< SMU73_MAX_LEVELS_GRAPHICS
; i
++)
605 data
->activity_target
[i
] = FIJI_AT_DFLT
;
607 data
->vddc_vddci_delta
= VDDC_VDDCI_DELTA
;
609 data
->mclk_activity_target
= PPFIJI_MCLK_TARGETACTIVITY_DFLT
;
610 data
->mclk_dpm0_activity_target
= 0xa;
612 data
->sclk_dpm_key_disabled
= 0;
613 data
->mclk_dpm_key_disabled
= 0;
614 data
->pcie_dpm_key_disabled
= 0;
616 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
617 PHM_PlatformCaps_UnTabledHardwareInterface
);
618 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
619 PHM_PlatformCaps_TablelessHardwareInterface
);
621 data
->gpio_debug
= 0;
623 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
624 PHM_PlatformCaps_DynamicPatchPowerState
);
626 /* need to set voltage control types before EVV patching */
627 data
->voltage_control
= FIJI_VOLTAGE_CONTROL_NONE
;
628 data
->vddci_control
= FIJI_VOLTAGE_CONTROL_NONE
;
629 data
->mvdd_control
= FIJI_VOLTAGE_CONTROL_NONE
;
631 data
->force_pcie_gen
= PP_PCIEGenInvalid
;
633 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
634 VOLTAGE_TYPE_VDDC
, VOLTAGE_OBJ_SVID2
))
635 data
->voltage_control
= FIJI_VOLTAGE_CONTROL_BY_SVID2
;
637 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
638 PHM_PlatformCaps_EnableMVDDControl
))
639 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
640 VOLTAGE_TYPE_MVDDC
, VOLTAGE_OBJ_GPIO_LUT
))
641 data
->mvdd_control
= FIJI_VOLTAGE_CONTROL_BY_GPIO
;
643 if (data
->mvdd_control
== FIJI_VOLTAGE_CONTROL_NONE
)
644 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
645 PHM_PlatformCaps_EnableMVDDControl
);
647 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
648 PHM_PlatformCaps_ControlVDDCI
)) {
649 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
650 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_GPIO_LUT
))
651 data
->vddci_control
= FIJI_VOLTAGE_CONTROL_BY_GPIO
;
652 else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
653 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_SVID2
))
654 data
->vddci_control
= FIJI_VOLTAGE_CONTROL_BY_SVID2
;
657 if (data
->vddci_control
== FIJI_VOLTAGE_CONTROL_NONE
)
658 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
659 PHM_PlatformCaps_ControlVDDCI
);
661 if (table_info
&& table_info
->cac_dtp_table
->usClockStretchAmount
)
662 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
663 PHM_PlatformCaps_ClockStretcher
);
665 fiji_init_dpm_defaults(hwmgr
);
667 /* Get leakage voltage based on leakage ID. */
668 fiji_get_evv_voltages(hwmgr
);
670 /* Patch our voltage dependency table with actual leakage voltage
671 * We need to perform leakage translation before it's used by other functions
673 fiji_complete_dependency_tables(hwmgr
);
675 /* Parse pptable data read from VBIOS */
676 fiji_set_private_data_based_on_pptable(hwmgr
);
679 data
->ulv
.ulv_supported
= true; /* ULV feature is enabled by default */
681 /* Initalize Dynamic State Adjustment Rule Settings */
682 result
= tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr
);
685 data
->uvd_enabled
= false;
686 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
687 PHM_PlatformCaps_EnableSMU7ThermalManagement
);
688 data
->vddc_phase_shed_control
= false;
691 stay_in_boot
= phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
692 PHM_PlatformCaps_StayInBootState
);
695 struct cgs_system_info sys_info
= {0};
697 data
->is_tlu_enabled
= false;
698 hwmgr
->platform_descriptor
.hardwareActivityPerformanceLevels
=
699 FIJI_MAX_HARDWARE_POWERLEVELS
;
700 hwmgr
->platform_descriptor
.hardwarePerformanceLevels
= 2;
701 hwmgr
->platform_descriptor
.minimumClocksReductionPercentage
= 50;
703 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
704 PHM_PlatformCaps_FanSpeedInTableIsRPM
);
706 if (table_info
->cac_dtp_table
->usDefaultTargetOperatingTemp
&&
707 hwmgr
->thermal_controller
.
708 advanceFanControlParameters
.ucFanControlMode
) {
709 hwmgr
->thermal_controller
.advanceFanControlParameters
.usMaxFanPWM
=
710 hwmgr
->thermal_controller
.advanceFanControlParameters
.usDefaultMaxFanPWM
;
711 hwmgr
->thermal_controller
.advanceFanControlParameters
.usMaxFanRPM
=
712 hwmgr
->thermal_controller
.advanceFanControlParameters
.usDefaultMaxFanRPM
;
713 hwmgr
->dyn_state
.cac_dtp_table
->usOperatingTempMinLimit
=
714 table_info
->cac_dtp_table
->usOperatingTempMinLimit
;
715 hwmgr
->dyn_state
.cac_dtp_table
->usOperatingTempMaxLimit
=
716 table_info
->cac_dtp_table
->usOperatingTempMaxLimit
;
717 hwmgr
->dyn_state
.cac_dtp_table
->usDefaultTargetOperatingTemp
=
718 table_info
->cac_dtp_table
->usDefaultTargetOperatingTemp
;
719 hwmgr
->dyn_state
.cac_dtp_table
->usOperatingTempStep
=
720 table_info
->cac_dtp_table
->usOperatingTempStep
;
721 hwmgr
->dyn_state
.cac_dtp_table
->usTargetOperatingTemp
=
722 table_info
->cac_dtp_table
->usTargetOperatingTemp
;
724 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
725 PHM_PlatformCaps_ODFuzzyFanControlSupport
);
728 sys_info
.size
= sizeof(struct cgs_system_info
);
729 sys_info
.info_id
= CGS_SYSTEM_INFO_PCIE_GEN_INFO
;
730 result
= cgs_query_system_info(hwmgr
->device
, &sys_info
);
732 data
->pcie_gen_cap
= AMDGPU_DEFAULT_PCIE_GEN_MASK
;
734 data
->pcie_gen_cap
= (uint32_t)sys_info
.value
;
735 if (data
->pcie_gen_cap
& CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3
)
736 data
->pcie_spc_cap
= 20;
737 sys_info
.size
= sizeof(struct cgs_system_info
);
738 sys_info
.info_id
= CGS_SYSTEM_INFO_PCIE_MLW
;
739 result
= cgs_query_system_info(hwmgr
->device
, &sys_info
);
741 data
->pcie_lane_cap
= AMDGPU_DEFAULT_PCIE_MLW_MASK
;
743 data
->pcie_lane_cap
= (uint32_t)sys_info
.value
;
745 /* Ignore return value in here, we are cleaning up a mess. */
746 fiji_hwmgr_backend_fini(hwmgr
);
753 * Read clock related registers.
755 * @param hwmgr the address of the powerplay hardware manager.
758 static int fiji_read_clock_registers(struct pp_hwmgr
*hwmgr
)
760 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
762 data
->clock_registers
.vCG_SPLL_FUNC_CNTL
=
763 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
764 ixCG_SPLL_FUNC_CNTL
);
765 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
=
766 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
767 ixCG_SPLL_FUNC_CNTL_2
);
768 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
=
769 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
770 ixCG_SPLL_FUNC_CNTL_3
);
771 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
=
772 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
773 ixCG_SPLL_FUNC_CNTL_4
);
774 data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
=
775 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
776 ixCG_SPLL_SPREAD_SPECTRUM
);
777 data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
=
778 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
779 ixCG_SPLL_SPREAD_SPECTRUM_2
);
785 * Find out if memory is GDDR5.
787 * @param hwmgr the address of the powerplay hardware manager.
790 static int fiji_get_memory_type(struct pp_hwmgr
*hwmgr
)
792 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
795 temp
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC0
);
797 data
->is_memory_gddr5
= (MC_SEQ_MISC0_GDDR5_VALUE
==
798 ((temp
& MC_SEQ_MISC0_GDDR5_MASK
) >>
799 MC_SEQ_MISC0_GDDR5_SHIFT
));
805 * Enables Dynamic Power Management by SMC
807 * @param hwmgr the address of the powerplay hardware manager.
810 static int fiji_enable_acpi_power_management(struct pp_hwmgr
*hwmgr
)
812 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
813 GENERAL_PWRMGT
, STATIC_PM_EN
, 1);
819 * Initialize PowerGating States for different engines
821 * @param hwmgr the address of the powerplay hardware manager.
824 static int fiji_init_power_gate_state(struct pp_hwmgr
*hwmgr
)
826 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
828 data
->uvd_power_gated
= false;
829 data
->vce_power_gated
= false;
830 data
->samu_power_gated
= false;
831 data
->acp_power_gated
= false;
832 data
->pg_acp_init
= true;
837 static int fiji_init_sclk_threshold(struct pp_hwmgr
*hwmgr
)
839 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
840 data
->low_sclk_interrupt_threshold
= 0;
845 static int fiji_setup_asic_task(struct pp_hwmgr
*hwmgr
)
847 int tmp_result
, result
= 0;
849 tmp_result
= fiji_read_clock_registers(hwmgr
);
850 PP_ASSERT_WITH_CODE((0 == tmp_result
),
851 "Failed to read clock registers!", result
= tmp_result
);
853 tmp_result
= fiji_get_memory_type(hwmgr
);
854 PP_ASSERT_WITH_CODE((0 == tmp_result
),
855 "Failed to get memory type!", result
= tmp_result
);
857 tmp_result
= fiji_enable_acpi_power_management(hwmgr
);
858 PP_ASSERT_WITH_CODE((0 == tmp_result
),
859 "Failed to enable ACPI power management!", result
= tmp_result
);
861 tmp_result
= fiji_init_power_gate_state(hwmgr
);
862 PP_ASSERT_WITH_CODE((0 == tmp_result
),
863 "Failed to init power gate state!", result
= tmp_result
);
865 tmp_result
= tonga_get_mc_microcode_version(hwmgr
);
866 PP_ASSERT_WITH_CODE((0 == tmp_result
),
867 "Failed to get MC microcode version!", result
= tmp_result
);
869 tmp_result
= fiji_init_sclk_threshold(hwmgr
);
870 PP_ASSERT_WITH_CODE((0 == tmp_result
),
871 "Failed to init sclk threshold!", result
= tmp_result
);
877 * Checks if we want to support voltage control
879 * @param hwmgr the address of the powerplay hardware manager.
881 static bool fiji_voltage_control(const struct pp_hwmgr
*hwmgr
)
883 const struct fiji_hwmgr
*data
=
884 (const struct fiji_hwmgr
*)(hwmgr
->backend
);
886 return (FIJI_VOLTAGE_CONTROL_NONE
!= data
->voltage_control
);
890 * Enable voltage control
892 * @param hwmgr the address of the powerplay hardware manager.
895 static int fiji_enable_voltage_control(struct pp_hwmgr
*hwmgr
)
897 /* enable voltage control */
898 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
899 GENERAL_PWRMGT
, VOLT_PWRMGT_EN
, 1);
905 * Remove repeated voltage values and create table with unique values.
907 * @param hwmgr the address of the powerplay hardware manager.
908 * @param vol_table the pointer to changing voltage table
909 * @return 0 in success
912 static int fiji_trim_voltage_table(struct pp_hwmgr
*hwmgr
,
913 struct pp_atomctrl_voltage_table
*vol_table
)
918 struct pp_atomctrl_voltage_table
*table
;
920 PP_ASSERT_WITH_CODE((NULL
!= vol_table
),
921 "Voltage Table empty.", return -EINVAL
);
922 table
= kzalloc(sizeof(struct pp_atomctrl_voltage_table
),
928 table
->mask_low
= vol_table
->mask_low
;
929 table
->phase_delay
= vol_table
->phase_delay
;
931 for (i
= 0; i
< vol_table
->count
; i
++) {
932 vvalue
= vol_table
->entries
[i
].value
;
935 for (j
= 0; j
< table
->count
; j
++) {
936 if (vvalue
== table
->entries
[j
].value
) {
943 table
->entries
[table
->count
].value
= vvalue
;
944 table
->entries
[table
->count
].smio_low
=
945 vol_table
->entries
[i
].smio_low
;
950 memcpy(vol_table
, table
, sizeof(struct pp_atomctrl_voltage_table
));
956 static int fiji_get_svi2_mvdd_voltage_table(struct pp_hwmgr
*hwmgr
,
957 phm_ppt_v1_clock_voltage_dependency_table
*dep_table
)
961 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
962 struct pp_atomctrl_voltage_table
*vol_table
= &(data
->mvdd_voltage_table
);
964 PP_ASSERT_WITH_CODE((0 != dep_table
->count
),
965 "Voltage Dependency Table empty.", return -EINVAL
);
967 vol_table
->mask_low
= 0;
968 vol_table
->phase_delay
= 0;
969 vol_table
->count
= dep_table
->count
;
971 for (i
= 0; i
< dep_table
->count
; i
++) {
972 vol_table
->entries
[i
].value
= dep_table
->entries
[i
].mvdd
;
973 vol_table
->entries
[i
].smio_low
= 0;
976 result
= fiji_trim_voltage_table(hwmgr
, vol_table
);
977 PP_ASSERT_WITH_CODE((0 == result
),
978 "Failed to trim MVDD table.", return result
);
983 static int fiji_get_svi2_vddci_voltage_table(struct pp_hwmgr
*hwmgr
,
984 phm_ppt_v1_clock_voltage_dependency_table
*dep_table
)
988 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
989 struct pp_atomctrl_voltage_table
*vol_table
= &(data
->vddci_voltage_table
);
991 PP_ASSERT_WITH_CODE((0 != dep_table
->count
),
992 "Voltage Dependency Table empty.", return -EINVAL
);
994 vol_table
->mask_low
= 0;
995 vol_table
->phase_delay
= 0;
996 vol_table
->count
= dep_table
->count
;
998 for (i
= 0; i
< dep_table
->count
; i
++) {
999 vol_table
->entries
[i
].value
= dep_table
->entries
[i
].vddci
;
1000 vol_table
->entries
[i
].smio_low
= 0;
1003 result
= fiji_trim_voltage_table(hwmgr
, vol_table
);
1004 PP_ASSERT_WITH_CODE((0 == result
),
1005 "Failed to trim VDDCI table.", return result
);
1010 static int fiji_get_svi2_vdd_voltage_table(struct pp_hwmgr
*hwmgr
,
1011 phm_ppt_v1_voltage_lookup_table
*lookup_table
)
1014 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1015 struct pp_atomctrl_voltage_table
*vol_table
= &(data
->vddc_voltage_table
);
1017 PP_ASSERT_WITH_CODE((0 != lookup_table
->count
),
1018 "Voltage Lookup Table empty.", return -EINVAL
);
1020 vol_table
->mask_low
= 0;
1021 vol_table
->phase_delay
= 0;
1023 vol_table
->count
= lookup_table
->count
;
1025 for (i
= 0; i
< vol_table
->count
; i
++) {
1026 vol_table
->entries
[i
].value
= lookup_table
->entries
[i
].us_vdd
;
1027 vol_table
->entries
[i
].smio_low
= 0;
1033 /* ---- Voltage Tables ----
1034 * If the voltage table would be bigger than
1035 * what will fit into the state table on
1036 * the SMC keep only the higher entries.
1038 static void fiji_trim_voltage_table_to_fit_state_table(struct pp_hwmgr
*hwmgr
,
1039 uint32_t max_vol_steps
, struct pp_atomctrl_voltage_table
*vol_table
)
1041 unsigned int i
, diff
;
1043 if (vol_table
->count
<= max_vol_steps
)
1046 diff
= vol_table
->count
- max_vol_steps
;
1048 for (i
= 0; i
< max_vol_steps
; i
++)
1049 vol_table
->entries
[i
] = vol_table
->entries
[i
+ diff
];
1051 vol_table
->count
= max_vol_steps
;
1057 * Create Voltage Tables.
1059 * @param hwmgr the address of the powerplay hardware manager.
1062 static int fiji_construct_voltage_tables(struct pp_hwmgr
*hwmgr
)
1064 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1065 struct phm_ppt_v1_information
*table_info
=
1066 (struct phm_ppt_v1_information
*)hwmgr
->pptable
;
1069 if (FIJI_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1070 result
= atomctrl_get_voltage_table_v3(hwmgr
,
1071 VOLTAGE_TYPE_MVDDC
, VOLTAGE_OBJ_GPIO_LUT
,
1072 &(data
->mvdd_voltage_table
));
1073 PP_ASSERT_WITH_CODE((0 == result
),
1074 "Failed to retrieve MVDD table.",
1076 } else if (FIJI_VOLTAGE_CONTROL_BY_SVID2
== data
->mvdd_control
) {
1077 result
= fiji_get_svi2_mvdd_voltage_table(hwmgr
,
1078 table_info
->vdd_dep_on_mclk
);
1079 PP_ASSERT_WITH_CODE((0 == result
),
1080 "Failed to retrieve SVI2 MVDD table from dependancy table.",
1084 if (FIJI_VOLTAGE_CONTROL_BY_GPIO
== data
->vddci_control
) {
1085 result
= atomctrl_get_voltage_table_v3(hwmgr
,
1086 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_GPIO_LUT
,
1087 &(data
->vddci_voltage_table
));
1088 PP_ASSERT_WITH_CODE((0 == result
),
1089 "Failed to retrieve VDDCI table.",
1091 } else if (FIJI_VOLTAGE_CONTROL_BY_SVID2
== data
->vddci_control
) {
1092 result
= fiji_get_svi2_vddci_voltage_table(hwmgr
,
1093 table_info
->vdd_dep_on_mclk
);
1094 PP_ASSERT_WITH_CODE((0 == result
),
1095 "Failed to retrieve SVI2 VDDCI table from dependancy table.",
1099 if(FIJI_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1100 result
= fiji_get_svi2_vdd_voltage_table(hwmgr
,
1101 table_info
->vddc_lookup_table
);
1102 PP_ASSERT_WITH_CODE((0 == result
),
1103 "Failed to retrieve SVI2 VDDC table from lookup table.",
1107 PP_ASSERT_WITH_CODE(
1108 (data
->vddc_voltage_table
.count
<= (SMU73_MAX_LEVELS_VDDC
)),
1109 "Too many voltage values for VDDC. Trimming to fit state table.",
1110 fiji_trim_voltage_table_to_fit_state_table(hwmgr
,
1111 SMU73_MAX_LEVELS_VDDC
, &(data
->vddc_voltage_table
)));
1113 PP_ASSERT_WITH_CODE(
1114 (data
->vddci_voltage_table
.count
<= (SMU73_MAX_LEVELS_VDDCI
)),
1115 "Too many voltage values for VDDCI. Trimming to fit state table.",
1116 fiji_trim_voltage_table_to_fit_state_table(hwmgr
,
1117 SMU73_MAX_LEVELS_VDDCI
, &(data
->vddci_voltage_table
)));
1119 PP_ASSERT_WITH_CODE(
1120 (data
->mvdd_voltage_table
.count
<= (SMU73_MAX_LEVELS_MVDD
)),
1121 "Too many voltage values for MVDD. Trimming to fit state table.",
1122 fiji_trim_voltage_table_to_fit_state_table(hwmgr
,
1123 SMU73_MAX_LEVELS_MVDD
, &(data
->mvdd_voltage_table
)));
1128 static int fiji_initialize_mc_reg_table(struct pp_hwmgr
*hwmgr
)
1130 /* Program additional LP registers
1131 * that are no longer programmed by VBIOS
1133 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING_LP
,
1134 cgs_read_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING
));
1135 cgs_write_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING_LP
,
1136 cgs_read_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING
));
1137 cgs_write_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2_LP
,
1138 cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2
));
1139 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1_LP
,
1140 cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1
));
1141 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0_LP
,
1142 cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0
));
1143 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1_LP
,
1144 cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1
));
1145 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING_LP
,
1146 cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING
));
1152 * Programs static screed detection parameters
1154 * @param hwmgr the address of the powerplay hardware manager.
1157 static int fiji_program_static_screen_threshold_parameters(
1158 struct pp_hwmgr
*hwmgr
)
1160 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1162 /* Set static screen threshold unit */
1163 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
1164 CG_STATIC_SCREEN_PARAMETER
, STATIC_SCREEN_THRESHOLD_UNIT
,
1165 data
->static_screen_threshold_unit
);
1166 /* Set static screen threshold */
1167 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
1168 CG_STATIC_SCREEN_PARAMETER
, STATIC_SCREEN_THRESHOLD
,
1169 data
->static_screen_threshold
);
1175 * Setup display gap for glitch free memory clock switching.
1177 * @param hwmgr the address of the powerplay hardware manager.
1180 static int fiji_enable_display_gap(struct pp_hwmgr
*hwmgr
)
1182 uint32_t displayGap
=
1183 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1184 ixCG_DISPLAY_GAP_CNTL
);
1186 displayGap
= PHM_SET_FIELD(displayGap
, CG_DISPLAY_GAP_CNTL
,
1187 DISP_GAP
, DISPLAY_GAP_IGNORE
);
1189 displayGap
= PHM_SET_FIELD(displayGap
, CG_DISPLAY_GAP_CNTL
,
1190 DISP_GAP_MCHG
, DISPLAY_GAP_VBLANK
);
1192 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1193 ixCG_DISPLAY_GAP_CNTL
, displayGap
);
1199 * Programs activity state transition voting clients
1201 * @param hwmgr the address of the powerplay hardware manager.
1204 static int fiji_program_voting_clients(struct pp_hwmgr
*hwmgr
)
1206 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1208 /* Clear reset for voting clients before enabling DPM */
1209 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
1210 SCLK_PWRMGT_CNTL
, RESET_SCLK_CNT
, 0);
1211 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
1212 SCLK_PWRMGT_CNTL
, RESET_BUSY_CNT
, 0);
1214 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1215 ixCG_FREQ_TRAN_VOTING_0
, data
->voting_rights_clients0
);
1216 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1217 ixCG_FREQ_TRAN_VOTING_1
, data
->voting_rights_clients1
);
1218 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1219 ixCG_FREQ_TRAN_VOTING_2
, data
->voting_rights_clients2
);
1220 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1221 ixCG_FREQ_TRAN_VOTING_3
, data
->voting_rights_clients3
);
1222 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1223 ixCG_FREQ_TRAN_VOTING_4
, data
->voting_rights_clients4
);
1224 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1225 ixCG_FREQ_TRAN_VOTING_5
, data
->voting_rights_clients5
);
1226 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1227 ixCG_FREQ_TRAN_VOTING_6
, data
->voting_rights_clients6
);
1228 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1229 ixCG_FREQ_TRAN_VOTING_7
, data
->voting_rights_clients7
);
1234 static int fiji_clear_voting_clients(struct pp_hwmgr
*hwmgr
)
1236 /* Reset voting clients before disabling DPM */
1237 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
1238 SCLK_PWRMGT_CNTL
, RESET_SCLK_CNT
, 1);
1239 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
1240 SCLK_PWRMGT_CNTL
, RESET_BUSY_CNT
, 1);
1242 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1243 ixCG_FREQ_TRAN_VOTING_0
, 0);
1244 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1245 ixCG_FREQ_TRAN_VOTING_1
, 0);
1246 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1247 ixCG_FREQ_TRAN_VOTING_2
, 0);
1248 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1249 ixCG_FREQ_TRAN_VOTING_3
, 0);
1250 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1251 ixCG_FREQ_TRAN_VOTING_4
, 0);
1252 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1253 ixCG_FREQ_TRAN_VOTING_5
, 0);
1254 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1255 ixCG_FREQ_TRAN_VOTING_6
, 0);
1256 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1257 ixCG_FREQ_TRAN_VOTING_7
, 0);
1263 * Get the location of various tables inside the FW image.
1265 * @param hwmgr the address of the powerplay hardware manager.
1268 static int fiji_process_firmware_header(struct pp_hwmgr
*hwmgr
)
1270 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1271 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
1276 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
1277 SMU7_FIRMWARE_HEADER_LOCATION
+
1278 offsetof(SMU73_Firmware_Header
, DpmTable
),
1279 &tmp
, data
->sram_end
);
1282 data
->dpm_table_start
= tmp
;
1284 error
|= (0 != result
);
1286 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
1287 SMU7_FIRMWARE_HEADER_LOCATION
+
1288 offsetof(SMU73_Firmware_Header
, SoftRegisters
),
1289 &tmp
, data
->sram_end
);
1292 data
->soft_regs_start
= tmp
;
1293 smu_data
->soft_regs_start
= tmp
;
1296 error
|= (0 != result
);
1298 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
1299 SMU7_FIRMWARE_HEADER_LOCATION
+
1300 offsetof(SMU73_Firmware_Header
, mcRegisterTable
),
1301 &tmp
, data
->sram_end
);
1304 data
->mc_reg_table_start
= tmp
;
1306 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
1307 SMU7_FIRMWARE_HEADER_LOCATION
+
1308 offsetof(SMU73_Firmware_Header
, FanTable
),
1309 &tmp
, data
->sram_end
);
1312 data
->fan_table_start
= tmp
;
1314 error
|= (0 != result
);
1316 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
1317 SMU7_FIRMWARE_HEADER_LOCATION
+
1318 offsetof(SMU73_Firmware_Header
, mcArbDramTimingTable
),
1319 &tmp
, data
->sram_end
);
1322 data
->arb_table_start
= tmp
;
1324 error
|= (0 != result
);
1326 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
1327 SMU7_FIRMWARE_HEADER_LOCATION
+
1328 offsetof(SMU73_Firmware_Header
, Version
),
1329 &tmp
, data
->sram_end
);
1332 hwmgr
->microcode_version_info
.SMC
= tmp
;
1334 error
|= (0 != result
);
1336 return error
? -1 : 0;
1339 /* Copy one arb setting to another and then switch the active set.
1340 * arb_src and arb_dest is one of the MC_CG_ARB_FREQ_Fx constants.
1342 static int fiji_copy_and_switch_arb_sets(struct pp_hwmgr
*hwmgr
,
1343 uint32_t arb_src
, uint32_t arb_dest
)
1345 uint32_t mc_arb_dram_timing
;
1346 uint32_t mc_arb_dram_timing2
;
1347 uint32_t burst_time
;
1348 uint32_t mc_cg_config
;
1351 case MC_CG_ARB_FREQ_F0
:
1352 mc_arb_dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
1353 mc_arb_dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
1354 burst_time
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
);
1356 case MC_CG_ARB_FREQ_F1
:
1357 mc_arb_dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING_1
);
1358 mc_arb_dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2_1
);
1359 burst_time
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE1
);
1366 case MC_CG_ARB_FREQ_F0
:
1367 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
, mc_arb_dram_timing
);
1368 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
, mc_arb_dram_timing2
);
1369 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
, burst_time
);
1371 case MC_CG_ARB_FREQ_F1
:
1372 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING_1
, mc_arb_dram_timing
);
1373 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2_1
, mc_arb_dram_timing2
);
1374 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE1
, burst_time
);
1380 mc_cg_config
= cgs_read_register(hwmgr
->device
, mmMC_CG_CONFIG
);
1381 mc_cg_config
|= 0x0000000F;
1382 cgs_write_register(hwmgr
->device
, mmMC_CG_CONFIG
, mc_cg_config
);
1383 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_CG
, CG_ARB_REQ
, arb_dest
);
1389 * Call SMC to reset S0/S1 to S1 and Reset SMIO to initial value
1391 * @param hwmgr the address of the powerplay hardware manager.
1392 * @return if success then 0;
1394 static int fiji_reset_to_default(struct pp_hwmgr
*hwmgr
)
1396 return smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_ResetToDefaults
);
1400 * Initial switch from ARB F0->F1
1402 * @param hwmgr the address of the powerplay hardware manager.
1404 * This function is to be called from the SetPowerState table.
1406 static int fiji_initial_switch_from_arbf0_to_f1(struct pp_hwmgr
*hwmgr
)
1408 return fiji_copy_and_switch_arb_sets(hwmgr
,
1409 MC_CG_ARB_FREQ_F0
, MC_CG_ARB_FREQ_F1
);
1412 static int fiji_force_switch_to_arbf0(struct pp_hwmgr
*hwmgr
)
1416 tmp
= (cgs_read_ind_register(hwmgr
->device
,
1417 CGS_IND_REG__SMC
, ixSMC_SCRATCH9
) &
1420 if (tmp
== MC_CG_ARB_FREQ_F0
)
1423 return fiji_copy_and_switch_arb_sets(hwmgr
,
1424 tmp
, MC_CG_ARB_FREQ_F0
);
1427 static int fiji_reset_single_dpm_table(struct pp_hwmgr
*hwmgr
,
1428 struct fiji_single_dpm_table
*dpm_table
, uint32_t count
)
1431 PP_ASSERT_WITH_CODE(count
<= MAX_REGULAR_DPM_NUMBER
,
1432 "Fatal error, can not set up single DPM table entries "
1433 "to exceed max number!",);
1435 dpm_table
->count
= count
;
1436 for (i
= 0; i
< MAX_REGULAR_DPM_NUMBER
; i
++)
1437 dpm_table
->dpm_levels
[i
].enabled
= false;
1442 static void fiji_setup_pcie_table_entry(
1443 struct fiji_single_dpm_table
*dpm_table
,
1444 uint32_t index
, uint32_t pcie_gen
,
1445 uint32_t pcie_lanes
)
1447 dpm_table
->dpm_levels
[index
].value
= pcie_gen
;
1448 dpm_table
->dpm_levels
[index
].param1
= pcie_lanes
;
1449 dpm_table
->dpm_levels
[index
].enabled
= true;
1452 static int fiji_setup_default_pcie_table(struct pp_hwmgr
*hwmgr
)
1454 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1455 struct phm_ppt_v1_information
*table_info
=
1456 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1457 struct phm_ppt_v1_pcie_table
*pcie_table
= table_info
->pcie_table
;
1458 uint32_t i
, max_entry
;
1460 PP_ASSERT_WITH_CODE((data
->use_pcie_performance_levels
||
1461 data
->use_pcie_power_saving_levels
), "No pcie performance levels!",
1464 if (data
->use_pcie_performance_levels
&&
1465 !data
->use_pcie_power_saving_levels
) {
1466 data
->pcie_gen_power_saving
= data
->pcie_gen_performance
;
1467 data
->pcie_lane_power_saving
= data
->pcie_lane_performance
;
1468 } else if (!data
->use_pcie_performance_levels
&&
1469 data
->use_pcie_power_saving_levels
) {
1470 data
->pcie_gen_performance
= data
->pcie_gen_power_saving
;
1471 data
->pcie_lane_performance
= data
->pcie_lane_power_saving
;
1474 fiji_reset_single_dpm_table(hwmgr
,
1475 &data
->dpm_table
.pcie_speed_table
, SMU73_MAX_LEVELS_LINK
);
1477 if (pcie_table
!= NULL
) {
1478 /* max_entry is used to make sure we reserve one PCIE level
1479 * for boot level (fix for A+A PSPP issue).
1480 * If PCIE table from PPTable have ULV entry + 8 entries,
1481 * then ignore the last entry.*/
1482 max_entry
= (SMU73_MAX_LEVELS_LINK
< pcie_table
->count
) ?
1483 SMU73_MAX_LEVELS_LINK
: pcie_table
->count
;
1484 for (i
= 1; i
< max_entry
; i
++) {
1485 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, i
- 1,
1486 get_pcie_gen_support(data
->pcie_gen_cap
,
1487 pcie_table
->entries
[i
].gen_speed
),
1488 get_pcie_lane_support(data
->pcie_lane_cap
,
1489 pcie_table
->entries
[i
].lane_width
));
1491 data
->dpm_table
.pcie_speed_table
.count
= max_entry
- 1;
1493 /* Hardcode Pcie Table */
1494 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 0,
1495 get_pcie_gen_support(data
->pcie_gen_cap
,
1497 get_pcie_lane_support(data
->pcie_lane_cap
,
1499 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 1,
1500 get_pcie_gen_support(data
->pcie_gen_cap
,
1502 get_pcie_lane_support(data
->pcie_lane_cap
,
1504 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 2,
1505 get_pcie_gen_support(data
->pcie_gen_cap
,
1507 get_pcie_lane_support(data
->pcie_lane_cap
,
1509 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 3,
1510 get_pcie_gen_support(data
->pcie_gen_cap
,
1512 get_pcie_lane_support(data
->pcie_lane_cap
,
1514 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 4,
1515 get_pcie_gen_support(data
->pcie_gen_cap
,
1517 get_pcie_lane_support(data
->pcie_lane_cap
,
1519 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 5,
1520 get_pcie_gen_support(data
->pcie_gen_cap
,
1522 get_pcie_lane_support(data
->pcie_lane_cap
,
1525 data
->dpm_table
.pcie_speed_table
.count
= 6;
1527 /* Populate last level for boot PCIE level, but do not increment count. */
1528 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
,
1529 data
->dpm_table
.pcie_speed_table
.count
,
1530 get_pcie_gen_support(data
->pcie_gen_cap
,
1532 get_pcie_lane_support(data
->pcie_lane_cap
,
1539 * This function is to initalize all DPM state tables
1540 * for SMU7 based on the dependency table.
1541 * Dynamic state patching function will then trim these
1542 * state tables to the allowed range based
1543 * on the power policy or external client requests,
1544 * such as UVD request, etc.
1546 static int fiji_setup_default_dpm_tables(struct pp_hwmgr
*hwmgr
)
1548 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1549 struct phm_ppt_v1_information
*table_info
=
1550 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1553 struct phm_ppt_v1_clock_voltage_dependency_table
*dep_sclk_table
=
1554 table_info
->vdd_dep_on_sclk
;
1555 struct phm_ppt_v1_clock_voltage_dependency_table
*dep_mclk_table
=
1556 table_info
->vdd_dep_on_mclk
;
1558 PP_ASSERT_WITH_CODE(dep_sclk_table
!= NULL
,
1559 "SCLK dependency table is missing. This table is mandatory",
1561 PP_ASSERT_WITH_CODE(dep_sclk_table
->count
>= 1,
1562 "SCLK dependency table has to have is missing. "
1563 "This table is mandatory",
1566 PP_ASSERT_WITH_CODE(dep_mclk_table
!= NULL
,
1567 "MCLK dependency table is missing. This table is mandatory",
1569 PP_ASSERT_WITH_CODE(dep_mclk_table
->count
>= 1,
1570 "MCLK dependency table has to have is missing. "
1571 "This table is mandatory",
1574 /* clear the state table to reset everything to default */
1575 fiji_reset_single_dpm_table(hwmgr
,
1576 &data
->dpm_table
.sclk_table
, SMU73_MAX_LEVELS_GRAPHICS
);
1577 fiji_reset_single_dpm_table(hwmgr
,
1578 &data
->dpm_table
.mclk_table
, SMU73_MAX_LEVELS_MEMORY
);
1580 /* Initialize Sclk DPM table based on allow Sclk values */
1581 data
->dpm_table
.sclk_table
.count
= 0;
1582 for (i
= 0; i
< dep_sclk_table
->count
; i
++) {
1583 if (i
== 0 || data
->dpm_table
.sclk_table
.dpm_levels
1584 [data
->dpm_table
.sclk_table
.count
- 1].value
!=
1585 dep_sclk_table
->entries
[i
].clk
) {
1586 data
->dpm_table
.sclk_table
.dpm_levels
1587 [data
->dpm_table
.sclk_table
.count
].value
=
1588 dep_sclk_table
->entries
[i
].clk
;
1589 data
->dpm_table
.sclk_table
.dpm_levels
1590 [data
->dpm_table
.sclk_table
.count
].enabled
=
1591 (i
== 0) ? true : false;
1592 data
->dpm_table
.sclk_table
.count
++;
1596 /* Initialize Mclk DPM table based on allow Mclk values */
1597 data
->dpm_table
.mclk_table
.count
= 0;
1598 for (i
=0; i
<dep_mclk_table
->count
; i
++) {
1599 if ( i
==0 || data
->dpm_table
.mclk_table
.dpm_levels
1600 [data
->dpm_table
.mclk_table
.count
- 1].value
!=
1601 dep_mclk_table
->entries
[i
].clk
) {
1602 data
->dpm_table
.mclk_table
.dpm_levels
1603 [data
->dpm_table
.mclk_table
.count
].value
=
1604 dep_mclk_table
->entries
[i
].clk
;
1605 data
->dpm_table
.mclk_table
.dpm_levels
1606 [data
->dpm_table
.mclk_table
.count
].enabled
=
1607 (i
== 0) ? true : false;
1608 data
->dpm_table
.mclk_table
.count
++;
1612 /* setup PCIE gen speed levels */
1613 fiji_setup_default_pcie_table(hwmgr
);
1615 /* save a copy of the default DPM table */
1616 memcpy(&(data
->golden_dpm_table
), &(data
->dpm_table
),
1617 sizeof(struct fiji_dpm_table
));
1623 * @brief PhwFiji_GetVoltageOrder
1624 * Returns index of requested voltage record in lookup(table)
1625 * @param lookup_table - lookup list to search in
1626 * @param voltage - voltage to look for
1627 * @return 0 on success
1629 uint8_t fiji_get_voltage_index(
1630 struct phm_ppt_v1_voltage_lookup_table
*lookup_table
, uint16_t voltage
)
1632 uint8_t count
= (uint8_t) (lookup_table
->count
);
1635 PP_ASSERT_WITH_CODE((NULL
!= lookup_table
),
1636 "Lookup Table empty.", return 0);
1637 PP_ASSERT_WITH_CODE((0 != count
),
1638 "Lookup Table empty.", return 0);
1640 for (i
= 0; i
< lookup_table
->count
; i
++) {
1641 /* find first voltage equal or bigger than requested */
1642 if (lookup_table
->entries
[i
].us_vdd
>= voltage
)
1645 /* voltage is bigger than max voltage in the table */
1650 * Preparation of vddc and vddgfx CAC tables for SMC.
1652 * @param hwmgr the address of the hardware manager
1653 * @param table the SMC DPM table structure to be populated
1656 static int fiji_populate_cac_table(struct pp_hwmgr
*hwmgr
,
1657 struct SMU73_Discrete_DpmTable
*table
)
1661 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1662 struct phm_ppt_v1_information
*table_info
=
1663 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1664 struct phm_ppt_v1_voltage_lookup_table
*lookup_table
=
1665 table_info
->vddc_lookup_table
;
1666 /* tables is already swapped, so in order to use the value from it,
1667 * we need to swap it back.
1668 * We are populating vddc CAC data to BapmVddc table
1669 * in split and merged mode
1671 for( count
= 0; count
<lookup_table
->count
; count
++) {
1672 index
= fiji_get_voltage_index(lookup_table
,
1673 data
->vddc_voltage_table
.entries
[count
].value
);
1674 table
->BapmVddcVidLoSidd
[count
] = (uint8_t) ((6200 -
1675 (lookup_table
->entries
[index
].us_cac_low
*
1676 VOLTAGE_SCALE
)) / 25);
1677 table
->BapmVddcVidHiSidd
[count
] = (uint8_t) ((6200 -
1678 (lookup_table
->entries
[index
].us_cac_high
*
1679 VOLTAGE_SCALE
)) / 25);
1686 * Preparation of voltage tables for SMC.
1688 * @param hwmgr the address of the hardware manager
1689 * @param table the SMC DPM table structure to be populated
1693 int fiji_populate_smc_voltage_tables(struct pp_hwmgr
*hwmgr
,
1694 struct SMU73_Discrete_DpmTable
*table
)
1698 result
= fiji_populate_cac_table(hwmgr
, table
);
1699 PP_ASSERT_WITH_CODE(0 == result
,
1700 "can not populate CAC voltage tables to SMC",
1706 static int fiji_populate_ulv_level(struct pp_hwmgr
*hwmgr
,
1707 struct SMU73_Discrete_Ulv
*state
)
1710 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1711 struct phm_ppt_v1_information
*table_info
=
1712 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1714 state
->CcPwrDynRm
= 0;
1715 state
->CcPwrDynRm1
= 0;
1717 state
->VddcOffset
= (uint16_t) table_info
->us_ulv_voltage_offset
;
1718 state
->VddcOffsetVid
= (uint8_t)( table_info
->us_ulv_voltage_offset
*
1719 VOLTAGE_VID_OFFSET_SCALE2
/ VOLTAGE_VID_OFFSET_SCALE1
);
1721 state
->VddcPhase
= (data
->vddc_phase_shed_control
) ? 0 : 1;
1724 CONVERT_FROM_HOST_TO_SMC_UL(state
->CcPwrDynRm
);
1725 CONVERT_FROM_HOST_TO_SMC_UL(state
->CcPwrDynRm1
);
1726 CONVERT_FROM_HOST_TO_SMC_US(state
->VddcOffset
);
1731 static int fiji_populate_ulv_state(struct pp_hwmgr
*hwmgr
,
1732 struct SMU73_Discrete_DpmTable
*table
)
1734 return fiji_populate_ulv_level(hwmgr
, &table
->Ulv
);
1737 static int32_t fiji_get_dpm_level_enable_mask_value(
1738 struct fiji_single_dpm_table
* dpm_table
)
1743 for (i
= dpm_table
->count
; i
> 0; i
--) {
1745 if (dpm_table
->dpm_levels
[i
- 1].enabled
)
1753 static int fiji_populate_smc_link_level(struct pp_hwmgr
*hwmgr
,
1754 struct SMU73_Discrete_DpmTable
*table
)
1756 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1757 struct fiji_dpm_table
*dpm_table
= &data
->dpm_table
;
1760 /* Index (dpm_table->pcie_speed_table.count)
1761 * is reserved for PCIE boot level. */
1762 for (i
= 0; i
<= dpm_table
->pcie_speed_table
.count
; i
++) {
1763 table
->LinkLevel
[i
].PcieGenSpeed
=
1764 (uint8_t)dpm_table
->pcie_speed_table
.dpm_levels
[i
].value
;
1765 table
->LinkLevel
[i
].PcieLaneCount
= (uint8_t)encode_pcie_lane_width(
1766 dpm_table
->pcie_speed_table
.dpm_levels
[i
].param1
);
1767 table
->LinkLevel
[i
].EnabledForActivity
= 1;
1768 table
->LinkLevel
[i
].SPC
= (uint8_t)(data
->pcie_spc_cap
& 0xff);
1769 table
->LinkLevel
[i
].DownThreshold
= PP_HOST_TO_SMC_UL(5);
1770 table
->LinkLevel
[i
].UpThreshold
= PP_HOST_TO_SMC_UL(30);
1773 data
->smc_state_table
.LinkLevelCount
=
1774 (uint8_t)dpm_table
->pcie_speed_table
.count
;
1775 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
=
1776 fiji_get_dpm_level_enable_mask_value(&dpm_table
->pcie_speed_table
);
1782 * Calculates the SCLK dividers using the provided engine clock
1784 * @param hwmgr the address of the hardware manager
1785 * @param clock the engine clock to use to populate the structure
1786 * @param sclk the SMC SCLK structure to be populated
1788 static int fiji_calculate_sclk_params(struct pp_hwmgr
*hwmgr
,
1789 uint32_t clock
, struct SMU73_Discrete_GraphicsLevel
*sclk
)
1791 const struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1792 struct pp_atomctrl_clock_dividers_vi dividers
;
1793 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
1794 uint32_t spll_func_cntl_3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
1795 uint32_t spll_func_cntl_4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
1796 uint32_t cg_spll_spread_spectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
1797 uint32_t cg_spll_spread_spectrum_2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
1799 uint32_t ref_divider
;
1803 /* get the engine clock dividers for this clock value */
1804 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
, clock
, ÷rs
);
1806 PP_ASSERT_WITH_CODE(result
== 0,
1807 "Error retrieving Engine Clock dividers from VBIOS.",
1810 /* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */
1811 ref_clock
= atomctrl_get_reference_clock(hwmgr
);
1812 ref_divider
= 1 + dividers
.uc_pll_ref_div
;
1814 /* low 14 bits is fraction and high 12 bits is divider */
1815 fbdiv
= dividers
.ul_fb_div
.ul_fb_divider
& 0x3FFFFFF;
1817 /* SPLL_FUNC_CNTL setup */
1818 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
1819 SPLL_REF_DIV
, dividers
.uc_pll_ref_div
);
1820 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
1821 SPLL_PDIV_A
, dividers
.uc_pll_post_div
);
1823 /* SPLL_FUNC_CNTL_3 setup*/
1824 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
, CG_SPLL_FUNC_CNTL_3
,
1825 SPLL_FB_DIV
, fbdiv
);
1827 /* set to use fractional accumulation*/
1828 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
, CG_SPLL_FUNC_CNTL_3
,
1831 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
1832 PHM_PlatformCaps_EngineSpreadSpectrumSupport
)) {
1833 struct pp_atomctrl_internal_ss_info ssInfo
;
1835 uint32_t vco_freq
= clock
* dividers
.uc_pll_post_div
;
1836 if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr
,
1837 vco_freq
, &ssInfo
)) {
1839 * ss_info.speed_spectrum_percentage -- in unit of 0.01%
1840 * ss_info.speed_spectrum_rate -- in unit of khz
1842 * clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2
1844 uint32_t clk_s
= ref_clock
* 5 /
1845 (ref_divider
* ssInfo
.speed_spectrum_rate
);
1846 /* clkv = 2 * D * fbdiv / NS */
1847 uint32_t clk_v
= 4 * ssInfo
.speed_spectrum_percentage
*
1848 fbdiv
/ (clk_s
* 10000);
1850 cg_spll_spread_spectrum
= PHM_SET_FIELD(cg_spll_spread_spectrum
,
1851 CG_SPLL_SPREAD_SPECTRUM
, CLKS
, clk_s
);
1852 cg_spll_spread_spectrum
= PHM_SET_FIELD(cg_spll_spread_spectrum
,
1853 CG_SPLL_SPREAD_SPECTRUM
, SSEN
, 1);
1854 cg_spll_spread_spectrum_2
= PHM_SET_FIELD(cg_spll_spread_spectrum_2
,
1855 CG_SPLL_SPREAD_SPECTRUM_2
, CLKV
, clk_v
);
1859 sclk
->SclkFrequency
= clock
;
1860 sclk
->CgSpllFuncCntl3
= spll_func_cntl_3
;
1861 sclk
->CgSpllFuncCntl4
= spll_func_cntl_4
;
1862 sclk
->SpllSpreadSpectrum
= cg_spll_spread_spectrum
;
1863 sclk
->SpllSpreadSpectrum2
= cg_spll_spread_spectrum_2
;
1864 sclk
->SclkDid
= (uint8_t)dividers
.pll_post_divider
;
1869 static uint16_t fiji_find_closest_vddci(struct pp_hwmgr
*hwmgr
, uint16_t vddci
)
1872 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1873 struct pp_atomctrl_voltage_table
*vddci_table
=
1874 &(data
->vddci_voltage_table
);
1876 for (i
= 0; i
< vddci_table
->count
; i
++) {
1877 if (vddci_table
->entries
[i
].value
>= vddci
)
1878 return vddci_table
->entries
[i
].value
;
1881 PP_ASSERT_WITH_CODE(false,
1882 "VDDCI is larger than max VDDCI in VDDCI Voltage Table!",
1883 return vddci_table
->entries
[i
-1].value
);
1886 static int fiji_get_dependency_volt_by_clk(struct pp_hwmgr
*hwmgr
,
1887 struct phm_ppt_v1_clock_voltage_dependency_table
* dep_table
,
1888 uint32_t clock
, SMU_VoltageLevel
*voltage
, uint32_t *mvdd
)
1892 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1894 *voltage
= *mvdd
= 0;
1896 /* clock - voltage dependency table is empty table */
1897 if (dep_table
->count
== 0)
1900 for (i
= 0; i
< dep_table
->count
; i
++) {
1901 /* find first sclk bigger than request */
1902 if (dep_table
->entries
[i
].clk
>= clock
) {
1903 *voltage
|= (dep_table
->entries
[i
].vddc
*
1904 VOLTAGE_SCALE
) << VDDC_SHIFT
;
1905 if (FIJI_VOLTAGE_CONTROL_NONE
== data
->vddci_control
)
1906 *voltage
|= (data
->vbios_boot_state
.vddci_bootup_value
*
1907 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1908 else if (dep_table
->entries
[i
].vddci
)
1909 *voltage
|= (dep_table
->entries
[i
].vddci
*
1910 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1912 vddci
= fiji_find_closest_vddci(hwmgr
,
1913 (dep_table
->entries
[i
].vddc
-
1914 (uint16_t)data
->vddc_vddci_delta
));
1915 *voltage
|= (vddci
* VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1918 if (FIJI_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
)
1919 *mvdd
= data
->vbios_boot_state
.mvdd_bootup_value
*
1921 else if (dep_table
->entries
[i
].mvdd
)
1922 *mvdd
= (uint32_t) dep_table
->entries
[i
].mvdd
*
1925 *voltage
|= 1 << PHASES_SHIFT
;
1930 /* sclk is bigger than max sclk in the dependence table */
1931 *voltage
|= (dep_table
->entries
[i
- 1].vddc
* VOLTAGE_SCALE
) << VDDC_SHIFT
;
1933 if (FIJI_VOLTAGE_CONTROL_NONE
== data
->vddci_control
)
1934 *voltage
|= (data
->vbios_boot_state
.vddci_bootup_value
*
1935 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1936 else if (dep_table
->entries
[i
-1].vddci
) {
1937 vddci
= fiji_find_closest_vddci(hwmgr
,
1938 (dep_table
->entries
[i
].vddc
-
1939 (uint16_t)data
->vddc_vddci_delta
));
1940 *voltage
|= (vddci
* VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1943 if (FIJI_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
)
1944 *mvdd
= data
->vbios_boot_state
.mvdd_bootup_value
* VOLTAGE_SCALE
;
1945 else if (dep_table
->entries
[i
].mvdd
)
1946 *mvdd
= (uint32_t) dep_table
->entries
[i
- 1].mvdd
* VOLTAGE_SCALE
;
1951 static uint8_t fiji_get_sleep_divider_id_from_clock(uint32_t clock
,
1952 uint32_t clock_insr
)
1956 uint32_t min
= max(clock_insr
, (uint32_t)FIJI_MINIMUM_ENGINE_CLOCK
);
1958 PP_ASSERT_WITH_CODE((clock
>= min
), "Engine clock can't satisfy stutter requirement!", return 0);
1959 for (i
= FIJI_MAX_DEEPSLEEP_DIVIDER_ID
; ; i
--) {
1962 if (temp
>= min
|| i
== 0)
1968 * Populates single SMC SCLK structure using the provided engine clock
1970 * @param hwmgr the address of the hardware manager
1971 * @param clock the engine clock to use to populate the structure
1972 * @param sclk the SMC SCLK structure to be populated
1975 static int fiji_populate_single_graphic_level(struct pp_hwmgr
*hwmgr
,
1976 uint32_t clock
, uint16_t sclk_al_threshold
,
1977 struct SMU73_Discrete_GraphicsLevel
*level
)
1980 /* PP_Clocks minClocks; */
1981 uint32_t threshold
, mvdd
;
1982 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1983 struct phm_ppt_v1_information
*table_info
=
1984 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1986 result
= fiji_calculate_sclk_params(hwmgr
, clock
, level
);
1988 /* populate graphics levels */
1989 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
1990 table_info
->vdd_dep_on_sclk
, clock
,
1991 &level
->MinVoltage
, &mvdd
);
1992 PP_ASSERT_WITH_CODE((0 == result
),
1993 "can not find VDDC voltage value for "
1994 "VDDC engine clock dependency table",
1997 level
->SclkFrequency
= clock
;
1998 level
->ActivityLevel
= sclk_al_threshold
;
1999 level
->CcPwrDynRm
= 0;
2000 level
->CcPwrDynRm1
= 0;
2001 level
->EnabledForActivity
= 0;
2002 level
->EnabledForThrottle
= 1;
2004 level
->DownHyst
= 0;
2005 level
->VoltageDownHyst
= 0;
2006 level
->PowerThrottle
= 0;
2008 threshold
= clock
* data
->fast_watermark_threshold
/ 100;
2011 data
->display_timing
.min_clock_in_sr
= hwmgr
->display_config
.min_core_set_clock_in_sr
;
2013 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_SclkDeepSleep
))
2014 level
->DeepSleepDivId
= fiji_get_sleep_divider_id_from_clock(clock
,
2015 hwmgr
->display_config
.min_core_set_clock_in_sr
);
2018 /* Default to slow, highest DPM level will be
2019 * set to PPSMC_DISPLAY_WATERMARK_LOW later.
2021 level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2023 CONVERT_FROM_HOST_TO_SMC_UL(level
->MinVoltage
);
2024 CONVERT_FROM_HOST_TO_SMC_UL(level
->SclkFrequency
);
2025 CONVERT_FROM_HOST_TO_SMC_US(level
->ActivityLevel
);
2026 CONVERT_FROM_HOST_TO_SMC_UL(level
->CgSpllFuncCntl3
);
2027 CONVERT_FROM_HOST_TO_SMC_UL(level
->CgSpllFuncCntl4
);
2028 CONVERT_FROM_HOST_TO_SMC_UL(level
->SpllSpreadSpectrum
);
2029 CONVERT_FROM_HOST_TO_SMC_UL(level
->SpllSpreadSpectrum2
);
2030 CONVERT_FROM_HOST_TO_SMC_UL(level
->CcPwrDynRm
);
2031 CONVERT_FROM_HOST_TO_SMC_UL(level
->CcPwrDynRm1
);
2036 * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
2038 * @param hwmgr the address of the hardware manager
2040 static int fiji_populate_all_graphic_levels(struct pp_hwmgr
*hwmgr
)
2042 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2043 struct fiji_dpm_table
*dpm_table
= &data
->dpm_table
;
2044 struct phm_ppt_v1_information
*table_info
=
2045 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2046 struct phm_ppt_v1_pcie_table
*pcie_table
= table_info
->pcie_table
;
2047 uint8_t pcie_entry_cnt
= (uint8_t) data
->dpm_table
.pcie_speed_table
.count
;
2049 uint32_t array
= data
->dpm_table_start
+
2050 offsetof(SMU73_Discrete_DpmTable
, GraphicsLevel
);
2051 uint32_t array_size
= sizeof(struct SMU73_Discrete_GraphicsLevel
) *
2052 SMU73_MAX_LEVELS_GRAPHICS
;
2053 struct SMU73_Discrete_GraphicsLevel
*levels
=
2054 data
->smc_state_table
.GraphicsLevel
;
2055 uint32_t i
, max_entry
;
2056 uint8_t hightest_pcie_level_enabled
= 0,
2057 lowest_pcie_level_enabled
= 0,
2058 mid_pcie_level_enabled
= 0,
2061 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
2062 result
= fiji_populate_single_graphic_level(hwmgr
,
2063 dpm_table
->sclk_table
.dpm_levels
[i
].value
,
2064 (uint16_t)data
->activity_target
[i
],
2069 /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
2071 levels
[i
].DeepSleepDivId
= 0;
2074 /* Only enable level 0 for now.*/
2075 levels
[0].EnabledForActivity
= 1;
2077 /* set highest level watermark to high */
2078 levels
[dpm_table
->sclk_table
.count
- 1].DisplayWatermark
=
2079 PPSMC_DISPLAY_WATERMARK_HIGH
;
2081 data
->smc_state_table
.GraphicsDpmLevelCount
=
2082 (uint8_t)dpm_table
->sclk_table
.count
;
2083 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
=
2084 fiji_get_dpm_level_enable_mask_value(&dpm_table
->sclk_table
);
2086 if (pcie_table
!= NULL
) {
2087 PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt
),
2088 "There must be 1 or more PCIE levels defined in PPTable.",
2090 max_entry
= pcie_entry_cnt
- 1;
2091 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++)
2092 levels
[i
].pcieDpmLevel
=
2093 (uint8_t) ((i
< max_entry
)? i
: max_entry
);
2095 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
2096 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2097 (1 << (hightest_pcie_level_enabled
+ 1))) != 0 ))
2098 hightest_pcie_level_enabled
++;
2100 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
2101 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2102 (1 << lowest_pcie_level_enabled
)) == 0 ))
2103 lowest_pcie_level_enabled
++;
2105 while ((count
< hightest_pcie_level_enabled
) &&
2106 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2107 (1 << (lowest_pcie_level_enabled
+ 1 + count
))) == 0 ))
2110 mid_pcie_level_enabled
= (lowest_pcie_level_enabled
+ 1+ count
) <
2111 hightest_pcie_level_enabled
?
2112 (lowest_pcie_level_enabled
+ 1 + count
) :
2113 hightest_pcie_level_enabled
;
2115 /* set pcieDpmLevel to hightest_pcie_level_enabled */
2116 for(i
= 2; i
< dpm_table
->sclk_table
.count
; i
++)
2117 levels
[i
].pcieDpmLevel
= hightest_pcie_level_enabled
;
2119 /* set pcieDpmLevel to lowest_pcie_level_enabled */
2120 levels
[0].pcieDpmLevel
= lowest_pcie_level_enabled
;
2122 /* set pcieDpmLevel to mid_pcie_level_enabled */
2123 levels
[1].pcieDpmLevel
= mid_pcie_level_enabled
;
2125 /* level count will send to smc once at init smc table and never change */
2126 result
= fiji_copy_bytes_to_smc(hwmgr
->smumgr
, array
, (uint8_t *)levels
,
2127 (uint32_t)array_size
, data
->sram_end
);
2133 * MCLK Frequency Ratio
2134 * SEQ_CG_RESP Bit[31:24] - 0x0
2135 * Bit[27:24] \96 DDR3 Frequency ratio
2136 * 0x0 <= 100MHz, 450 < 0x8 <= 500MHz
2137 * 100 < 0x1 <= 150MHz, 500 < 0x9 <= 550MHz
2138 * 150 < 0x2 <= 200MHz, 550 < 0xA <= 600MHz
2139 * 200 < 0x3 <= 250MHz, 600 < 0xB <= 650MHz
2140 * 250 < 0x4 <= 300MHz, 650 < 0xC <= 700MHz
2141 * 300 < 0x5 <= 350MHz, 700 < 0xD <= 750MHz
2142 * 350 < 0x6 <= 400MHz, 750 < 0xE <= 800MHz
2143 * 400 < 0x7 <= 450MHz, 800 < 0xF
2145 static uint8_t fiji_get_mclk_frequency_ratio(uint32_t mem_clock
)
2147 if (mem_clock
<= 10000) return 0x0;
2148 if (mem_clock
<= 15000) return 0x1;
2149 if (mem_clock
<= 20000) return 0x2;
2150 if (mem_clock
<= 25000) return 0x3;
2151 if (mem_clock
<= 30000) return 0x4;
2152 if (mem_clock
<= 35000) return 0x5;
2153 if (mem_clock
<= 40000) return 0x6;
2154 if (mem_clock
<= 45000) return 0x7;
2155 if (mem_clock
<= 50000) return 0x8;
2156 if (mem_clock
<= 55000) return 0x9;
2157 if (mem_clock
<= 60000) return 0xa;
2158 if (mem_clock
<= 65000) return 0xb;
2159 if (mem_clock
<= 70000) return 0xc;
2160 if (mem_clock
<= 75000) return 0xd;
2161 if (mem_clock
<= 80000) return 0xe;
2162 /* mem_clock > 800MHz */
2167 * Populates the SMC MCLK structure using the provided memory clock
2169 * @param hwmgr the address of the hardware manager
2170 * @param clock the memory clock to use to populate the structure
2171 * @param sclk the SMC SCLK structure to be populated
2173 static int fiji_calculate_mclk_params(struct pp_hwmgr
*hwmgr
,
2174 uint32_t clock
, struct SMU73_Discrete_MemoryLevel
*mclk
)
2176 struct pp_atomctrl_memory_clock_param mem_param
;
2179 result
= atomctrl_get_memory_pll_dividers_vi(hwmgr
, clock
, &mem_param
);
2180 PP_ASSERT_WITH_CODE((0 == result
),
2181 "Failed to get Memory PLL Dividers.",);
2183 /* Save the result data to outpupt memory level structure */
2184 mclk
->MclkFrequency
= clock
;
2185 mclk
->MclkDivider
= (uint8_t)mem_param
.mpll_post_divider
;
2186 mclk
->FreqRange
= fiji_get_mclk_frequency_ratio(clock
);
2191 static int fiji_populate_single_memory_level(struct pp_hwmgr
*hwmgr
,
2192 uint32_t clock
, struct SMU73_Discrete_MemoryLevel
*mem_level
)
2194 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2195 struct phm_ppt_v1_information
*table_info
=
2196 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2199 if (table_info
->vdd_dep_on_mclk
) {
2200 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
2201 table_info
->vdd_dep_on_mclk
, clock
,
2202 &mem_level
->MinVoltage
, &mem_level
->MinMvdd
);
2203 PP_ASSERT_WITH_CODE((0 == result
),
2204 "can not find MinVddc voltage value from memory "
2205 "VDDC voltage dependency table", return result
);
2208 mem_level
->EnabledForThrottle
= 1;
2209 mem_level
->EnabledForActivity
= 0;
2210 mem_level
->UpHyst
= 0;
2211 mem_level
->DownHyst
= 100;
2212 mem_level
->VoltageDownHyst
= 0;
2213 mem_level
->ActivityLevel
= (uint16_t)data
->mclk_activity_target
;
2214 mem_level
->StutterEnable
= false;
2216 mem_level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2218 /* enable stutter mode if all the follow condition applied
2219 * PECI_GetNumberOfActiveDisplays(hwmgr->pPECI,
2220 * &(data->DisplayTiming.numExistingDisplays));
2222 data
->display_timing
.num_existing_displays
= 1;
2224 if ((data
->mclk_stutter_mode_threshold
) &&
2225 (clock
<= data
->mclk_stutter_mode_threshold
) &&
2226 (!data
->is_uvd_enabled
) &&
2227 (PHM_READ_FIELD(hwmgr
->device
, DPG_PIPE_STUTTER_CONTROL
,
2228 STUTTER_ENABLE
) & 0x1))
2229 mem_level
->StutterEnable
= true;
2231 result
= fiji_calculate_mclk_params(hwmgr
, clock
, mem_level
);
2233 CONVERT_FROM_HOST_TO_SMC_UL(mem_level
->MinMvdd
);
2234 CONVERT_FROM_HOST_TO_SMC_UL(mem_level
->MclkFrequency
);
2235 CONVERT_FROM_HOST_TO_SMC_US(mem_level
->ActivityLevel
);
2236 CONVERT_FROM_HOST_TO_SMC_UL(mem_level
->MinVoltage
);
2242 * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
2244 * @param hwmgr the address of the hardware manager
2246 static int fiji_populate_all_memory_levels(struct pp_hwmgr
*hwmgr
)
2248 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2249 struct fiji_dpm_table
*dpm_table
= &data
->dpm_table
;
2251 /* populate MCLK dpm table to SMU7 */
2252 uint32_t array
= data
->dpm_table_start
+
2253 offsetof(SMU73_Discrete_DpmTable
, MemoryLevel
);
2254 uint32_t array_size
= sizeof(SMU73_Discrete_MemoryLevel
) *
2255 SMU73_MAX_LEVELS_MEMORY
;
2256 struct SMU73_Discrete_MemoryLevel
*levels
=
2257 data
->smc_state_table
.MemoryLevel
;
2260 for (i
= 0; i
< dpm_table
->mclk_table
.count
; i
++) {
2261 PP_ASSERT_WITH_CODE((0 != dpm_table
->mclk_table
.dpm_levels
[i
].value
),
2262 "can not populate memory level as memory clock is zero",
2264 result
= fiji_populate_single_memory_level(hwmgr
,
2265 dpm_table
->mclk_table
.dpm_levels
[i
].value
,
2271 /* Only enable level 0 for now. */
2272 levels
[0].EnabledForActivity
= 1;
2274 /* in order to prevent MC activity from stutter mode to push DPM up.
2275 * the UVD change complements this by putting the MCLK in
2276 * a higher state by default such that we are not effected by
2277 * up threshold or and MCLK DPM latency.
2279 levels
[0].ActivityLevel
= (uint16_t)data
->mclk_dpm0_activity_target
;
2280 CONVERT_FROM_HOST_TO_SMC_US(levels
[0].ActivityLevel
);
2282 data
->smc_state_table
.MemoryDpmLevelCount
=
2283 (uint8_t)dpm_table
->mclk_table
.count
;
2284 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
=
2285 fiji_get_dpm_level_enable_mask_value(&dpm_table
->mclk_table
);
2286 /* set highest level watermark to high */
2287 levels
[dpm_table
->mclk_table
.count
- 1].DisplayWatermark
=
2288 PPSMC_DISPLAY_WATERMARK_HIGH
;
2290 /* level count will send to smc once at init smc table and never change */
2291 result
= fiji_copy_bytes_to_smc(hwmgr
->smumgr
, array
, (uint8_t *)levels
,
2292 (uint32_t)array_size
, data
->sram_end
);
2298 * Populates the SMC MVDD structure using the provided memory clock.
2300 * @param hwmgr the address of the hardware manager
2301 * @param mclk the MCLK value to be used in the decision if MVDD should be high or low.
2302 * @param voltage the SMC VOLTAGE structure to be populated
2304 int fiji_populate_mvdd_value(struct pp_hwmgr
*hwmgr
,
2305 uint32_t mclk
, SMIO_Pattern
*smio_pat
)
2307 const struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2308 struct phm_ppt_v1_information
*table_info
=
2309 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2312 if (FIJI_VOLTAGE_CONTROL_NONE
!= data
->mvdd_control
) {
2313 /* find mvdd value which clock is more than request */
2314 for (i
= 0; i
< table_info
->vdd_dep_on_mclk
->count
; i
++) {
2315 if (mclk
<= table_info
->vdd_dep_on_mclk
->entries
[i
].clk
) {
2316 smio_pat
->Voltage
= data
->mvdd_voltage_table
.entries
[i
].value
;
2320 PP_ASSERT_WITH_CODE(i
< table_info
->vdd_dep_on_mclk
->count
,
2321 "MVDD Voltage is outside the supported range.",
2329 static int fiji_populate_smc_acpi_level(struct pp_hwmgr
*hwmgr
,
2330 SMU73_Discrete_DpmTable
*table
)
2333 const struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2334 struct phm_ppt_v1_information
*table_info
=
2335 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2336 struct pp_atomctrl_clock_dividers_vi dividers
;
2337 SMIO_Pattern vol_level
;
2340 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
2341 uint32_t spll_func_cntl_2
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
;
2343 table
->ACPILevel
.Flags
&= ~PPSMC_SWSTATE_FLAG_DC
;
2345 if (!data
->sclk_dpm_key_disabled
) {
2346 /* Get MinVoltage and Frequency from DPM0,
2347 * already converted to SMC_UL */
2348 table
->ACPILevel
.SclkFrequency
=
2349 data
->dpm_table
.sclk_table
.dpm_levels
[0].value
;
2350 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
2351 table_info
->vdd_dep_on_sclk
,
2352 table
->ACPILevel
.SclkFrequency
,
2353 &table
->ACPILevel
.MinVoltage
, &mvdd
);
2354 PP_ASSERT_WITH_CODE((0 == result
),
2355 "Cannot find ACPI VDDC voltage value "
2356 "in Clock Dependency Table",);
2358 table
->ACPILevel
.SclkFrequency
=
2359 data
->vbios_boot_state
.sclk_bootup_value
;
2360 table
->ACPILevel
.MinVoltage
=
2361 data
->vbios_boot_state
.vddc_bootup_value
* VOLTAGE_SCALE
;
2364 /* get the engine clock dividers for this clock value */
2365 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
,
2366 table
->ACPILevel
.SclkFrequency
, ÷rs
);
2367 PP_ASSERT_WITH_CODE(result
== 0,
2368 "Error retrieving Engine Clock dividers from VBIOS.",
2371 table
->ACPILevel
.SclkDid
= (uint8_t)dividers
.pll_post_divider
;
2372 table
->ACPILevel
.DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2373 table
->ACPILevel
.DeepSleepDivId
= 0;
2375 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
2377 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
2379 spll_func_cntl_2
= PHM_SET_FIELD(spll_func_cntl_2
, CG_SPLL_FUNC_CNTL_2
,
2382 table
->ACPILevel
.CgSpllFuncCntl
= spll_func_cntl
;
2383 table
->ACPILevel
.CgSpllFuncCntl2
= spll_func_cntl_2
;
2384 table
->ACPILevel
.CgSpllFuncCntl3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
2385 table
->ACPILevel
.CgSpllFuncCntl4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
2386 table
->ACPILevel
.SpllSpreadSpectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
2387 table
->ACPILevel
.SpllSpreadSpectrum2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
2388 table
->ACPILevel
.CcPwrDynRm
= 0;
2389 table
->ACPILevel
.CcPwrDynRm1
= 0;
2391 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.Flags
);
2392 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SclkFrequency
);
2393 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.MinVoltage
);
2394 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl
);
2395 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl2
);
2396 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl3
);
2397 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl4
);
2398 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum
);
2399 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum2
);
2400 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm
);
2401 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm1
);
2403 if (!data
->mclk_dpm_key_disabled
) {
2404 /* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */
2405 table
->MemoryACPILevel
.MclkFrequency
=
2406 data
->dpm_table
.mclk_table
.dpm_levels
[0].value
;
2407 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
2408 table_info
->vdd_dep_on_mclk
,
2409 table
->MemoryACPILevel
.MclkFrequency
,
2410 &table
->MemoryACPILevel
.MinVoltage
, &mvdd
);
2411 PP_ASSERT_WITH_CODE((0 == result
),
2412 "Cannot find ACPI VDDCI voltage value "
2413 "in Clock Dependency Table",);
2415 table
->MemoryACPILevel
.MclkFrequency
=
2416 data
->vbios_boot_state
.mclk_bootup_value
;
2417 table
->MemoryACPILevel
.MinVoltage
=
2418 data
->vbios_boot_state
.vddci_bootup_value
* VOLTAGE_SCALE
;
2422 if ((FIJI_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
) ||
2423 (data
->mclk_dpm_key_disabled
))
2424 us_mvdd
= data
->vbios_boot_state
.mvdd_bootup_value
;
2426 if (!fiji_populate_mvdd_value(hwmgr
,
2427 data
->dpm_table
.mclk_table
.dpm_levels
[0].value
,
2429 us_mvdd
= vol_level
.Voltage
;
2432 table
->MemoryACPILevel
.MinMvdd
=
2433 PP_HOST_TO_SMC_UL(us_mvdd
* VOLTAGE_SCALE
);
2435 table
->MemoryACPILevel
.EnabledForThrottle
= 0;
2436 table
->MemoryACPILevel
.EnabledForActivity
= 0;
2437 table
->MemoryACPILevel
.UpHyst
= 0;
2438 table
->MemoryACPILevel
.DownHyst
= 100;
2439 table
->MemoryACPILevel
.VoltageDownHyst
= 0;
2440 table
->MemoryACPILevel
.ActivityLevel
=
2441 PP_HOST_TO_SMC_US((uint16_t)data
->mclk_activity_target
);
2443 table
->MemoryACPILevel
.StutterEnable
= false;
2444 CONVERT_FROM_HOST_TO_SMC_UL(table
->MemoryACPILevel
.MclkFrequency
);
2445 CONVERT_FROM_HOST_TO_SMC_UL(table
->MemoryACPILevel
.MinVoltage
);
2450 static int fiji_populate_smc_vce_level(struct pp_hwmgr
*hwmgr
,
2451 SMU73_Discrete_DpmTable
*table
)
2453 int result
= -EINVAL
;
2455 struct pp_atomctrl_clock_dividers_vi dividers
;
2456 struct phm_ppt_v1_information
*table_info
=
2457 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2458 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
2459 table_info
->mm_dep_table
;
2460 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2462 table
->VceLevelCount
= (uint8_t)(mm_table
->count
);
2463 table
->VceBootLevel
= 0;
2465 for(count
= 0; count
< table
->VceLevelCount
; count
++) {
2466 table
->VceLevel
[count
].Frequency
= mm_table
->entries
[count
].eclk
;
2467 table
->VceLevel
[count
].MinVoltage
= 0;
2468 table
->VceLevel
[count
].MinVoltage
|=
2469 (mm_table
->entries
[count
].vddc
* VOLTAGE_SCALE
) << VDDC_SHIFT
;
2470 table
->VceLevel
[count
].MinVoltage
|=
2471 ((mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
) *
2472 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
2473 table
->VceLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
2475 /*retrieve divider value for VBIOS */
2476 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
2477 table
->VceLevel
[count
].Frequency
, ÷rs
);
2478 PP_ASSERT_WITH_CODE((0 == result
),
2479 "can not find divide id for VCE engine clock",
2482 table
->VceLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
2484 CONVERT_FROM_HOST_TO_SMC_UL(table
->VceLevel
[count
].Frequency
);
2485 CONVERT_FROM_HOST_TO_SMC_UL(table
->VceLevel
[count
].MinVoltage
);
2490 static int fiji_populate_smc_acp_level(struct pp_hwmgr
*hwmgr
,
2491 SMU73_Discrete_DpmTable
*table
)
2493 int result
= -EINVAL
;
2495 struct pp_atomctrl_clock_dividers_vi dividers
;
2496 struct phm_ppt_v1_information
*table_info
=
2497 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2498 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
2499 table_info
->mm_dep_table
;
2500 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2502 table
->AcpLevelCount
= (uint8_t)(mm_table
->count
);
2503 table
->AcpBootLevel
= 0;
2505 for (count
= 0; count
< table
->AcpLevelCount
; count
++) {
2506 table
->AcpLevel
[count
].Frequency
= mm_table
->entries
[count
].aclk
;
2507 table
->AcpLevel
[count
].MinVoltage
|= (mm_table
->entries
[count
].vddc
*
2508 VOLTAGE_SCALE
) << VDDC_SHIFT
;
2509 table
->AcpLevel
[count
].MinVoltage
|= ((mm_table
->entries
[count
].vddc
-
2510 data
->vddc_vddci_delta
) * VOLTAGE_SCALE
) << VDDCI_SHIFT
;
2511 table
->AcpLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
2513 /* retrieve divider value for VBIOS */
2514 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
2515 table
->AcpLevel
[count
].Frequency
, ÷rs
);
2516 PP_ASSERT_WITH_CODE((0 == result
),
2517 "can not find divide id for engine clock", return result
);
2519 table
->AcpLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
2521 CONVERT_FROM_HOST_TO_SMC_UL(table
->AcpLevel
[count
].Frequency
);
2522 CONVERT_FROM_HOST_TO_SMC_UL(table
->AcpLevel
[count
].MinVoltage
);
2527 static int fiji_populate_smc_samu_level(struct pp_hwmgr
*hwmgr
,
2528 SMU73_Discrete_DpmTable
*table
)
2530 int result
= -EINVAL
;
2532 struct pp_atomctrl_clock_dividers_vi dividers
;
2533 struct phm_ppt_v1_information
*table_info
=
2534 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2535 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
2536 table_info
->mm_dep_table
;
2537 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2539 table
->SamuBootLevel
= 0;
2540 table
->SamuLevelCount
= (uint8_t)(mm_table
->count
);
2542 for (count
= 0; count
< table
->SamuLevelCount
; count
++) {
2543 /* not sure whether we need evclk or not */
2544 table
->SamuLevel
[count
].MinVoltage
= 0;
2545 table
->SamuLevel
[count
].Frequency
= mm_table
->entries
[count
].samclock
;
2546 table
->SamuLevel
[count
].MinVoltage
|= (mm_table
->entries
[count
].vddc
*
2547 VOLTAGE_SCALE
) << VDDC_SHIFT
;
2548 table
->SamuLevel
[count
].MinVoltage
|= ((mm_table
->entries
[count
].vddc
-
2549 data
->vddc_vddci_delta
) * VOLTAGE_SCALE
) << VDDCI_SHIFT
;
2550 table
->SamuLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
2552 /* retrieve divider value for VBIOS */
2553 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
2554 table
->SamuLevel
[count
].Frequency
, ÷rs
);
2555 PP_ASSERT_WITH_CODE((0 == result
),
2556 "can not find divide id for samu clock", return result
);
2558 table
->SamuLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
2560 CONVERT_FROM_HOST_TO_SMC_UL(table
->SamuLevel
[count
].Frequency
);
2561 CONVERT_FROM_HOST_TO_SMC_UL(table
->SamuLevel
[count
].MinVoltage
);
2566 static int fiji_populate_memory_timing_parameters(struct pp_hwmgr
*hwmgr
,
2567 int32_t eng_clock
, int32_t mem_clock
,
2568 struct SMU73_Discrete_MCArbDramTimingTableEntry
*arb_regs
)
2570 uint32_t dram_timing
;
2571 uint32_t dram_timing2
;
2573 ULONG state
, trrds
, trrdl
;
2576 result
= atomctrl_set_engine_dram_timings_rv770(hwmgr
,
2577 eng_clock
, mem_clock
);
2578 PP_ASSERT_WITH_CODE(result
== 0,
2579 "Error calling VBIOS to set DRAM_TIMING.", return result
);
2581 dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
2582 dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
2583 burstTime
= cgs_read_register(hwmgr
->device
, mmMC_ARB_BURST_TIME
);
2585 state
= PHM_GET_FIELD(burstTime
, MC_ARB_BURST_TIME
, STATE0
);
2586 trrds
= PHM_GET_FIELD(burstTime
, MC_ARB_BURST_TIME
, TRRDS0
);
2587 trrdl
= PHM_GET_FIELD(burstTime
, MC_ARB_BURST_TIME
, TRRDL0
);
2589 arb_regs
->McArbDramTiming
= PP_HOST_TO_SMC_UL(dram_timing
);
2590 arb_regs
->McArbDramTiming2
= PP_HOST_TO_SMC_UL(dram_timing2
);
2591 arb_regs
->McArbBurstTime
= (uint8_t)burstTime
;
2592 arb_regs
->TRRDS
= (uint8_t)trrds
;
2593 arb_regs
->TRRDL
= (uint8_t)trrdl
;
2598 static int fiji_program_memory_timing_parameters(struct pp_hwmgr
*hwmgr
)
2600 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2601 struct SMU73_Discrete_MCArbDramTimingTable arb_regs
;
2605 for (i
= 0; i
< data
->dpm_table
.sclk_table
.count
; i
++) {
2606 for (j
= 0; j
< data
->dpm_table
.mclk_table
.count
; j
++) {
2607 result
= fiji_populate_memory_timing_parameters(hwmgr
,
2608 data
->dpm_table
.sclk_table
.dpm_levels
[i
].value
,
2609 data
->dpm_table
.mclk_table
.dpm_levels
[j
].value
,
2610 &arb_regs
.entries
[i
][j
]);
2617 result
= fiji_copy_bytes_to_smc(
2619 data
->arb_table_start
,
2620 (uint8_t *)&arb_regs
,
2621 sizeof(SMU73_Discrete_MCArbDramTimingTable
),
2626 static int fiji_populate_smc_uvd_level(struct pp_hwmgr
*hwmgr
,
2627 struct SMU73_Discrete_DpmTable
*table
)
2629 int result
= -EINVAL
;
2631 struct pp_atomctrl_clock_dividers_vi dividers
;
2632 struct phm_ppt_v1_information
*table_info
=
2633 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2634 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
2635 table_info
->mm_dep_table
;
2636 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2638 table
->UvdLevelCount
= (uint8_t)(mm_table
->count
);
2639 table
->UvdBootLevel
= 0;
2641 for (count
= 0; count
< table
->UvdLevelCount
; count
++) {
2642 table
->UvdLevel
[count
].MinVoltage
= 0;
2643 table
->UvdLevel
[count
].VclkFrequency
= mm_table
->entries
[count
].vclk
;
2644 table
->UvdLevel
[count
].DclkFrequency
= mm_table
->entries
[count
].dclk
;
2645 table
->UvdLevel
[count
].MinVoltage
|= (mm_table
->entries
[count
].vddc
*
2646 VOLTAGE_SCALE
) << VDDC_SHIFT
;
2647 table
->UvdLevel
[count
].MinVoltage
|= ((mm_table
->entries
[count
].vddc
-
2648 data
->vddc_vddci_delta
) * VOLTAGE_SCALE
) << VDDCI_SHIFT
;
2649 table
->UvdLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
2651 /* retrieve divider value for VBIOS */
2652 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
2653 table
->UvdLevel
[count
].VclkFrequency
, ÷rs
);
2654 PP_ASSERT_WITH_CODE((0 == result
),
2655 "can not find divide id for Vclk clock", return result
);
2657 table
->UvdLevel
[count
].VclkDivider
= (uint8_t)dividers
.pll_post_divider
;
2659 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
2660 table
->UvdLevel
[count
].DclkFrequency
, ÷rs
);
2661 PP_ASSERT_WITH_CODE((0 == result
),
2662 "can not find divide id for Dclk clock", return result
);
2664 table
->UvdLevel
[count
].DclkDivider
= (uint8_t)dividers
.pll_post_divider
;
2666 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].VclkFrequency
);
2667 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].DclkFrequency
);
2668 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].MinVoltage
);
2674 static int fiji_find_boot_level(struct fiji_single_dpm_table
*table
,
2675 uint32_t value
, uint32_t *boot_level
)
2677 int result
= -EINVAL
;
2680 for (i
= 0; i
< table
->count
; i
++) {
2681 if (value
== table
->dpm_levels
[i
].value
) {
2689 static int fiji_populate_smc_boot_level(struct pp_hwmgr
*hwmgr
,
2690 struct SMU73_Discrete_DpmTable
*table
)
2693 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2695 table
->GraphicsBootLevel
= 0;
2696 table
->MemoryBootLevel
= 0;
2698 /* find boot level from dpm table */
2699 result
= fiji_find_boot_level(&(data
->dpm_table
.sclk_table
),
2700 data
->vbios_boot_state
.sclk_bootup_value
,
2701 (uint32_t *)&(table
->GraphicsBootLevel
));
2703 result
= fiji_find_boot_level(&(data
->dpm_table
.mclk_table
),
2704 data
->vbios_boot_state
.mclk_bootup_value
,
2705 (uint32_t *)&(table
->MemoryBootLevel
));
2707 table
->BootVddc
= data
->vbios_boot_state
.vddc_bootup_value
*
2709 table
->BootVddci
= data
->vbios_boot_state
.vddci_bootup_value
*
2711 table
->BootMVdd
= data
->vbios_boot_state
.mvdd_bootup_value
*
2714 CONVERT_FROM_HOST_TO_SMC_US(table
->BootVddc
);
2715 CONVERT_FROM_HOST_TO_SMC_US(table
->BootVddci
);
2716 CONVERT_FROM_HOST_TO_SMC_US(table
->BootMVdd
);
2721 static int fiji_populate_smc_initailial_state(struct pp_hwmgr
*hwmgr
)
2723 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2724 struct phm_ppt_v1_information
*table_info
=
2725 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2726 uint8_t count
, level
;
2728 count
= (uint8_t)(table_info
->vdd_dep_on_sclk
->count
);
2729 for (level
= 0; level
< count
; level
++) {
2730 if(table_info
->vdd_dep_on_sclk
->entries
[level
].clk
>=
2731 data
->vbios_boot_state
.sclk_bootup_value
) {
2732 data
->smc_state_table
.GraphicsBootLevel
= level
;
2737 count
= (uint8_t)(table_info
->vdd_dep_on_mclk
->count
);
2738 for (level
= 0; level
< count
; level
++) {
2739 if(table_info
->vdd_dep_on_mclk
->entries
[level
].clk
>=
2740 data
->vbios_boot_state
.mclk_bootup_value
) {
2741 data
->smc_state_table
.MemoryBootLevel
= level
;
2749 static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr
*hwmgr
)
2751 uint32_t ro
, efuse
, efuse2
, clock_freq
, volt_without_cks
,
2752 volt_with_cks
, value
;
2753 uint16_t clock_freq_u16
;
2754 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2755 uint8_t type
, i
, j
, cks_setting
, stretch_amount
, stretch_amount2
,
2757 struct phm_ppt_v1_information
*table_info
=
2758 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2759 struct phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
=
2760 table_info
->vdd_dep_on_sclk
;
2762 stretch_amount
= (uint8_t)table_info
->cac_dtp_table
->usClockStretchAmount
;
2764 /* Read SMU_Eefuse to read and calculate RO and determine
2765 * if the part is SS or FF. if RO >= 1660MHz, part is FF.
2767 efuse
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
2768 ixSMU_EFUSE_0
+ (146 * 4));
2769 efuse2
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
2770 ixSMU_EFUSE_0
+ (148 * 4));
2771 efuse
&= 0xFF000000;
2772 efuse
= efuse
>> 24;
2776 ro
= (2300 - 1350) * efuse
/ 255 + 1350;
2778 ro
= (2500 - 1000) * efuse
/ 255 + 1000;
2785 /* Populate Stretch amount */
2786 data
->smc_state_table
.ClockStretcherAmount
= stretch_amount
;
2788 /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
2789 for (i
= 0; i
< sclk_table
->count
; i
++) {
2790 data
->smc_state_table
.Sclk_CKS_masterEn0_7
|=
2791 sclk_table
->entries
[i
].cks_enable
<< i
;
2792 volt_without_cks
= (uint32_t)((14041 *
2793 (sclk_table
->entries
[i
].clk
/100) / 10000 + 3571 + 75 - ro
) * 1000 /
2794 (4026 - (13924 * (sclk_table
->entries
[i
].clk
/100) / 10000)));
2795 volt_with_cks
= (uint32_t)((13946 *
2796 (sclk_table
->entries
[i
].clk
/100) / 10000 + 3320 + 45 - ro
) * 1000 /
2797 (3664 - (11454 * (sclk_table
->entries
[i
].clk
/100) / 10000)));
2798 if (volt_without_cks
>= volt_with_cks
)
2799 volt_offset
= (uint8_t)(((volt_without_cks
- volt_with_cks
+
2800 sclk_table
->entries
[i
].cks_voffset
) * 100 / 625) + 1);
2801 data
->smc_state_table
.Sclk_voltageOffset
[i
] = volt_offset
;
2804 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
2805 STRETCH_ENABLE
, 0x0);
2806 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
2808 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
2810 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
2813 /* Populate CKS Lookup Table */
2814 if (stretch_amount
== 1 || stretch_amount
== 2 || stretch_amount
== 5)
2815 stretch_amount2
= 0;
2816 else if (stretch_amount
== 3 || stretch_amount
== 4)
2817 stretch_amount2
= 1;
2819 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
2820 PHM_PlatformCaps_ClockStretcher
);
2821 PP_ASSERT_WITH_CODE(false,
2822 "Stretch Amount in PPTable not supported\n",
2826 value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
2828 value
&= 0xFFC2FF87;
2829 data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].minFreq
=
2830 fiji_clock_stretcher_lookup_table
[stretch_amount2
][0];
2831 data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].maxFreq
=
2832 fiji_clock_stretcher_lookup_table
[stretch_amount2
][1];
2833 clock_freq_u16
= (uint16_t)(PP_SMC_TO_HOST_UL(data
->smc_state_table
.
2834 GraphicsLevel
[data
->smc_state_table
.GraphicsDpmLevelCount
- 1].
2835 SclkFrequency
) / 100);
2836 if (fiji_clock_stretcher_lookup_table
[stretch_amount2
][0] <
2838 fiji_clock_stretcher_lookup_table
[stretch_amount2
][1] >
2840 /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
2841 value
|= (fiji_clock_stretcher_lookup_table
[stretch_amount2
][3]) << 16;
2842 /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
2843 value
|= (fiji_clock_stretcher_lookup_table
[stretch_amount2
][2]) << 18;
2844 /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
2845 value
|= (fiji_clock_stretch_amount_conversion
2846 [fiji_clock_stretcher_lookup_table
[stretch_amount2
][3]]
2847 [stretch_amount
]) << 3;
2849 CONVERT_FROM_HOST_TO_SMC_US(data
->smc_state_table
.CKS_LOOKUPTable
.
2850 CKS_LOOKUPTableEntry
[0].minFreq
);
2851 CONVERT_FROM_HOST_TO_SMC_US(data
->smc_state_table
.CKS_LOOKUPTable
.
2852 CKS_LOOKUPTableEntry
[0].maxFreq
);
2853 data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].setting
=
2854 fiji_clock_stretcher_lookup_table
[stretch_amount2
][2] & 0x7F;
2855 data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].setting
|=
2856 (fiji_clock_stretcher_lookup_table
[stretch_amount2
][3]) << 7;
2858 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
2859 ixPWR_CKS_CNTL
, value
);
2861 /* Populate DDT Lookup Table */
2862 for (i
= 0; i
< 4; i
++) {
2863 /* Assign the minimum and maximum VID stored
2864 * in the last row of Clock Stretcher Voltage Table.
2866 data
->smc_state_table
.ClockStretcherDataTable
.
2867 ClockStretcherDataTableEntry
[i
].minVID
=
2868 (uint8_t) fiji_clock_stretcher_ddt_table
[type
][i
][2];
2869 data
->smc_state_table
.ClockStretcherDataTable
.
2870 ClockStretcherDataTableEntry
[i
].maxVID
=
2871 (uint8_t) fiji_clock_stretcher_ddt_table
[type
][i
][3];
2872 /* Loop through each SCLK and check the frequency
2873 * to see if it lies within the frequency for clock stretcher.
2875 for (j
= 0; j
< data
->smc_state_table
.GraphicsDpmLevelCount
; j
++) {
2877 clock_freq
= PP_SMC_TO_HOST_UL(
2878 data
->smc_state_table
.GraphicsLevel
[j
].SclkFrequency
);
2879 /* Check the allowed frequency against the sclk level[j].
2880 * Sclk's endianness has already been converted,
2881 * and it's in 10Khz unit,
2882 * as opposed to Data table, which is in Mhz unit.
2885 (fiji_clock_stretcher_ddt_table
[type
][i
][0]) * 100) {
2888 (fiji_clock_stretcher_ddt_table
[type
][i
][1]) * 100)
2891 data
->smc_state_table
.ClockStretcherDataTable
.
2892 ClockStretcherDataTableEntry
[i
].setting
|= cks_setting
<< (j
* 2);
2894 CONVERT_FROM_HOST_TO_SMC_US(data
->smc_state_table
.
2895 ClockStretcherDataTable
.
2896 ClockStretcherDataTableEntry
[i
].setting
);
2899 value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixPWR_CKS_CNTL
);
2900 value
&= 0xFFFFFFFE;
2901 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixPWR_CKS_CNTL
, value
);
2907 * Populates the SMC VRConfig field in DPM table.
2909 * @param hwmgr the address of the hardware manager
2910 * @param table the SMC DPM table structure to be populated
2913 static int fiji_populate_vr_config(struct pp_hwmgr
*hwmgr
,
2914 struct SMU73_Discrete_DpmTable
*table
)
2916 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2919 config
= VR_MERGED_WITH_VDDC
;
2920 table
->VRConfig
|= (config
<< VRCONF_VDDGFX_SHIFT
);
2922 /* Set Vddc Voltage Controller */
2923 if(FIJI_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
2924 config
= VR_SVI2_PLANE_1
;
2925 table
->VRConfig
|= config
;
2927 PP_ASSERT_WITH_CODE(false,
2928 "VDDC should be on SVI2 control in merged mode!",);
2930 /* Set Vddci Voltage Controller */
2931 if(FIJI_VOLTAGE_CONTROL_BY_SVID2
== data
->vddci_control
) {
2932 config
= VR_SVI2_PLANE_2
; /* only in merged mode */
2933 table
->VRConfig
|= (config
<< VRCONF_VDDCI_SHIFT
);
2934 } else if (FIJI_VOLTAGE_CONTROL_BY_GPIO
== data
->vddci_control
) {
2935 config
= VR_SMIO_PATTERN_1
;
2936 table
->VRConfig
|= (config
<< VRCONF_VDDCI_SHIFT
);
2938 config
= VR_STATIC_VOLTAGE
;
2939 table
->VRConfig
|= (config
<< VRCONF_VDDCI_SHIFT
);
2941 /* Set Mvdd Voltage Controller */
2942 if(FIJI_VOLTAGE_CONTROL_BY_SVID2
== data
->mvdd_control
) {
2943 config
= VR_SVI2_PLANE_2
;
2944 table
->VRConfig
|= (config
<< VRCONF_MVDD_SHIFT
);
2945 } else if(FIJI_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
2946 config
= VR_SMIO_PATTERN_2
;
2947 table
->VRConfig
|= (config
<< VRCONF_MVDD_SHIFT
);
2949 config
= VR_STATIC_VOLTAGE
;
2950 table
->VRConfig
|= (config
<< VRCONF_MVDD_SHIFT
);
2957 * Initializes the SMC table and uploads it
2959 * @param hwmgr the address of the powerplay hardware manager.
2960 * @param pInput the pointer to input data (PowerState)
2963 static int fiji_init_smc_table(struct pp_hwmgr
*hwmgr
)
2966 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2967 struct phm_ppt_v1_information
*table_info
=
2968 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2969 struct SMU73_Discrete_DpmTable
*table
= &(data
->smc_state_table
);
2970 const struct fiji_ulv_parm
*ulv
= &(data
->ulv
);
2972 struct pp_atomctrl_gpio_pin_assignment gpio_pin
;
2974 result
= fiji_setup_default_dpm_tables(hwmgr
);
2975 PP_ASSERT_WITH_CODE(0 == result
,
2976 "Failed to setup default DPM tables!", return result
);
2978 if(FIJI_VOLTAGE_CONTROL_NONE
!= data
->voltage_control
)
2979 fiji_populate_smc_voltage_tables(hwmgr
, table
);
2981 table
->SystemFlags
= 0;
2983 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2984 PHM_PlatformCaps_AutomaticDCTransition
))
2985 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GPIO_DC
;
2987 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2988 PHM_PlatformCaps_StepVddc
))
2989 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_STEPVDDC
;
2991 if (data
->is_memory_gddr5
)
2992 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GDDR5
;
2994 if (ulv
->ulv_supported
&& table_info
->us_ulv_voltage_offset
) {
2995 result
= fiji_populate_ulv_state(hwmgr
, table
);
2996 PP_ASSERT_WITH_CODE(0 == result
,
2997 "Failed to initialize ULV state!", return result
);
2998 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
2999 ixCG_ULV_PARAMETER
, ulv
->cg_ulv_parameter
);
3002 result
= fiji_populate_smc_link_level(hwmgr
, table
);
3003 PP_ASSERT_WITH_CODE(0 == result
,
3004 "Failed to initialize Link Level!", return result
);
3006 result
= fiji_populate_all_graphic_levels(hwmgr
);
3007 PP_ASSERT_WITH_CODE(0 == result
,
3008 "Failed to initialize Graphics Level!", return result
);
3010 result
= fiji_populate_all_memory_levels(hwmgr
);
3011 PP_ASSERT_WITH_CODE(0 == result
,
3012 "Failed to initialize Memory Level!", return result
);
3014 result
= fiji_populate_smc_acpi_level(hwmgr
, table
);
3015 PP_ASSERT_WITH_CODE(0 == result
,
3016 "Failed to initialize ACPI Level!", return result
);
3018 result
= fiji_populate_smc_vce_level(hwmgr
, table
);
3019 PP_ASSERT_WITH_CODE(0 == result
,
3020 "Failed to initialize VCE Level!", return result
);
3022 result
= fiji_populate_smc_acp_level(hwmgr
, table
);
3023 PP_ASSERT_WITH_CODE(0 == result
,
3024 "Failed to initialize ACP Level!", return result
);
3026 result
= fiji_populate_smc_samu_level(hwmgr
, table
);
3027 PP_ASSERT_WITH_CODE(0 == result
,
3028 "Failed to initialize SAMU Level!", return result
);
3030 /* Since only the initial state is completely set up at this point
3031 * (the other states are just copies of the boot state) we only
3032 * need to populate the ARB settings for the initial state.
3034 result
= fiji_program_memory_timing_parameters(hwmgr
);
3035 PP_ASSERT_WITH_CODE(0 == result
,
3036 "Failed to Write ARB settings for the initial state.", return result
);
3038 result
= fiji_populate_smc_uvd_level(hwmgr
, table
);
3039 PP_ASSERT_WITH_CODE(0 == result
,
3040 "Failed to initialize UVD Level!", return result
);
3042 result
= fiji_populate_smc_boot_level(hwmgr
, table
);
3043 PP_ASSERT_WITH_CODE(0 == result
,
3044 "Failed to initialize Boot Level!", return result
);
3046 result
= fiji_populate_smc_initailial_state(hwmgr
);
3047 PP_ASSERT_WITH_CODE(0 == result
,
3048 "Failed to initialize Boot State!", return result
);
3050 result
= fiji_populate_bapm_parameters_in_dpm_table(hwmgr
);
3051 PP_ASSERT_WITH_CODE(0 == result
,
3052 "Failed to populate BAPM Parameters!", return result
);
3054 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3055 PHM_PlatformCaps_ClockStretcher
)) {
3056 result
= fiji_populate_clock_stretcher_data_table(hwmgr
);
3057 PP_ASSERT_WITH_CODE(0 == result
,
3058 "Failed to populate Clock Stretcher Data Table!",
3062 table
->GraphicsVoltageChangeEnable
= 1;
3063 table
->GraphicsThermThrottleEnable
= 1;
3064 table
->GraphicsInterval
= 1;
3065 table
->VoltageInterval
= 1;
3066 table
->ThermalInterval
= 1;
3067 table
->TemperatureLimitHigh
=
3068 table_info
->cac_dtp_table
->usTargetOperatingTemp
*
3069 FIJI_Q88_FORMAT_CONVERSION_UNIT
;
3070 table
->TemperatureLimitLow
=
3071 (table_info
->cac_dtp_table
->usTargetOperatingTemp
- 1) *
3072 FIJI_Q88_FORMAT_CONVERSION_UNIT
;
3073 table
->MemoryVoltageChangeEnable
= 1;
3074 table
->MemoryInterval
= 1;
3075 table
->VoltageResponseTime
= 0;
3076 table
->PhaseResponseTime
= 0;
3077 table
->MemoryThermThrottleEnable
= 1;
3078 table
->PCIeBootLinkLevel
= 0; /* 0:Gen1 1:Gen2 2:Gen3*/
3079 table
->PCIeGenInterval
= 1;
3080 table
->VRConfig
= 0;
3082 result
= fiji_populate_vr_config(hwmgr
, table
);
3083 PP_ASSERT_WITH_CODE(0 == result
,
3084 "Failed to populate VRConfig setting!", return result
);
3086 table
->ThermGpio
= 17;
3087 table
->SclkStepSize
= 0x4000;
3089 if (atomctrl_get_pp_assign_pin(hwmgr
, VDDC_VRHOT_GPIO_PINID
, &gpio_pin
)) {
3090 table
->VRHotGpio
= gpio_pin
.uc_gpio_pin_bit_shift
;
3091 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3092 PHM_PlatformCaps_RegulatorHot
);
3094 table
->VRHotGpio
= FIJI_UNUSED_GPIO_PIN
;
3095 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3096 PHM_PlatformCaps_RegulatorHot
);
3099 if (atomctrl_get_pp_assign_pin(hwmgr
, PP_AC_DC_SWITCH_GPIO_PINID
,
3101 table
->AcDcGpio
= gpio_pin
.uc_gpio_pin_bit_shift
;
3102 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3103 PHM_PlatformCaps_AutomaticDCTransition
);
3105 table
->AcDcGpio
= FIJI_UNUSED_GPIO_PIN
;
3106 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3107 PHM_PlatformCaps_AutomaticDCTransition
);
3110 /* Thermal Output GPIO */
3111 if (atomctrl_get_pp_assign_pin(hwmgr
, THERMAL_INT_OUTPUT_GPIO_PINID
,
3113 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3114 PHM_PlatformCaps_ThermalOutGPIO
);
3116 table
->ThermOutGpio
= gpio_pin
.uc_gpio_pin_bit_shift
;
3118 /* For porlarity read GPIOPAD_A with assigned Gpio pin
3119 * since VBIOS will program this register to set 'inactive state',
3120 * driver can then determine 'active state' from this and
3121 * program SMU with correct polarity
3123 table
->ThermOutPolarity
= (0 == (cgs_read_register(hwmgr
->device
, mmGPIOPAD_A
) &
3124 (1 << gpio_pin
.uc_gpio_pin_bit_shift
))) ? 1:0;
3125 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_ONLY
;
3127 /* if required, combine VRHot/PCC with thermal out GPIO */
3128 if(phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3129 PHM_PlatformCaps_RegulatorHot
) &&
3130 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3131 PHM_PlatformCaps_CombinePCCWithThermalSignal
))
3132 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_VRHOT
;
3134 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3135 PHM_PlatformCaps_ThermalOutGPIO
);
3136 table
->ThermOutGpio
= 17;
3137 table
->ThermOutPolarity
= 1;
3138 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_DISABLE
;
3141 for (i
= 0; i
< SMU73_MAX_ENTRIES_SMIO
; i
++)
3142 table
->Smio
[i
] = PP_HOST_TO_SMC_UL(table
->Smio
[i
]);
3144 CONVERT_FROM_HOST_TO_SMC_UL(table
->SystemFlags
);
3145 CONVERT_FROM_HOST_TO_SMC_UL(table
->VRConfig
);
3146 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask1
);
3147 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask2
);
3148 CONVERT_FROM_HOST_TO_SMC_UL(table
->SclkStepSize
);
3149 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitHigh
);
3150 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitLow
);
3151 CONVERT_FROM_HOST_TO_SMC_US(table
->VoltageResponseTime
);
3152 CONVERT_FROM_HOST_TO_SMC_US(table
->PhaseResponseTime
);
3154 /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
3155 result
= fiji_copy_bytes_to_smc(hwmgr
->smumgr
,
3156 data
->dpm_table_start
+
3157 offsetof(SMU73_Discrete_DpmTable
, SystemFlags
),
3158 (uint8_t *)&(table
->SystemFlags
),
3159 sizeof(SMU73_Discrete_DpmTable
) - 3 * sizeof(SMU73_PIDController
),
3161 PP_ASSERT_WITH_CODE(0 == result
,
3162 "Failed to upload dpm data to SMC memory!", return result
);
3168 * Initialize the ARB DRAM timing table's index field.
3170 * @param hwmgr the address of the powerplay hardware manager.
3173 static int fiji_init_arb_table_index(struct pp_hwmgr
*hwmgr
)
3175 const struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3179 /* This is a read-modify-write on the first byte of the ARB table.
3180 * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure
3181 * is the field 'current'.
3182 * This solution is ugly, but we never write the whole table only
3183 * individual fields in it.
3184 * In reality this field should not be in that structure
3185 * but in a soft register.
3187 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
3188 data
->arb_table_start
, &tmp
, data
->sram_end
);
3194 tmp
|= ((uint32_t)MC_CG_ARB_FREQ_F1
) << 24;
3196 return fiji_write_smc_sram_dword(hwmgr
->smumgr
,
3197 data
->arb_table_start
, tmp
, data
->sram_end
);
3200 static int fiji_enable_vrhot_gpio_interrupt(struct pp_hwmgr
*hwmgr
)
3202 if(phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3203 PHM_PlatformCaps_RegulatorHot
))
3204 return smum_send_msg_to_smc(hwmgr
->smumgr
,
3205 PPSMC_MSG_EnableVRHotGPIOInterrupt
);
3210 static int fiji_enable_sclk_control(struct pp_hwmgr
*hwmgr
)
3212 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
,
3213 SCLK_PWRMGT_OFF
, 0);
3217 static int fiji_enable_ulv(struct pp_hwmgr
*hwmgr
)
3219 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3220 struct fiji_ulv_parm
*ulv
= &(data
->ulv
);
3222 if (ulv
->ulv_supported
)
3223 return smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_EnableULV
);
3228 static int fiji_disable_ulv(struct pp_hwmgr
*hwmgr
)
3230 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3231 struct fiji_ulv_parm
*ulv
= &(data
->ulv
);
3233 if (ulv
->ulv_supported
)
3234 return smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_DisableULV
);
3239 static int fiji_enable_deep_sleep_master_switch(struct pp_hwmgr
*hwmgr
)
3241 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3242 PHM_PlatformCaps_SclkDeepSleep
)) {
3243 if (smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_MASTER_DeepSleep_ON
))
3244 PP_ASSERT_WITH_CODE(false,
3245 "Attempt to enable Master Deep Sleep switch failed!",
3248 if (smum_send_msg_to_smc(hwmgr
->smumgr
,
3249 PPSMC_MSG_MASTER_DeepSleep_OFF
)) {
3250 PP_ASSERT_WITH_CODE(false,
3251 "Attempt to disable Master Deep Sleep switch failed!",
3259 static int fiji_disable_deep_sleep_master_switch(struct pp_hwmgr
*hwmgr
)
3261 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3262 PHM_PlatformCaps_SclkDeepSleep
)) {
3263 if (smum_send_msg_to_smc(hwmgr
->smumgr
,
3264 PPSMC_MSG_MASTER_DeepSleep_OFF
)) {
3265 PP_ASSERT_WITH_CODE(false,
3266 "Attempt to disable Master Deep Sleep switch failed!",
3274 static int fiji_enable_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
3276 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3277 uint32_t val
, val0
, val2
;
3278 uint32_t i
, cpl_cntl
, cpl_threshold
, mc_threshold
;
3280 /* enable SCLK dpm */
3281 if(!data
->sclk_dpm_key_disabled
)
3282 PP_ASSERT_WITH_CODE(
3283 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_DPM_Enable
)),
3284 "Failed to enable SCLK DPM during DPM Start Function!",
3287 /* enable MCLK dpm */
3288 if(0 == data
->mclk_dpm_key_disabled
) {
3292 /* Read per MCD tile (0 - 7) */
3293 for (i
= 0; i
< 8; i
++) {
3294 PHM_WRITE_FIELD(hwmgr
->device
, MC_CONFIG_MCD
, MC_RD_ENABLE
, i
);
3295 val
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_RESERVE_0_S
) & 0xf0000000;
3296 if (0xf0000000 != val
) {
3297 /* count number of MCQ that has channel(s) enabled */
3299 /* only harvest 3 or full 4 supported */
3300 mc_threshold
= val
? 3 : 4;
3303 PP_ASSERT_WITH_CODE(0 != cpl_threshold
,
3304 "Number of MCQ is zero!", return -EINVAL
;);
3306 mc_threshold
= ((mc_threshold
& LCAC_MC0_CNTL__MC0_THRESHOLD_MASK
) <<
3307 LCAC_MC0_CNTL__MC0_THRESHOLD__SHIFT
) |
3308 LCAC_MC0_CNTL__MC0_ENABLE_MASK
;
3309 cpl_cntl
= ((cpl_threshold
& LCAC_CPL_CNTL__CPL_THRESHOLD_MASK
) <<
3310 LCAC_CPL_CNTL__CPL_THRESHOLD__SHIFT
) |
3311 LCAC_CPL_CNTL__CPL_ENABLE_MASK
;
3312 cpl_cntl
= (cpl_cntl
| (8 << LCAC_CPL_CNTL__CPL_BLOCK_ID__SHIFT
));
3313 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3314 ixLCAC_MC0_CNTL
, mc_threshold
);
3315 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3316 ixLCAC_MC1_CNTL
, mc_threshold
);
3317 if (8 == cpl_threshold
) {
3318 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3319 ixLCAC_MC2_CNTL
, mc_threshold
);
3320 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3321 ixLCAC_MC3_CNTL
, mc_threshold
);
3322 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3323 ixLCAC_MC4_CNTL
, mc_threshold
);
3324 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3325 ixLCAC_MC5_CNTL
, mc_threshold
);
3326 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3327 ixLCAC_MC6_CNTL
, mc_threshold
);
3328 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3329 ixLCAC_MC7_CNTL
, mc_threshold
);
3331 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3332 ixLCAC_CPL_CNTL
, cpl_cntl
);
3336 mc_threshold
= mc_threshold
|
3337 (1 << LCAC_MC0_CNTL__MC0_SIGNAL_ID__SHIFT
);
3338 cpl_cntl
= cpl_cntl
| (1 << LCAC_CPL_CNTL__CPL_SIGNAL_ID__SHIFT
);
3339 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3340 ixLCAC_MC0_CNTL
, mc_threshold
);
3341 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3342 ixLCAC_MC1_CNTL
, mc_threshold
);
3343 if (8 == cpl_threshold
) {
3344 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3345 ixLCAC_MC2_CNTL
, mc_threshold
);
3346 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3347 ixLCAC_MC3_CNTL
, mc_threshold
);
3348 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3349 ixLCAC_MC4_CNTL
, mc_threshold
);
3350 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3351 ixLCAC_MC5_CNTL
, mc_threshold
);
3352 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3353 ixLCAC_MC6_CNTL
, mc_threshold
);
3354 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3355 ixLCAC_MC7_CNTL
, mc_threshold
);
3357 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3358 ixLCAC_CPL_CNTL
, cpl_cntl
);
3360 /* Program CAC_EN per MCD (0-7) Tile */
3361 val0
= val
= cgs_read_register(hwmgr
->device
, mmMC_CONFIG_MCD
);
3362 val
&= ~(MC_CONFIG_MCD__MCD0_WR_ENABLE_MASK
|
3363 MC_CONFIG_MCD__MCD1_WR_ENABLE_MASK
|
3364 MC_CONFIG_MCD__MCD2_WR_ENABLE_MASK
|
3365 MC_CONFIG_MCD__MCD3_WR_ENABLE_MASK
|
3366 MC_CONFIG_MCD__MCD4_WR_ENABLE_MASK
|
3367 MC_CONFIG_MCD__MCD5_WR_ENABLE_MASK
|
3368 MC_CONFIG_MCD__MCD6_WR_ENABLE_MASK
|
3369 MC_CONFIG_MCD__MCD7_WR_ENABLE_MASK
|
3370 MC_CONFIG_MCD__MC_RD_ENABLE_MASK
);
3372 for (i
= 0; i
< 8; i
++) {
3373 /* Enable MCD i Tile read & write */
3374 val2
= (val
| (i
<< MC_CONFIG_MCD__MC_RD_ENABLE__SHIFT
) |
3376 cgs_write_register(hwmgr
->device
, mmMC_CONFIG_MCD
, val2
);
3377 /* Enbale CAC_ON MCD i Tile */
3378 val2
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_CNTL
);
3379 val2
|= MC_SEQ_CNTL__CAC_EN_MASK
;
3380 cgs_write_register(hwmgr
->device
, mmMC_SEQ_CNTL
, val2
);
3382 /* Set MC_CONFIG_MCD back to its default setting val0 */
3383 cgs_write_register(hwmgr
->device
, mmMC_CONFIG_MCD
, val0
);
3385 PP_ASSERT_WITH_CODE(
3386 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
3387 PPSMC_MSG_MCLKDPM_Enable
)),
3388 "Failed to enable MCLK DPM during DPM Start Function!",
3394 static int fiji_start_dpm(struct pp_hwmgr
*hwmgr
)
3396 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3398 /*enable general power management */
3399 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
,
3400 GLOBAL_PWRMGT_EN
, 1);
3401 /* enable sclk deep sleep */
3402 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
,
3404 /* prepare for PCIE DPM */
3405 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3406 data
->soft_regs_start
+ offsetof(SMU73_SoftRegisters
,
3407 VoltageChangeTimeout
), 0x1000);
3408 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__PCIE
,
3409 SWRST_COMMAND_1
, RESETLC
, 0x0);
3411 PP_ASSERT_WITH_CODE(
3412 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
3413 PPSMC_MSG_Voltage_Cntl_Enable
)),
3414 "Failed to enable voltage DPM during DPM Start Function!",
3417 if (fiji_enable_sclk_mclk_dpm(hwmgr
)) {
3418 printk(KERN_ERR
"Failed to enable Sclk DPM and Mclk DPM!");
3422 /* enable PCIE dpm */
3423 if(!data
->pcie_dpm_key_disabled
) {
3424 PP_ASSERT_WITH_CODE(
3425 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
3426 PPSMC_MSG_PCIeDPM_Enable
)),
3427 "Failed to enable pcie DPM during DPM Start Function!",
3434 static int fiji_disable_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
3436 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3438 /* disable SCLK dpm */
3439 if (!data
->sclk_dpm_key_disabled
)
3440 PP_ASSERT_WITH_CODE(
3441 (smum_send_msg_to_smc(hwmgr
->smumgr
,
3442 PPSMC_MSG_DPM_Disable
) == 0),
3443 "Failed to disable SCLK DPM!",
3446 /* disable MCLK dpm */
3447 if (!data
->mclk_dpm_key_disabled
) {
3448 PP_ASSERT_WITH_CODE(
3449 (smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3450 PPSMC_MSG_MCLKDPM_SetEnabledMask
, 1) == 0),
3451 "Failed to force MCLK DPM0!",
3454 PP_ASSERT_WITH_CODE(
3455 (smum_send_msg_to_smc(hwmgr
->smumgr
,
3456 PPSMC_MSG_MCLKDPM_Disable
) == 0),
3457 "Failed to disable MCLK DPM!",
3464 static int fiji_stop_dpm(struct pp_hwmgr
*hwmgr
)
3466 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3468 /* disable general power management */
3469 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
,
3470 GLOBAL_PWRMGT_EN
, 0);
3471 /* disable sclk deep sleep */
3472 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
,
3475 /* disable PCIE dpm */
3476 if (!data
->pcie_dpm_key_disabled
) {
3477 PP_ASSERT_WITH_CODE(
3478 (smum_send_msg_to_smc(hwmgr
->smumgr
,
3479 PPSMC_MSG_PCIeDPM_Disable
) == 0),
3480 "Failed to disable pcie DPM during DPM Stop Function!",
3484 if (fiji_disable_sclk_mclk_dpm(hwmgr
)) {
3485 printk(KERN_ERR
"Failed to disable Sclk DPM and Mclk DPM!");
3489 PP_ASSERT_WITH_CODE(
3490 (smum_send_msg_to_smc(hwmgr
->smumgr
,
3491 PPSMC_MSG_Voltage_Cntl_Disable
) == 0),
3492 "Failed to disable voltage DPM during DPM Stop Function!",
3498 static void fiji_set_dpm_event_sources(struct pp_hwmgr
*hwmgr
,
3502 enum DPM_EVENT_SRC src
;
3506 printk(KERN_ERR
"Unknown throttling event sources.");
3512 case (1 << PHM_AutoThrottleSource_Thermal
):
3514 src
= DPM_EVENT_SRC_DIGITAL
;
3516 case (1 << PHM_AutoThrottleSource_External
):
3518 src
= DPM_EVENT_SRC_EXTERNAL
;
3520 case (1 << PHM_AutoThrottleSource_External
) |
3521 (1 << PHM_AutoThrottleSource_Thermal
):
3523 src
= DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL
;
3526 /* Order matters - don't enable thermal protection for the wrong source. */
3528 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, CG_THERMAL_CTRL
,
3529 DPM_EVENT_SRC
, src
);
3530 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
,
3531 THERMAL_PROTECTION_DIS
,
3532 !phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3533 PHM_PlatformCaps_ThermalController
));
3535 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
,
3536 THERMAL_PROTECTION_DIS
, 1);
3539 static int fiji_enable_auto_throttle_source(struct pp_hwmgr
*hwmgr
,
3540 PHM_AutoThrottleSource source
)
3542 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3544 if (!(data
->active_auto_throttle_sources
& (1 << source
))) {
3545 data
->active_auto_throttle_sources
|= 1 << source
;
3546 fiji_set_dpm_event_sources(hwmgr
, data
->active_auto_throttle_sources
);
3551 static int fiji_enable_thermal_auto_throttle(struct pp_hwmgr
*hwmgr
)
3553 return fiji_enable_auto_throttle_source(hwmgr
, PHM_AutoThrottleSource_Thermal
);
3556 static int fiji_disable_auto_throttle_source(struct pp_hwmgr
*hwmgr
,
3557 PHM_AutoThrottleSource source
)
3559 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3561 if (data
->active_auto_throttle_sources
& (1 << source
)) {
3562 data
->active_auto_throttle_sources
&= ~(1 << source
);
3563 fiji_set_dpm_event_sources(hwmgr
, data
->active_auto_throttle_sources
);
3568 static int fiji_disable_thermal_auto_throttle(struct pp_hwmgr
*hwmgr
)
3570 return fiji_disable_auto_throttle_source(hwmgr
, PHM_AutoThrottleSource_Thermal
);
3573 static int fiji_enable_dpm_tasks(struct pp_hwmgr
*hwmgr
)
3575 int tmp_result
, result
= 0;
3577 tmp_result
= (!fiji_is_dpm_running(hwmgr
))? 0 : -1;
3578 PP_ASSERT_WITH_CODE(result
== 0,
3579 "DPM is already running right now, no need to enable DPM!",
3582 if (fiji_voltage_control(hwmgr
)) {
3583 tmp_result
= fiji_enable_voltage_control(hwmgr
);
3584 PP_ASSERT_WITH_CODE(tmp_result
== 0,
3585 "Failed to enable voltage control!",
3586 result
= tmp_result
);
3589 if (fiji_voltage_control(hwmgr
)) {
3590 tmp_result
= fiji_construct_voltage_tables(hwmgr
);
3591 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3592 "Failed to contruct voltage tables!",
3593 result
= tmp_result
);
3596 tmp_result
= fiji_initialize_mc_reg_table(hwmgr
);
3597 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3598 "Failed to initialize MC reg table!", result
= tmp_result
);
3600 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3601 PHM_PlatformCaps_EngineSpreadSpectrumSupport
))
3602 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3603 GENERAL_PWRMGT
, DYN_SPREAD_SPECTRUM_EN
, 1);
3605 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3606 PHM_PlatformCaps_ThermalController
))
3607 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3608 GENERAL_PWRMGT
, THERMAL_PROTECTION_DIS
, 0);
3610 tmp_result
= fiji_program_static_screen_threshold_parameters(hwmgr
);
3611 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3612 "Failed to program static screen threshold parameters!",
3613 result
= tmp_result
);
3615 tmp_result
= fiji_enable_display_gap(hwmgr
);
3616 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3617 "Failed to enable display gap!", result
= tmp_result
);
3619 tmp_result
= fiji_program_voting_clients(hwmgr
);
3620 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3621 "Failed to program voting clients!", result
= tmp_result
);
3623 tmp_result
= fiji_process_firmware_header(hwmgr
);
3624 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3625 "Failed to process firmware header!", result
= tmp_result
);
3627 tmp_result
= fiji_initial_switch_from_arbf0_to_f1(hwmgr
);
3628 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3629 "Failed to initialize switch from ArbF0 to F1!",
3630 result
= tmp_result
);
3632 tmp_result
= fiji_init_smc_table(hwmgr
);
3633 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3634 "Failed to initialize SMC table!", result
= tmp_result
);
3636 tmp_result
= fiji_init_arb_table_index(hwmgr
);
3637 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3638 "Failed to initialize ARB table index!", result
= tmp_result
);
3640 tmp_result
= fiji_populate_pm_fuses(hwmgr
);
3641 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3642 "Failed to populate PM fuses!", result
= tmp_result
);
3644 tmp_result
= fiji_enable_vrhot_gpio_interrupt(hwmgr
);
3645 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3646 "Failed to enable VR hot GPIO interrupt!", result
= tmp_result
);
3648 tmp_result
= tonga_notify_smc_display_change(hwmgr
, false);
3649 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3650 "Failed to notify no display!", result
= tmp_result
);
3652 tmp_result
= fiji_enable_sclk_control(hwmgr
);
3653 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3654 "Failed to enable SCLK control!", result
= tmp_result
);
3656 tmp_result
= fiji_enable_ulv(hwmgr
);
3657 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3658 "Failed to enable ULV!", result
= tmp_result
);
3660 tmp_result
= fiji_enable_deep_sleep_master_switch(hwmgr
);
3661 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3662 "Failed to enable deep sleep master switch!", result
= tmp_result
);
3664 tmp_result
= fiji_start_dpm(hwmgr
);
3665 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3666 "Failed to start DPM!", result
= tmp_result
);
3668 tmp_result
= fiji_enable_smc_cac(hwmgr
);
3669 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3670 "Failed to enable SMC CAC!", result
= tmp_result
);
3672 tmp_result
= fiji_enable_power_containment(hwmgr
);
3673 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3674 "Failed to enable power containment!", result
= tmp_result
);
3676 tmp_result
= fiji_power_control_set_level(hwmgr
);
3677 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3678 "Failed to power control set level!", result
= tmp_result
);
3680 tmp_result
= fiji_enable_thermal_auto_throttle(hwmgr
);
3681 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3682 "Failed to enable thermal auto throttle!", result
= tmp_result
);
3687 static int fiji_disable_dpm_tasks(struct pp_hwmgr
*hwmgr
)
3689 int tmp_result
, result
= 0;
3691 tmp_result
= (fiji_is_dpm_running(hwmgr
)) ? 0 : -1;
3692 PP_ASSERT_WITH_CODE(tmp_result
== 0,
3693 "DPM is not running right now, no need to disable DPM!",
3696 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3697 PHM_PlatformCaps_ThermalController
))
3698 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3699 GENERAL_PWRMGT
, THERMAL_PROTECTION_DIS
, 1);
3701 tmp_result
= fiji_disable_power_containment(hwmgr
);
3702 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3703 "Failed to disable power containment!", result
= tmp_result
);
3705 tmp_result
= fiji_disable_smc_cac(hwmgr
);
3706 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3707 "Failed to disable SMC CAC!", result
= tmp_result
);
3709 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3710 CG_SPLL_SPREAD_SPECTRUM
, SSEN
, 0);
3711 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3712 GENERAL_PWRMGT
, DYN_SPREAD_SPECTRUM_EN
, 0);
3714 tmp_result
= fiji_disable_thermal_auto_throttle(hwmgr
);
3715 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3716 "Failed to disable thermal auto throttle!", result
= tmp_result
);
3718 tmp_result
= fiji_stop_dpm(hwmgr
);
3719 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3720 "Failed to stop DPM!", result
= tmp_result
);
3722 tmp_result
= fiji_disable_deep_sleep_master_switch(hwmgr
);
3723 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3724 "Failed to disable deep sleep master switch!", result
= tmp_result
);
3726 tmp_result
= fiji_disable_ulv(hwmgr
);
3727 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3728 "Failed to disable ULV!", result
= tmp_result
);
3730 tmp_result
= fiji_clear_voting_clients(hwmgr
);
3731 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3732 "Failed to clear voting clients!", result
= tmp_result
);
3734 tmp_result
= fiji_reset_to_default(hwmgr
);
3735 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3736 "Failed to reset to default!", result
= tmp_result
);
3738 tmp_result
= fiji_force_switch_to_arbf0(hwmgr
);
3739 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3740 "Failed to force to switch arbf0!", result
= tmp_result
);
3745 static int fiji_force_dpm_highest(struct pp_hwmgr
*hwmgr
)
3747 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3748 uint32_t level
, tmp
;
3750 if (!data
->sclk_dpm_key_disabled
) {
3751 if (data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
3753 tmp
= data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
;
3757 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3758 PPSMC_MSG_SCLKDPM_SetEnabledMask
,
3763 if (!data
->mclk_dpm_key_disabled
) {
3764 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
) {
3766 tmp
= data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
;
3770 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3771 PPSMC_MSG_MCLKDPM_SetEnabledMask
,
3776 if (!data
->pcie_dpm_key_disabled
) {
3777 if (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
) {
3779 tmp
= data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
;
3783 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3784 PPSMC_MSG_PCIeDPM_ForceLevel
,
3791 static int fiji_upload_dpmlevel_enable_mask(struct pp_hwmgr
*hwmgr
)
3793 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3795 phm_apply_dal_min_voltage_request(hwmgr
);
3797 if (!data
->sclk_dpm_key_disabled
) {
3798 if (data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
)
3799 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3800 PPSMC_MSG_SCLKDPM_SetEnabledMask
,
3801 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
3806 static int fiji_unforce_dpm_levels(struct pp_hwmgr
*hwmgr
)
3808 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3810 if (!fiji_is_dpm_running(hwmgr
))
3813 if (!data
->pcie_dpm_key_disabled
) {
3814 smum_send_msg_to_smc(hwmgr
->smumgr
,
3815 PPSMC_MSG_PCIeDPM_UnForceLevel
);
3818 return fiji_upload_dpmlevel_enable_mask(hwmgr
);
3821 static uint32_t fiji_get_lowest_enabled_level(
3822 struct pp_hwmgr
*hwmgr
, uint32_t mask
)
3826 while(0 == (mask
& (1 << level
)))
3832 static int fiji_force_dpm_lowest(struct pp_hwmgr
*hwmgr
)
3834 struct fiji_hwmgr
*data
=
3835 (struct fiji_hwmgr
*)(hwmgr
->backend
);
3838 if (!data
->sclk_dpm_key_disabled
)
3839 if (data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
3840 level
= fiji_get_lowest_enabled_level(hwmgr
,
3841 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
3842 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3843 PPSMC_MSG_SCLKDPM_SetEnabledMask
,
3848 if (!data
->mclk_dpm_key_disabled
) {
3849 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
) {
3850 level
= fiji_get_lowest_enabled_level(hwmgr
,
3851 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
);
3852 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3853 PPSMC_MSG_MCLKDPM_SetEnabledMask
,
3858 if (!data
->pcie_dpm_key_disabled
) {
3859 if (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
) {
3860 level
= fiji_get_lowest_enabled_level(hwmgr
,
3861 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
);
3862 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3863 PPSMC_MSG_PCIeDPM_ForceLevel
,
3871 static int fiji_dpm_force_dpm_level(struct pp_hwmgr
*hwmgr
,
3872 enum amd_dpm_forced_level level
)
3877 case AMD_DPM_FORCED_LEVEL_HIGH
:
3878 ret
= fiji_force_dpm_highest(hwmgr
);
3882 case AMD_DPM_FORCED_LEVEL_LOW
:
3883 ret
= fiji_force_dpm_lowest(hwmgr
);
3887 case AMD_DPM_FORCED_LEVEL_AUTO
:
3888 ret
= fiji_unforce_dpm_levels(hwmgr
);
3896 hwmgr
->dpm_level
= level
;
3901 static int fiji_get_power_state_size(struct pp_hwmgr
*hwmgr
)
3903 return sizeof(struct fiji_power_state
);
3906 static int fiji_get_pp_table_entry_callback_func(struct pp_hwmgr
*hwmgr
,
3907 void *state
, struct pp_power_state
*power_state
,
3908 void *pp_table
, uint32_t classification_flag
)
3910 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3911 struct fiji_power_state
*fiji_power_state
=
3912 (struct fiji_power_state
*)(&(power_state
->hardware
));
3913 struct fiji_performance_level
*performance_level
;
3914 ATOM_Tonga_State
*state_entry
= (ATOM_Tonga_State
*)state
;
3915 ATOM_Tonga_POWERPLAYTABLE
*powerplay_table
=
3916 (ATOM_Tonga_POWERPLAYTABLE
*)pp_table
;
3917 ATOM_Tonga_SCLK_Dependency_Table
*sclk_dep_table
=
3918 (ATOM_Tonga_SCLK_Dependency_Table
*)
3919 (((unsigned long)powerplay_table
) +
3920 le16_to_cpu(powerplay_table
->usSclkDependencyTableOffset
));
3921 ATOM_Tonga_MCLK_Dependency_Table
*mclk_dep_table
=
3922 (ATOM_Tonga_MCLK_Dependency_Table
*)
3923 (((unsigned long)powerplay_table
) +
3924 le16_to_cpu(powerplay_table
->usMclkDependencyTableOffset
));
3926 /* The following fields are not initialized here: id orderedList allStatesList */
3927 power_state
->classification
.ui_label
=
3928 (le16_to_cpu(state_entry
->usClassification
) &
3929 ATOM_PPLIB_CLASSIFICATION_UI_MASK
) >>
3930 ATOM_PPLIB_CLASSIFICATION_UI_SHIFT
;
3931 power_state
->classification
.flags
= classification_flag
;
3932 /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
3934 power_state
->classification
.temporary_state
= false;
3935 power_state
->classification
.to_be_deleted
= false;
3937 power_state
->validation
.disallowOnDC
=
3938 (0 != (le32_to_cpu(state_entry
->ulCapsAndSettings
) &
3939 ATOM_Tonga_DISALLOW_ON_DC
));
3941 power_state
->pcie
.lanes
= 0;
3943 power_state
->display
.disableFrameModulation
= false;
3944 power_state
->display
.limitRefreshrate
= false;
3945 power_state
->display
.enableVariBright
=
3946 (0 != (le32_to_cpu(state_entry
->ulCapsAndSettings
) &
3947 ATOM_Tonga_ENABLE_VARIBRIGHT
));
3949 power_state
->validation
.supportedPowerLevels
= 0;
3950 power_state
->uvd_clocks
.VCLK
= 0;
3951 power_state
->uvd_clocks
.DCLK
= 0;
3952 power_state
->temperatures
.min
= 0;
3953 power_state
->temperatures
.max
= 0;
3955 performance_level
= &(fiji_power_state
->performance_levels
3956 [fiji_power_state
->performance_level_count
++]);
3958 PP_ASSERT_WITH_CODE(
3959 (fiji_power_state
->performance_level_count
< SMU73_MAX_LEVELS_GRAPHICS
),
3960 "Performance levels exceeds SMC limit!",
3963 PP_ASSERT_WITH_CODE(
3964 (fiji_power_state
->performance_level_count
<=
3965 hwmgr
->platform_descriptor
.hardwareActivityPerformanceLevels
),
3966 "Performance levels exceeds Driver limit!",
3969 /* Performance levels are arranged from low to high. */
3970 performance_level
->memory_clock
= mclk_dep_table
->entries
3971 [state_entry
->ucMemoryClockIndexLow
].ulMclk
;
3972 performance_level
->engine_clock
= sclk_dep_table
->entries
3973 [state_entry
->ucEngineClockIndexLow
].ulSclk
;
3974 performance_level
->pcie_gen
= get_pcie_gen_support(data
->pcie_gen_cap
,
3975 state_entry
->ucPCIEGenLow
);
3976 performance_level
->pcie_lane
= get_pcie_lane_support(data
->pcie_lane_cap
,
3977 state_entry
->ucPCIELaneHigh
);
3979 performance_level
= &(fiji_power_state
->performance_levels
3980 [fiji_power_state
->performance_level_count
++]);
3981 performance_level
->memory_clock
= mclk_dep_table
->entries
3982 [state_entry
->ucMemoryClockIndexHigh
].ulMclk
;
3983 performance_level
->engine_clock
= sclk_dep_table
->entries
3984 [state_entry
->ucEngineClockIndexHigh
].ulSclk
;
3985 performance_level
->pcie_gen
= get_pcie_gen_support(data
->pcie_gen_cap
,
3986 state_entry
->ucPCIEGenHigh
);
3987 performance_level
->pcie_lane
= get_pcie_lane_support(data
->pcie_lane_cap
,
3988 state_entry
->ucPCIELaneHigh
);
3993 static int fiji_get_pp_table_entry(struct pp_hwmgr
*hwmgr
,
3994 unsigned long entry_index
, struct pp_power_state
*state
)
3997 struct fiji_power_state
*ps
;
3998 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3999 struct phm_ppt_v1_information
*table_info
=
4000 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4001 struct phm_ppt_v1_clock_voltage_dependency_table
*dep_mclk_table
=
4002 table_info
->vdd_dep_on_mclk
;
4004 state
->hardware
.magic
= PHM_VIslands_Magic
;
4006 ps
= (struct fiji_power_state
*)(&state
->hardware
);
4008 result
= tonga_get_powerplay_table_entry(hwmgr
, entry_index
, state
,
4009 fiji_get_pp_table_entry_callback_func
);
4011 /* This is the earliest time we have all the dependency table and the VBIOS boot state
4012 * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
4013 * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
4015 if (dep_mclk_table
!= NULL
&& dep_mclk_table
->count
== 1) {
4016 if (dep_mclk_table
->entries
[0].clk
!=
4017 data
->vbios_boot_state
.mclk_bootup_value
)
4018 printk(KERN_ERR
"Single MCLK entry VDDCI/MCLK dependency table "
4019 "does not match VBIOS boot MCLK level");
4020 if (dep_mclk_table
->entries
[0].vddci
!=
4021 data
->vbios_boot_state
.vddci_bootup_value
)
4022 printk(KERN_ERR
"Single VDDCI entry VDDCI/MCLK dependency table "
4023 "does not match VBIOS boot VDDCI level");
4026 /* set DC compatible flag if this state supports DC */
4027 if (!state
->validation
.disallowOnDC
)
4028 ps
->dc_compatible
= true;
4030 if (state
->classification
.flags
& PP_StateClassificationFlag_ACPI
)
4031 data
->acpi_pcie_gen
= ps
->performance_levels
[0].pcie_gen
;
4033 ps
->uvd_clks
.vclk
= state
->uvd_clocks
.VCLK
;
4034 ps
->uvd_clks
.dclk
= state
->uvd_clocks
.DCLK
;
4039 switch (state
->classification
.ui_label
) {
4040 case PP_StateUILabel_Performance
:
4041 data
->use_pcie_performance_levels
= true;
4043 for (i
= 0; i
< ps
->performance_level_count
; i
++) {
4044 if (data
->pcie_gen_performance
.max
<
4045 ps
->performance_levels
[i
].pcie_gen
)
4046 data
->pcie_gen_performance
.max
=
4047 ps
->performance_levels
[i
].pcie_gen
;
4049 if (data
->pcie_gen_performance
.min
>
4050 ps
->performance_levels
[i
].pcie_gen
)
4051 data
->pcie_gen_performance
.min
=
4052 ps
->performance_levels
[i
].pcie_gen
;
4054 if (data
->pcie_lane_performance
.max
<
4055 ps
->performance_levels
[i
].pcie_lane
)
4056 data
->pcie_lane_performance
.max
=
4057 ps
->performance_levels
[i
].pcie_lane
;
4059 if (data
->pcie_lane_performance
.min
>
4060 ps
->performance_levels
[i
].pcie_lane
)
4061 data
->pcie_lane_performance
.min
=
4062 ps
->performance_levels
[i
].pcie_lane
;
4065 case PP_StateUILabel_Battery
:
4066 data
->use_pcie_power_saving_levels
= true;
4068 for (i
= 0; i
< ps
->performance_level_count
; i
++) {
4069 if (data
->pcie_gen_power_saving
.max
<
4070 ps
->performance_levels
[i
].pcie_gen
)
4071 data
->pcie_gen_power_saving
.max
=
4072 ps
->performance_levels
[i
].pcie_gen
;
4074 if (data
->pcie_gen_power_saving
.min
>
4075 ps
->performance_levels
[i
].pcie_gen
)
4076 data
->pcie_gen_power_saving
.min
=
4077 ps
->performance_levels
[i
].pcie_gen
;
4079 if (data
->pcie_lane_power_saving
.max
<
4080 ps
->performance_levels
[i
].pcie_lane
)
4081 data
->pcie_lane_power_saving
.max
=
4082 ps
->performance_levels
[i
].pcie_lane
;
4084 if (data
->pcie_lane_power_saving
.min
>
4085 ps
->performance_levels
[i
].pcie_lane
)
4086 data
->pcie_lane_power_saving
.min
=
4087 ps
->performance_levels
[i
].pcie_lane
;
4097 static int fiji_apply_state_adjust_rules(struct pp_hwmgr
*hwmgr
,
4098 struct pp_power_state
*request_ps
,
4099 const struct pp_power_state
*current_ps
)
4101 struct fiji_power_state
*fiji_ps
=
4102 cast_phw_fiji_power_state(&request_ps
->hardware
);
4105 struct PP_Clocks minimum_clocks
= {0};
4106 bool disable_mclk_switching
;
4107 bool disable_mclk_switching_for_frame_lock
;
4108 struct cgs_display_info info
= {0};
4109 const struct phm_clock_and_voltage_limits
*max_limits
;
4111 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4112 struct phm_ppt_v1_information
*table_info
=
4113 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4115 int32_t stable_pstate_sclk
= 0, stable_pstate_mclk
= 0;
4117 data
->battery_state
= (PP_StateUILabel_Battery
==
4118 request_ps
->classification
.ui_label
);
4120 PP_ASSERT_WITH_CODE(fiji_ps
->performance_level_count
== 2,
4121 "VI should always have 2 performance levels",);
4123 max_limits
= (PP_PowerSource_AC
== hwmgr
->power_source
) ?
4124 &(hwmgr
->dyn_state
.max_clock_voltage_on_ac
) :
4125 &(hwmgr
->dyn_state
.max_clock_voltage_on_dc
);
4127 /* Cap clock DPM tables at DC MAX if it is in DC. */
4128 if (PP_PowerSource_DC
== hwmgr
->power_source
) {
4129 for (i
= 0; i
< fiji_ps
->performance_level_count
; i
++) {
4130 if (fiji_ps
->performance_levels
[i
].memory_clock
> max_limits
->mclk
)
4131 fiji_ps
->performance_levels
[i
].memory_clock
= max_limits
->mclk
;
4132 if (fiji_ps
->performance_levels
[i
].engine_clock
> max_limits
->sclk
)
4133 fiji_ps
->performance_levels
[i
].engine_clock
= max_limits
->sclk
;
4137 fiji_ps
->vce_clks
.evclk
= hwmgr
->vce_arbiter
.evclk
;
4138 fiji_ps
->vce_clks
.ecclk
= hwmgr
->vce_arbiter
.ecclk
;
4140 fiji_ps
->acp_clk
= hwmgr
->acp_arbiter
.acpclk
;
4142 cgs_get_active_displays_info(hwmgr
->device
, &info
);
4144 /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
4146 /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
4148 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4149 PHM_PlatformCaps_StablePState
)) {
4150 max_limits
= &(hwmgr
->dyn_state
.max_clock_voltage_on_ac
);
4151 stable_pstate_sclk
= (max_limits
->sclk
* 75) / 100;
4153 for (count
= table_info
->vdd_dep_on_sclk
->count
- 1;
4154 count
>= 0; count
--) {
4155 if (stable_pstate_sclk
>=
4156 table_info
->vdd_dep_on_sclk
->entries
[count
].clk
) {
4157 stable_pstate_sclk
=
4158 table_info
->vdd_dep_on_sclk
->entries
[count
].clk
;
4164 stable_pstate_sclk
= table_info
->vdd_dep_on_sclk
->entries
[0].clk
;
4166 stable_pstate_mclk
= max_limits
->mclk
;
4168 minimum_clocks
.engineClock
= stable_pstate_sclk
;
4169 minimum_clocks
.memoryClock
= stable_pstate_mclk
;
4172 if (minimum_clocks
.engineClock
< hwmgr
->gfx_arbiter
.sclk
)
4173 minimum_clocks
.engineClock
= hwmgr
->gfx_arbiter
.sclk
;
4175 if (minimum_clocks
.memoryClock
< hwmgr
->gfx_arbiter
.mclk
)
4176 minimum_clocks
.memoryClock
= hwmgr
->gfx_arbiter
.mclk
;
4178 fiji_ps
->sclk_threshold
= hwmgr
->gfx_arbiter
.sclk_threshold
;
4180 if (0 != hwmgr
->gfx_arbiter
.sclk_over_drive
) {
4181 PP_ASSERT_WITH_CODE((hwmgr
->gfx_arbiter
.sclk_over_drive
<=
4182 hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
),
4183 "Overdrive sclk exceeds limit",
4184 hwmgr
->gfx_arbiter
.sclk_over_drive
=
4185 hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
);
4187 if (hwmgr
->gfx_arbiter
.sclk_over_drive
>= hwmgr
->gfx_arbiter
.sclk
)
4188 fiji_ps
->performance_levels
[1].engine_clock
=
4189 hwmgr
->gfx_arbiter
.sclk_over_drive
;
4192 if (0 != hwmgr
->gfx_arbiter
.mclk_over_drive
) {
4193 PP_ASSERT_WITH_CODE((hwmgr
->gfx_arbiter
.mclk_over_drive
<=
4194 hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
),
4195 "Overdrive mclk exceeds limit",
4196 hwmgr
->gfx_arbiter
.mclk_over_drive
=
4197 hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
);
4199 if (hwmgr
->gfx_arbiter
.mclk_over_drive
>= hwmgr
->gfx_arbiter
.mclk
)
4200 fiji_ps
->performance_levels
[1].memory_clock
=
4201 hwmgr
->gfx_arbiter
.mclk_over_drive
;
4204 disable_mclk_switching_for_frame_lock
= phm_cap_enabled(
4205 hwmgr
->platform_descriptor
.platformCaps
,
4206 PHM_PlatformCaps_DisableMclkSwitchingForFrameLock
);
4208 disable_mclk_switching
= (1 < info
.display_count
) ||
4209 disable_mclk_switching_for_frame_lock
;
4211 sclk
= fiji_ps
->performance_levels
[0].engine_clock
;
4212 mclk
= fiji_ps
->performance_levels
[0].memory_clock
;
4214 if (disable_mclk_switching
)
4215 mclk
= fiji_ps
->performance_levels
4216 [fiji_ps
->performance_level_count
- 1].memory_clock
;
4218 if (sclk
< minimum_clocks
.engineClock
)
4219 sclk
= (minimum_clocks
.engineClock
> max_limits
->sclk
) ?
4220 max_limits
->sclk
: minimum_clocks
.engineClock
;
4222 if (mclk
< minimum_clocks
.memoryClock
)
4223 mclk
= (minimum_clocks
.memoryClock
> max_limits
->mclk
) ?
4224 max_limits
->mclk
: minimum_clocks
.memoryClock
;
4226 fiji_ps
->performance_levels
[0].engine_clock
= sclk
;
4227 fiji_ps
->performance_levels
[0].memory_clock
= mclk
;
4229 fiji_ps
->performance_levels
[1].engine_clock
=
4230 (fiji_ps
->performance_levels
[1].engine_clock
>=
4231 fiji_ps
->performance_levels
[0].engine_clock
) ?
4232 fiji_ps
->performance_levels
[1].engine_clock
:
4233 fiji_ps
->performance_levels
[0].engine_clock
;
4235 if (disable_mclk_switching
) {
4236 if (mclk
< fiji_ps
->performance_levels
[1].memory_clock
)
4237 mclk
= fiji_ps
->performance_levels
[1].memory_clock
;
4239 fiji_ps
->performance_levels
[0].memory_clock
= mclk
;
4240 fiji_ps
->performance_levels
[1].memory_clock
= mclk
;
4242 if (fiji_ps
->performance_levels
[1].memory_clock
<
4243 fiji_ps
->performance_levels
[0].memory_clock
)
4244 fiji_ps
->performance_levels
[1].memory_clock
=
4245 fiji_ps
->performance_levels
[0].memory_clock
;
4248 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4249 PHM_PlatformCaps_StablePState
)) {
4250 for (i
= 0; i
< fiji_ps
->performance_level_count
; i
++) {
4251 fiji_ps
->performance_levels
[i
].engine_clock
= stable_pstate_sclk
;
4252 fiji_ps
->performance_levels
[i
].memory_clock
= stable_pstate_mclk
;
4253 fiji_ps
->performance_levels
[i
].pcie_gen
= data
->pcie_gen_performance
.max
;
4254 fiji_ps
->performance_levels
[i
].pcie_lane
= data
->pcie_gen_performance
.max
;
4261 static int fiji_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr
*hwmgr
, const void *input
)
4263 const struct phm_set_power_state_input
*states
=
4264 (const struct phm_set_power_state_input
*)input
;
4265 const struct fiji_power_state
*fiji_ps
=
4266 cast_const_phw_fiji_power_state(states
->pnew_state
);
4267 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4268 struct fiji_single_dpm_table
*sclk_table
= &(data
->dpm_table
.sclk_table
);
4269 uint32_t sclk
= fiji_ps
->performance_levels
4270 [fiji_ps
->performance_level_count
- 1].engine_clock
;
4271 struct fiji_single_dpm_table
*mclk_table
= &(data
->dpm_table
.mclk_table
);
4272 uint32_t mclk
= fiji_ps
->performance_levels
4273 [fiji_ps
->performance_level_count
- 1].memory_clock
;
4275 struct cgs_display_info info
= {0};
4277 data
->need_update_smu7_dpm_table
= 0;
4279 for (i
= 0; i
< sclk_table
->count
; i
++) {
4280 if (sclk
== sclk_table
->dpm_levels
[i
].value
)
4284 if (i
>= sclk_table
->count
)
4285 data
->need_update_smu7_dpm_table
|= DPMTABLE_OD_UPDATE_SCLK
;
4287 if(data
->display_timing
.min_clock_in_sr
!=
4288 hwmgr
->display_config
.min_core_set_clock_in_sr
)
4289 data
->need_update_smu7_dpm_table
|= DPMTABLE_UPDATE_SCLK
;
4292 for (i
= 0; i
< mclk_table
->count
; i
++) {
4293 if (mclk
== mclk_table
->dpm_levels
[i
].value
)
4297 if (i
>= mclk_table
->count
)
4298 data
->need_update_smu7_dpm_table
|= DPMTABLE_OD_UPDATE_MCLK
;
4300 cgs_get_active_displays_info(hwmgr
->device
, &info
);
4302 if (data
->display_timing
.num_existing_displays
!= info
.display_count
)
4303 data
->need_update_smu7_dpm_table
|= DPMTABLE_UPDATE_MCLK
;
4308 static uint16_t fiji_get_maximum_link_speed(struct pp_hwmgr
*hwmgr
,
4309 const struct fiji_power_state
*fiji_ps
)
4312 uint32_t sclk
, max_sclk
= 0;
4313 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4314 struct fiji_dpm_table
*dpm_table
= &data
->dpm_table
;
4316 for (i
= 0; i
< fiji_ps
->performance_level_count
; i
++) {
4317 sclk
= fiji_ps
->performance_levels
[i
].engine_clock
;
4318 if (max_sclk
< sclk
)
4322 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
4323 if (dpm_table
->sclk_table
.dpm_levels
[i
].value
== max_sclk
)
4324 return (uint16_t) ((i
>= dpm_table
->pcie_speed_table
.count
) ?
4325 dpm_table
->pcie_speed_table
.dpm_levels
4326 [dpm_table
->pcie_speed_table
.count
- 1].value
:
4327 dpm_table
->pcie_speed_table
.dpm_levels
[i
].value
);
4333 static int fiji_request_link_speed_change_before_state_change(
4334 struct pp_hwmgr
*hwmgr
, const void *input
)
4336 const struct phm_set_power_state_input
*states
=
4337 (const struct phm_set_power_state_input
*)input
;
4338 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4339 const struct fiji_power_state
*fiji_nps
=
4340 cast_const_phw_fiji_power_state(states
->pnew_state
);
4341 const struct fiji_power_state
*fiji_cps
=
4342 cast_const_phw_fiji_power_state(states
->pcurrent_state
);
4344 uint16_t target_link_speed
= fiji_get_maximum_link_speed(hwmgr
, fiji_nps
);
4345 uint16_t current_link_speed
;
4347 if (data
->force_pcie_gen
== PP_PCIEGenInvalid
)
4348 current_link_speed
= fiji_get_maximum_link_speed(hwmgr
, fiji_cps
);
4350 current_link_speed
= data
->force_pcie_gen
;
4352 data
->force_pcie_gen
= PP_PCIEGenInvalid
;
4353 data
->pspp_notify_required
= false;
4354 if (target_link_speed
> current_link_speed
) {
4355 switch(target_link_speed
) {
4357 if (0 == acpi_pcie_perf_request(hwmgr
->device
, PCIE_PERF_REQ_GEN3
, false))
4359 data
->force_pcie_gen
= PP_PCIEGen2
;
4360 if (current_link_speed
== PP_PCIEGen2
)
4363 if (0 == acpi_pcie_perf_request(hwmgr
->device
, PCIE_PERF_REQ_GEN2
, false))
4366 data
->force_pcie_gen
= fiji_get_current_pcie_speed(hwmgr
);
4370 if (target_link_speed
< current_link_speed
)
4371 data
->pspp_notify_required
= true;
4377 static int fiji_freeze_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
4379 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4381 if (0 == data
->need_update_smu7_dpm_table
)
4384 if ((0 == data
->sclk_dpm_key_disabled
) &&
4385 (data
->need_update_smu7_dpm_table
&
4386 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
))) {
4387 PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr
),
4388 "Trying to freeze SCLK DPM when DPM is disabled",
4390 PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
4391 PPSMC_MSG_SCLKDPM_FreezeLevel
),
4392 "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
4396 if ((0 == data
->mclk_dpm_key_disabled
) &&
4397 (data
->need_update_smu7_dpm_table
&
4398 DPMTABLE_OD_UPDATE_MCLK
)) {
4399 PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr
),
4400 "Trying to freeze MCLK DPM when DPM is disabled",
4402 PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
4403 PPSMC_MSG_MCLKDPM_FreezeLevel
),
4404 "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
4411 static int fiji_populate_and_upload_sclk_mclk_dpm_levels(
4412 struct pp_hwmgr
*hwmgr
, const void *input
)
4415 const struct phm_set_power_state_input
*states
=
4416 (const struct phm_set_power_state_input
*)input
;
4417 const struct fiji_power_state
*fiji_ps
=
4418 cast_const_phw_fiji_power_state(states
->pnew_state
);
4419 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4420 uint32_t sclk
= fiji_ps
->performance_levels
4421 [fiji_ps
->performance_level_count
- 1].engine_clock
;
4422 uint32_t mclk
= fiji_ps
->performance_levels
4423 [fiji_ps
->performance_level_count
- 1].memory_clock
;
4424 struct fiji_dpm_table
*dpm_table
= &data
->dpm_table
;
4426 struct fiji_dpm_table
*golden_dpm_table
= &data
->golden_dpm_table
;
4427 uint32_t dpm_count
, clock_percent
;
4430 if (0 == data
->need_update_smu7_dpm_table
)
4433 if (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_SCLK
) {
4434 dpm_table
->sclk_table
.dpm_levels
4435 [dpm_table
->sclk_table
.count
- 1].value
= sclk
;
4437 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4438 PHM_PlatformCaps_OD6PlusinACSupport
) ||
4439 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4440 PHM_PlatformCaps_OD6PlusinDCSupport
)) {
4441 /* Need to do calculation based on the golden DPM table
4442 * as the Heatmap GPU Clock axis is also based on the default values
4444 PP_ASSERT_WITH_CODE(
4445 (golden_dpm_table
->sclk_table
.dpm_levels
4446 [golden_dpm_table
->sclk_table
.count
- 1].value
!= 0),
4449 dpm_count
= dpm_table
->sclk_table
.count
< 2 ?
4450 0 : dpm_table
->sclk_table
.count
- 2;
4451 for (i
= dpm_count
; i
> 1; i
--) {
4452 if (sclk
> golden_dpm_table
->sclk_table
.dpm_levels
4453 [golden_dpm_table
->sclk_table
.count
-1].value
) {
4455 ((sclk
- golden_dpm_table
->sclk_table
.dpm_levels
4456 [golden_dpm_table
->sclk_table
.count
-1].value
) * 100) /
4457 golden_dpm_table
->sclk_table
.dpm_levels
4458 [golden_dpm_table
->sclk_table
.count
-1].value
;
4460 dpm_table
->sclk_table
.dpm_levels
[i
].value
=
4461 golden_dpm_table
->sclk_table
.dpm_levels
[i
].value
+
4462 (golden_dpm_table
->sclk_table
.dpm_levels
[i
].value
*
4465 } else if (golden_dpm_table
->sclk_table
.dpm_levels
4466 [dpm_table
->sclk_table
.count
-1].value
> sclk
) {
4468 ((golden_dpm_table
->sclk_table
.dpm_levels
4469 [golden_dpm_table
->sclk_table
.count
- 1].value
- sclk
) *
4471 golden_dpm_table
->sclk_table
.dpm_levels
4472 [golden_dpm_table
->sclk_table
.count
-1].value
;
4474 dpm_table
->sclk_table
.dpm_levels
[i
].value
=
4475 golden_dpm_table
->sclk_table
.dpm_levels
[i
].value
-
4476 (golden_dpm_table
->sclk_table
.dpm_levels
[i
].value
*
4477 clock_percent
) / 100;
4479 dpm_table
->sclk_table
.dpm_levels
[i
].value
=
4480 golden_dpm_table
->sclk_table
.dpm_levels
[i
].value
;
4485 if (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
) {
4486 dpm_table
->mclk_table
.dpm_levels
4487 [dpm_table
->mclk_table
.count
- 1].value
= mclk
;
4488 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4489 PHM_PlatformCaps_OD6PlusinACSupport
) ||
4490 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4491 PHM_PlatformCaps_OD6PlusinDCSupport
)) {
4493 PP_ASSERT_WITH_CODE(
4494 (golden_dpm_table
->mclk_table
.dpm_levels
4495 [golden_dpm_table
->mclk_table
.count
-1].value
!= 0),
4498 dpm_count
= dpm_table
->mclk_table
.count
< 2 ?
4499 0 : dpm_table
->mclk_table
.count
- 2;
4500 for (i
= dpm_count
; i
> 1; i
--) {
4501 if (mclk
> golden_dpm_table
->mclk_table
.dpm_levels
4502 [golden_dpm_table
->mclk_table
.count
-1].value
) {
4503 clock_percent
= ((mclk
-
4504 golden_dpm_table
->mclk_table
.dpm_levels
4505 [golden_dpm_table
->mclk_table
.count
-1].value
) * 100) /
4506 golden_dpm_table
->mclk_table
.dpm_levels
4507 [golden_dpm_table
->mclk_table
.count
-1].value
;
4509 dpm_table
->mclk_table
.dpm_levels
[i
].value
=
4510 golden_dpm_table
->mclk_table
.dpm_levels
[i
].value
+
4511 (golden_dpm_table
->mclk_table
.dpm_levels
[i
].value
*
4512 clock_percent
) / 100;
4514 } else if (golden_dpm_table
->mclk_table
.dpm_levels
4515 [dpm_table
->mclk_table
.count
-1].value
> mclk
) {
4516 clock_percent
= ((golden_dpm_table
->mclk_table
.dpm_levels
4517 [golden_dpm_table
->mclk_table
.count
-1].value
- mclk
) * 100) /
4518 golden_dpm_table
->mclk_table
.dpm_levels
4519 [golden_dpm_table
->mclk_table
.count
-1].value
;
4521 dpm_table
->mclk_table
.dpm_levels
[i
].value
=
4522 golden_dpm_table
->mclk_table
.dpm_levels
[i
].value
-
4523 (golden_dpm_table
->mclk_table
.dpm_levels
[i
].value
*
4524 clock_percent
) / 100;
4526 dpm_table
->mclk_table
.dpm_levels
[i
].value
=
4527 golden_dpm_table
->mclk_table
.dpm_levels
[i
].value
;
4532 if (data
->need_update_smu7_dpm_table
&
4533 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
)) {
4534 result
= fiji_populate_all_graphic_levels(hwmgr
);
4535 PP_ASSERT_WITH_CODE((0 == result
),
4536 "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
4540 if (data
->need_update_smu7_dpm_table
&
4541 (DPMTABLE_OD_UPDATE_MCLK
+ DPMTABLE_UPDATE_MCLK
)) {
4542 /*populate MCLK dpm table to SMU7 */
4543 result
= fiji_populate_all_memory_levels(hwmgr
);
4544 PP_ASSERT_WITH_CODE((0 == result
),
4545 "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
4552 static int fiji_trim_single_dpm_states(struct pp_hwmgr
*hwmgr
,
4553 struct fiji_single_dpm_table
* dpm_table
,
4554 uint32_t low_limit
, uint32_t high_limit
)
4558 for (i
= 0; i
< dpm_table
->count
; i
++) {
4559 if ((dpm_table
->dpm_levels
[i
].value
< low_limit
) ||
4560 (dpm_table
->dpm_levels
[i
].value
> high_limit
))
4561 dpm_table
->dpm_levels
[i
].enabled
= false;
4563 dpm_table
->dpm_levels
[i
].enabled
= true;
4568 static int fiji_trim_dpm_states(struct pp_hwmgr
*hwmgr
,
4569 const struct fiji_power_state
*fiji_ps
)
4571 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4572 uint32_t high_limit_count
;
4574 PP_ASSERT_WITH_CODE((fiji_ps
->performance_level_count
>= 1),
4575 "power state did not have any performance level",
4578 high_limit_count
= (1 == fiji_ps
->performance_level_count
) ? 0 : 1;
4580 fiji_trim_single_dpm_states(hwmgr
,
4581 &(data
->dpm_table
.sclk_table
),
4582 fiji_ps
->performance_levels
[0].engine_clock
,
4583 fiji_ps
->performance_levels
[high_limit_count
].engine_clock
);
4585 fiji_trim_single_dpm_states(hwmgr
,
4586 &(data
->dpm_table
.mclk_table
),
4587 fiji_ps
->performance_levels
[0].memory_clock
,
4588 fiji_ps
->performance_levels
[high_limit_count
].memory_clock
);
4593 static int fiji_generate_dpm_level_enable_mask(
4594 struct pp_hwmgr
*hwmgr
, const void *input
)
4597 const struct phm_set_power_state_input
*states
=
4598 (const struct phm_set_power_state_input
*)input
;
4599 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4600 const struct fiji_power_state
*fiji_ps
=
4601 cast_const_phw_fiji_power_state(states
->pnew_state
);
4603 result
= fiji_trim_dpm_states(hwmgr
, fiji_ps
);
4607 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
=
4608 fiji_get_dpm_level_enable_mask_value(&data
->dpm_table
.sclk_table
);
4609 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
=
4610 fiji_get_dpm_level_enable_mask_value(&data
->dpm_table
.mclk_table
);
4611 data
->last_mclk_dpm_enable_mask
=
4612 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
;
4614 if (data
->uvd_enabled
) {
4615 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
& 1)
4616 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
&= 0xFFFFFFFE;
4619 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
=
4620 fiji_get_dpm_level_enable_mask_value(&data
->dpm_table
.pcie_speed_table
);
4625 int fiji_enable_disable_uvd_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
4627 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
4628 (PPSMC_Msg
)PPSMC_MSG_UVDDPM_Enable
:
4629 (PPSMC_Msg
)PPSMC_MSG_UVDDPM_Disable
);
4632 int fiji_enable_disable_vce_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
4634 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
4635 PPSMC_MSG_VCEDPM_Enable
:
4636 PPSMC_MSG_VCEDPM_Disable
);
4639 int fiji_enable_disable_samu_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
4641 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
4642 PPSMC_MSG_SAMUDPM_Enable
:
4643 PPSMC_MSG_SAMUDPM_Disable
);
4646 int fiji_enable_disable_acp_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
4648 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
4649 PPSMC_MSG_ACPDPM_Enable
:
4650 PPSMC_MSG_ACPDPM_Disable
);
4653 int fiji_update_uvd_dpm(struct pp_hwmgr
*hwmgr
, bool bgate
)
4655 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4656 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
4657 struct phm_ppt_v1_information
*table_info
=
4658 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4661 data
->smc_state_table
.UvdBootLevel
= 0;
4662 if (table_info
->mm_dep_table
->count
> 0)
4663 data
->smc_state_table
.UvdBootLevel
=
4664 (uint8_t) (table_info
->mm_dep_table
->count
- 1);
4665 mm_boot_level_offset
= data
->dpm_table_start
+
4666 offsetof(SMU73_Discrete_DpmTable
, UvdBootLevel
);
4667 mm_boot_level_offset
/= 4;
4668 mm_boot_level_offset
*= 4;
4669 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
4670 CGS_IND_REG__SMC
, mm_boot_level_offset
);
4671 mm_boot_level_value
&= 0x00FFFFFF;
4672 mm_boot_level_value
|= data
->smc_state_table
.UvdBootLevel
<< 24;
4673 cgs_write_ind_register(hwmgr
->device
,
4674 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
4676 if (!phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4677 PHM_PlatformCaps_UVDDPM
) ||
4678 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4679 PHM_PlatformCaps_StablePState
))
4680 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
4681 PPSMC_MSG_UVDDPM_SetEnabledMask
,
4682 (uint32_t)(1 << data
->smc_state_table
.UvdBootLevel
));
4685 return fiji_enable_disable_uvd_dpm(hwmgr
, !bgate
);
4688 int fiji_update_vce_dpm(struct pp_hwmgr
*hwmgr
, const void *input
)
4690 const struct phm_set_power_state_input
*states
=
4691 (const struct phm_set_power_state_input
*)input
;
4692 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4693 const struct fiji_power_state
*fiji_nps
=
4694 cast_const_phw_fiji_power_state(states
->pnew_state
);
4695 const struct fiji_power_state
*fiji_cps
=
4696 cast_const_phw_fiji_power_state(states
->pcurrent_state
);
4698 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
4699 struct phm_ppt_v1_information
*table_info
=
4700 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4702 if (fiji_nps
->vce_clks
.evclk
>0 &&
4703 (fiji_cps
== NULL
|| fiji_cps
->vce_clks
.evclk
== 0)) {
4704 data
->smc_state_table
.VceBootLevel
=
4705 (uint8_t) (table_info
->mm_dep_table
->count
- 1);
4707 mm_boot_level_offset
= data
->dpm_table_start
+
4708 offsetof(SMU73_Discrete_DpmTable
, VceBootLevel
);
4709 mm_boot_level_offset
/= 4;
4710 mm_boot_level_offset
*= 4;
4711 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
4712 CGS_IND_REG__SMC
, mm_boot_level_offset
);
4713 mm_boot_level_value
&= 0xFF00FFFF;
4714 mm_boot_level_value
|= data
->smc_state_table
.VceBootLevel
<< 16;
4715 cgs_write_ind_register(hwmgr
->device
,
4716 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
4718 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4719 PHM_PlatformCaps_StablePState
)) {
4720 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
4721 PPSMC_MSG_VCEDPM_SetEnabledMask
,
4722 (uint32_t)1 << data
->smc_state_table
.VceBootLevel
);
4724 fiji_enable_disable_vce_dpm(hwmgr
, true);
4725 } else if (fiji_nps
->vce_clks
.evclk
== 0 &&
4727 fiji_cps
->vce_clks
.evclk
> 0)
4728 fiji_enable_disable_vce_dpm(hwmgr
, false);
4734 int fiji_update_samu_dpm(struct pp_hwmgr
*hwmgr
, bool bgate
)
4736 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4737 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
4738 struct phm_ppt_v1_information
*table_info
=
4739 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4742 data
->smc_state_table
.SamuBootLevel
=
4743 (uint8_t) (table_info
->mm_dep_table
->count
- 1);
4744 mm_boot_level_offset
= data
->dpm_table_start
+
4745 offsetof(SMU73_Discrete_DpmTable
, SamuBootLevel
);
4746 mm_boot_level_offset
/= 4;
4747 mm_boot_level_offset
*= 4;
4748 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
4749 CGS_IND_REG__SMC
, mm_boot_level_offset
);
4750 mm_boot_level_value
&= 0xFFFFFF00;
4751 mm_boot_level_value
|= data
->smc_state_table
.SamuBootLevel
<< 0;
4752 cgs_write_ind_register(hwmgr
->device
,
4753 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
4755 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4756 PHM_PlatformCaps_StablePState
))
4757 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
4758 PPSMC_MSG_SAMUDPM_SetEnabledMask
,
4759 (uint32_t)(1 << data
->smc_state_table
.SamuBootLevel
));
4762 return fiji_enable_disable_samu_dpm(hwmgr
, !bgate
);
4765 int fiji_update_acp_dpm(struct pp_hwmgr
*hwmgr
, bool bgate
)
4767 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4768 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
4769 struct phm_ppt_v1_information
*table_info
=
4770 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4773 data
->smc_state_table
.AcpBootLevel
=
4774 (uint8_t) (table_info
->mm_dep_table
->count
- 1);
4775 mm_boot_level_offset
= data
->dpm_table_start
+
4776 offsetof(SMU73_Discrete_DpmTable
, AcpBootLevel
);
4777 mm_boot_level_offset
/= 4;
4778 mm_boot_level_offset
*= 4;
4779 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
4780 CGS_IND_REG__SMC
, mm_boot_level_offset
);
4781 mm_boot_level_value
&= 0xFFFF00FF;
4782 mm_boot_level_value
|= data
->smc_state_table
.AcpBootLevel
<< 8;
4783 cgs_write_ind_register(hwmgr
->device
,
4784 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
4786 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4787 PHM_PlatformCaps_StablePState
))
4788 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
4789 PPSMC_MSG_ACPDPM_SetEnabledMask
,
4790 (uint32_t)(1 << data
->smc_state_table
.AcpBootLevel
));
4793 return fiji_enable_disable_acp_dpm(hwmgr
, !bgate
);
4796 static int fiji_update_sclk_threshold(struct pp_hwmgr
*hwmgr
)
4798 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4801 uint32_t low_sclk_interrupt_threshold
= 0;
4803 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4804 PHM_PlatformCaps_SclkThrottleLowNotification
)
4805 && (hwmgr
->gfx_arbiter
.sclk_threshold
!=
4806 data
->low_sclk_interrupt_threshold
)) {
4807 data
->low_sclk_interrupt_threshold
=
4808 hwmgr
->gfx_arbiter
.sclk_threshold
;
4809 low_sclk_interrupt_threshold
=
4810 data
->low_sclk_interrupt_threshold
;
4812 CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold
);
4814 result
= fiji_copy_bytes_to_smc(
4816 data
->dpm_table_start
+
4817 offsetof(SMU73_Discrete_DpmTable
,
4818 LowSclkInterruptThreshold
),
4819 (uint8_t *)&low_sclk_interrupt_threshold
,
4827 static int fiji_program_mem_timing_parameters(struct pp_hwmgr
*hwmgr
)
4829 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4831 if (data
->need_update_smu7_dpm_table
&
4832 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_OD_UPDATE_MCLK
))
4833 return fiji_program_memory_timing_parameters(hwmgr
);
4838 static int fiji_unfreeze_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
4840 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4842 if (0 == data
->need_update_smu7_dpm_table
)
4845 if ((0 == data
->sclk_dpm_key_disabled
) &&
4846 (data
->need_update_smu7_dpm_table
&
4847 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
))) {
4849 PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr
),
4850 "Trying to Unfreeze SCLK DPM when DPM is disabled",
4852 PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
4853 PPSMC_MSG_SCLKDPM_UnfreezeLevel
),
4854 "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
4858 if ((0 == data
->mclk_dpm_key_disabled
) &&
4859 (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
)) {
4861 PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr
),
4862 "Trying to Unfreeze MCLK DPM when DPM is disabled",
4864 PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
4865 PPSMC_MSG_SCLKDPM_UnfreezeLevel
),
4866 "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
4870 data
->need_update_smu7_dpm_table
= 0;
4875 /* Look up the voltaged based on DAL's requested level.
4876 * and then send the requested VDDC voltage to SMC
4878 static void fiji_apply_dal_minimum_voltage_request(struct pp_hwmgr
*hwmgr
)
4883 int fiji_upload_dpm_level_enable_mask(struct pp_hwmgr
*hwmgr
)
4886 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4888 /* Apply minimum voltage based on DAL's request level */
4889 fiji_apply_dal_minimum_voltage_request(hwmgr
);
4891 if (0 == data
->sclk_dpm_key_disabled
) {
4892 /* Checking if DPM is running. If we discover hang because of this,
4893 * we should skip this message.
4895 if (!fiji_is_dpm_running(hwmgr
))
4896 printk(KERN_ERR
"[ powerplay ] "
4897 "Trying to set Enable Mask when DPM is disabled \n");
4899 if (data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
4900 result
= smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
4901 PPSMC_MSG_SCLKDPM_SetEnabledMask
,
4902 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
4903 PP_ASSERT_WITH_CODE((0 == result
),
4904 "Set Sclk Dpm enable Mask failed", return -1);
4908 if (0 == data
->mclk_dpm_key_disabled
) {
4909 /* Checking if DPM is running. If we discover hang because of this,
4910 * we should skip this message.
4912 if (!fiji_is_dpm_running(hwmgr
))
4913 printk(KERN_ERR
"[ powerplay ]"
4914 " Trying to set Enable Mask when DPM is disabled \n");
4916 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
) {
4917 result
= smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
4918 PPSMC_MSG_MCLKDPM_SetEnabledMask
,
4919 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
);
4920 PP_ASSERT_WITH_CODE((0 == result
),
4921 "Set Mclk Dpm enable Mask failed", return -1);
4928 static int fiji_notify_link_speed_change_after_state_change(
4929 struct pp_hwmgr
*hwmgr
, const void *input
)
4931 const struct phm_set_power_state_input
*states
=
4932 (const struct phm_set_power_state_input
*)input
;
4933 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4934 const struct fiji_power_state
*fiji_ps
=
4935 cast_const_phw_fiji_power_state(states
->pnew_state
);
4936 uint16_t target_link_speed
= fiji_get_maximum_link_speed(hwmgr
, fiji_ps
);
4939 if (data
->pspp_notify_required
) {
4940 if (target_link_speed
== PP_PCIEGen3
)
4941 request
= PCIE_PERF_REQ_GEN3
;
4942 else if (target_link_speed
== PP_PCIEGen2
)
4943 request
= PCIE_PERF_REQ_GEN2
;
4945 request
= PCIE_PERF_REQ_GEN1
;
4947 if(request
== PCIE_PERF_REQ_GEN1
&&
4948 fiji_get_current_pcie_speed(hwmgr
) > 0)
4951 if (acpi_pcie_perf_request(hwmgr
->device
, request
, false)) {
4952 if (PP_PCIEGen2
== target_link_speed
)
4953 printk("PSPP request to switch to Gen2 from Gen3 Failed!");
4955 printk("PSPP request to switch to Gen1 from Gen2 Failed!");
4962 static int fiji_set_power_state_tasks(struct pp_hwmgr
*hwmgr
,
4965 int tmp_result
, result
= 0;
4967 tmp_result
= fiji_find_dpm_states_clocks_in_dpm_table(hwmgr
, input
);
4968 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4969 "Failed to find DPM states clocks in DPM table!",
4970 result
= tmp_result
);
4972 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4973 PHM_PlatformCaps_PCIEPerformanceRequest
)) {
4975 fiji_request_link_speed_change_before_state_change(hwmgr
, input
);
4976 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4977 "Failed to request link speed change before state change!",
4978 result
= tmp_result
);
4981 tmp_result
= fiji_freeze_sclk_mclk_dpm(hwmgr
);
4982 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4983 "Failed to freeze SCLK MCLK DPM!", result
= tmp_result
);
4985 tmp_result
= fiji_populate_and_upload_sclk_mclk_dpm_levels(hwmgr
, input
);
4986 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4987 "Failed to populate and upload SCLK MCLK DPM levels!",
4988 result
= tmp_result
);
4990 tmp_result
= fiji_generate_dpm_level_enable_mask(hwmgr
, input
);
4991 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4992 "Failed to generate DPM level enabled mask!",
4993 result
= tmp_result
);
4995 tmp_result
= fiji_update_vce_dpm(hwmgr
, input
);
4996 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4997 "Failed to update VCE DPM!",
4998 result
= tmp_result
);
5000 tmp_result
= fiji_update_sclk_threshold(hwmgr
);
5001 PP_ASSERT_WITH_CODE((0 == tmp_result
),
5002 "Failed to update SCLK threshold!",
5003 result
= tmp_result
);
5005 tmp_result
= fiji_program_mem_timing_parameters(hwmgr
);
5006 PP_ASSERT_WITH_CODE((0 == tmp_result
),
5007 "Failed to program memory timing parameters!",
5008 result
= tmp_result
);
5010 tmp_result
= fiji_unfreeze_sclk_mclk_dpm(hwmgr
);
5011 PP_ASSERT_WITH_CODE((0 == tmp_result
),
5012 "Failed to unfreeze SCLK MCLK DPM!",
5013 result
= tmp_result
);
5015 tmp_result
= fiji_upload_dpm_level_enable_mask(hwmgr
);
5016 PP_ASSERT_WITH_CODE((0 == tmp_result
),
5017 "Failed to upload DPM level enabled mask!",
5018 result
= tmp_result
);
5020 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
5021 PHM_PlatformCaps_PCIEPerformanceRequest
)) {
5023 fiji_notify_link_speed_change_after_state_change(hwmgr
, input
);
5024 PP_ASSERT_WITH_CODE((0 == tmp_result
),
5025 "Failed to notify link speed change after state change!",
5026 result
= tmp_result
);
5032 static int fiji_dpm_get_sclk(struct pp_hwmgr
*hwmgr
, bool low
)
5034 struct pp_power_state
*ps
;
5035 struct fiji_power_state
*fiji_ps
;
5040 ps
= hwmgr
->request_ps
;
5045 fiji_ps
= cast_phw_fiji_power_state(&ps
->hardware
);
5048 return fiji_ps
->performance_levels
[0].engine_clock
;
5050 return fiji_ps
->performance_levels
5051 [fiji_ps
->performance_level_count
-1].engine_clock
;
5054 static int fiji_dpm_get_mclk(struct pp_hwmgr
*hwmgr
, bool low
)
5056 struct pp_power_state
*ps
;
5057 struct fiji_power_state
*fiji_ps
;
5062 ps
= hwmgr
->request_ps
;
5067 fiji_ps
= cast_phw_fiji_power_state(&ps
->hardware
);
5070 return fiji_ps
->performance_levels
[0].memory_clock
;
5072 return fiji_ps
->performance_levels
5073 [fiji_ps
->performance_level_count
-1].memory_clock
;
5076 static void fiji_print_current_perforce_level(
5077 struct pp_hwmgr
*hwmgr
, struct seq_file
*m
)
5079 uint32_t sclk
, mclk
, activity_percent
= 0;
5081 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5083 smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_API_GetSclkFrequency
);
5085 sclk
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5087 smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_API_GetMclkFrequency
);
5089 mclk
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5090 seq_printf(m
, "\n [ mclk ]: %u MHz\n\n [ sclk ]: %u MHz\n",
5091 mclk
/ 100, sclk
/ 100);
5093 offset
= data
->soft_regs_start
+ offsetof(SMU73_SoftRegisters
, AverageGraphicsActivity
);
5094 activity_percent
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, offset
);
5095 activity_percent
+= 0x80;
5096 activity_percent
>>= 8;
5098 seq_printf(m
, "\n [GPU load]: %u%%\n\n", activity_percent
> 100 ? 100 : activity_percent
);
5100 seq_printf(m
, "uvd %sabled\n", data
->uvd_power_gated
? "dis" : "en");
5102 seq_printf(m
, "vce %sabled\n", data
->vce_power_gated
? "dis" : "en");
5105 static int fiji_program_display_gap(struct pp_hwmgr
*hwmgr
)
5107 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5108 uint32_t num_active_displays
= 0;
5109 uint32_t display_gap
= cgs_read_ind_register(hwmgr
->device
,
5110 CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
);
5111 uint32_t display_gap2
;
5112 uint32_t pre_vbi_time_in_us
;
5113 uint32_t frame_time_in_us
;
5115 uint32_t refresh_rate
= 0;
5116 struct cgs_display_info info
= {0};
5117 struct cgs_mode_info mode_info
;
5119 info
.mode_info
= &mode_info
;
5121 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5122 num_active_displays
= info
.display_count
;
5124 display_gap
= PHM_SET_FIELD(display_gap
, CG_DISPLAY_GAP_CNTL
,
5125 DISP_GAP
, (num_active_displays
> 0)?
5126 DISPLAY_GAP_VBLANK_OR_WM
: DISPLAY_GAP_IGNORE
);
5127 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
5128 ixCG_DISPLAY_GAP_CNTL
, display_gap
);
5130 ref_clock
= mode_info
.ref_clock
;
5131 refresh_rate
= mode_info
.refresh_rate
;
5133 if (refresh_rate
== 0)
5136 frame_time_in_us
= 1000000 / refresh_rate
;
5138 pre_vbi_time_in_us
= frame_time_in_us
- 200 - mode_info
.vblank_time_us
;
5139 display_gap2
= pre_vbi_time_in_us
* (ref_clock
/ 100);
5141 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
5142 ixCG_DISPLAY_GAP_CNTL2
, display_gap2
);
5144 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
5145 data
->soft_regs_start
+
5146 offsetof(SMU73_SoftRegisters
, PreVBlankGap
), 0x64);
5148 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
5149 data
->soft_regs_start
+
5150 offsetof(SMU73_SoftRegisters
, VBlankTimeout
),
5151 (frame_time_in_us
- pre_vbi_time_in_us
));
5153 if (num_active_displays
== 1)
5154 tonga_notify_smc_display_change(hwmgr
, true);
5159 int fiji_display_configuration_changed_task(struct pp_hwmgr
*hwmgr
)
5161 return fiji_program_display_gap(hwmgr
);
5164 static int fiji_set_max_fan_pwm_output(struct pp_hwmgr
*hwmgr
,
5165 uint16_t us_max_fan_pwm
)
5167 hwmgr
->thermal_controller
.
5168 advanceFanControlParameters
.usMaxFanPWM
= us_max_fan_pwm
;
5170 if (phm_is_hw_access_blocked(hwmgr
))
5173 return smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5174 PPSMC_MSG_SetFanPwmMax
, us_max_fan_pwm
);
5177 static int fiji_set_max_fan_rpm_output(struct pp_hwmgr
*hwmgr
,
5178 uint16_t us_max_fan_rpm
)
5180 hwmgr
->thermal_controller
.
5181 advanceFanControlParameters
.usMaxFanRPM
= us_max_fan_rpm
;
5183 if (phm_is_hw_access_blocked(hwmgr
))
5186 return smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5187 PPSMC_MSG_SetFanRpmMax
, us_max_fan_rpm
);
5190 int fiji_dpm_set_interrupt_state(void *private_data
,
5191 unsigned src_id
, unsigned type
,
5194 uint32_t cg_thermal_int
;
5195 struct pp_hwmgr
*hwmgr
= ((struct pp_eventmgr
*)private_data
)->hwmgr
;
5201 case AMD_THERMAL_IRQ_LOW_TO_HIGH
:
5203 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
,
5204 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5205 cg_thermal_int
|= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK
;
5206 cgs_write_ind_register(hwmgr
->device
,
5207 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5209 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
,
5210 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5211 cg_thermal_int
&= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK
;
5212 cgs_write_ind_register(hwmgr
->device
,
5213 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5217 case AMD_THERMAL_IRQ_HIGH_TO_LOW
:
5219 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
,
5220 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5221 cg_thermal_int
|= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK
;
5222 cgs_write_ind_register(hwmgr
->device
,
5223 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5225 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
,
5226 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5227 cg_thermal_int
&= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK
;
5228 cgs_write_ind_register(hwmgr
->device
,
5229 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5238 int fiji_register_internal_thermal_interrupt(struct pp_hwmgr
*hwmgr
,
5239 const void *thermal_interrupt_info
)
5242 const struct pp_interrupt_registration_info
*info
=
5243 (const struct pp_interrupt_registration_info
*)
5244 thermal_interrupt_info
;
5249 result
= cgs_add_irq_source(hwmgr
->device
, 230, AMD_THERMAL_IRQ_LAST
,
5250 fiji_dpm_set_interrupt_state
,
5251 info
->call_back
, info
->context
);
5256 result
= cgs_add_irq_source(hwmgr
->device
, 231, AMD_THERMAL_IRQ_LAST
,
5257 fiji_dpm_set_interrupt_state
,
5258 info
->call_back
, info
->context
);
5266 static int fiji_set_fan_control_mode(struct pp_hwmgr
*hwmgr
, uint32_t mode
)
5269 /* stop auto-manage */
5270 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
5271 PHM_PlatformCaps_MicrocodeFanControl
))
5272 fiji_fan_ctrl_stop_smc_fan_control(hwmgr
);
5273 fiji_fan_ctrl_set_static_mode(hwmgr
, mode
);
5275 /* restart auto-manage */
5276 fiji_fan_ctrl_reset_fan_speed_to_default(hwmgr
);
5281 static int fiji_get_fan_control_mode(struct pp_hwmgr
*hwmgr
)
5283 if (hwmgr
->fan_ctrl_is_in_default_mode
)
5284 return hwmgr
->fan_ctrl_default_mode
;
5286 return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
5287 CG_FDO_CTRL2
, FDO_PWM_MODE
);
5290 static int fiji_force_clock_level(struct pp_hwmgr
*hwmgr
,
5291 enum pp_clock_type type
, uint32_t mask
)
5293 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5295 if (hwmgr
->dpm_level
!= AMD_DPM_FORCED_LEVEL_MANUAL
)
5300 if (!data
->sclk_dpm_key_disabled
)
5301 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5302 PPSMC_MSG_SCLKDPM_SetEnabledMask
,
5303 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
& mask
);
5307 if (!data
->mclk_dpm_key_disabled
)
5308 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5309 PPSMC_MSG_MCLKDPM_SetEnabledMask
,
5310 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
& mask
);
5315 uint32_t tmp
= mask
& data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
;
5321 if (!data
->pcie_dpm_key_disabled
)
5322 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5323 PPSMC_MSG_PCIeDPM_ForceLevel
,
5334 static int fiji_print_clock_levels(struct pp_hwmgr
*hwmgr
,
5335 enum pp_clock_type type
, char *buf
)
5337 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5338 struct fiji_single_dpm_table
*sclk_table
= &(data
->dpm_table
.sclk_table
);
5339 struct fiji_single_dpm_table
*mclk_table
= &(data
->dpm_table
.mclk_table
);
5340 struct fiji_single_dpm_table
*pcie_table
= &(data
->dpm_table
.pcie_speed_table
);
5341 int i
, now
, size
= 0;
5342 uint32_t clock
, pcie_speed
;
5346 smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_API_GetSclkFrequency
);
5347 clock
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5349 for (i
= 0; i
< sclk_table
->count
; i
++) {
5350 if (clock
> sclk_table
->dpm_levels
[i
].value
)
5356 for (i
= 0; i
< sclk_table
->count
; i
++)
5357 size
+= sprintf(buf
+ size
, "%d: %uMhz %s\n",
5358 i
, sclk_table
->dpm_levels
[i
].value
/ 100,
5359 (i
== now
) ? "*" : "");
5362 smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_API_GetMclkFrequency
);
5363 clock
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5365 for (i
= 0; i
< mclk_table
->count
; i
++) {
5366 if (clock
> mclk_table
->dpm_levels
[i
].value
)
5372 for (i
= 0; i
< mclk_table
->count
; i
++)
5373 size
+= sprintf(buf
+ size
, "%d: %uMhz %s\n",
5374 i
, mclk_table
->dpm_levels
[i
].value
/ 100,
5375 (i
== now
) ? "*" : "");
5378 pcie_speed
= fiji_get_current_pcie_speed(hwmgr
);
5379 for (i
= 0; i
< pcie_table
->count
; i
++) {
5380 if (pcie_speed
!= pcie_table
->dpm_levels
[i
].value
)
5386 for (i
= 0; i
< pcie_table
->count
; i
++)
5387 size
+= sprintf(buf
+ size
, "%d: %s %s\n", i
,
5388 (pcie_table
->dpm_levels
[i
].value
== 0) ? "2.5GB, x1" :
5389 (pcie_table
->dpm_levels
[i
].value
== 1) ? "5.0GB, x16" :
5390 (pcie_table
->dpm_levels
[i
].value
== 2) ? "8.0GB, x16" : "",
5391 (i
== now
) ? "*" : "");
5399 static inline bool fiji_are_power_levels_equal(const struct fiji_performance_level
*pl1
,
5400 const struct fiji_performance_level
*pl2
)
5402 return ((pl1
->memory_clock
== pl2
->memory_clock
) &&
5403 (pl1
->engine_clock
== pl2
->engine_clock
) &&
5404 (pl1
->pcie_gen
== pl2
->pcie_gen
) &&
5405 (pl1
->pcie_lane
== pl2
->pcie_lane
));
5408 int fiji_check_states_equal(struct pp_hwmgr
*hwmgr
, const struct pp_hw_power_state
*pstate1
, const struct pp_hw_power_state
*pstate2
, bool *equal
)
5410 const struct fiji_power_state
*psa
= cast_const_phw_fiji_power_state(pstate1
);
5411 const struct fiji_power_state
*psb
= cast_const_phw_fiji_power_state(pstate2
);
5414 if (equal
== NULL
|| psa
== NULL
|| psb
== NULL
)
5417 /* If the two states don't even have the same number of performance levels they cannot be the same state. */
5418 if (psa
->performance_level_count
!= psb
->performance_level_count
) {
5423 for (i
= 0; i
< psa
->performance_level_count
; i
++) {
5424 if (!fiji_are_power_levels_equal(&(psa
->performance_levels
[i
]), &(psb
->performance_levels
[i
]))) {
5425 /* If we have found even one performance level pair that is different the states are different. */
5431 /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
5432 *equal
= ((psa
->uvd_clks
.vclk
== psb
->uvd_clks
.vclk
) && (psa
->uvd_clks
.dclk
== psb
->uvd_clks
.dclk
));
5433 *equal
&= ((psa
->vce_clks
.evclk
== psb
->vce_clks
.evclk
) && (psa
->vce_clks
.ecclk
== psb
->vce_clks
.ecclk
));
5434 *equal
&= (psa
->sclk_threshold
== psb
->sclk_threshold
);
5435 *equal
&= (psa
->acp_clk
== psb
->acp_clk
);
5440 bool fiji_check_smc_update_required_for_display_configuration(struct pp_hwmgr
*hwmgr
)
5442 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5443 bool is_update_required
= false;
5444 struct cgs_display_info info
= {0,0,NULL
};
5446 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5448 if (data
->display_timing
.num_existing_displays
!= info
.display_count
)
5449 is_update_required
= true;
5451 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_SclkDeepSleep
)) {
5452 if(hwmgr
->display_config
.min_core_set_clock_in_sr
!= data
->display_timing
.min_clock_in_sr
)
5453 is_update_required
= true;
5456 return is_update_required
;
5459 static int fiji_get_sclk_od(struct pp_hwmgr
*hwmgr
)
5461 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5462 struct fiji_single_dpm_table
*sclk_table
= &(data
->dpm_table
.sclk_table
);
5463 struct fiji_single_dpm_table
*golden_sclk_table
=
5464 &(data
->golden_dpm_table
.sclk_table
);
5467 value
= (sclk_table
->dpm_levels
[sclk_table
->count
- 1].value
-
5468 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
) *
5470 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
;
5475 static int fiji_set_sclk_od(struct pp_hwmgr
*hwmgr
, uint32_t value
)
5477 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5478 struct fiji_single_dpm_table
*golden_sclk_table
=
5479 &(data
->golden_dpm_table
.sclk_table
);
5480 struct pp_power_state
*ps
;
5481 struct fiji_power_state
*fiji_ps
;
5486 ps
= hwmgr
->request_ps
;
5491 fiji_ps
= cast_phw_fiji_power_state(&ps
->hardware
);
5493 fiji_ps
->performance_levels
[fiji_ps
->performance_level_count
- 1].engine_clock
=
5494 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
*
5496 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
;
5501 static int fiji_get_mclk_od(struct pp_hwmgr
*hwmgr
)
5503 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5504 struct fiji_single_dpm_table
*mclk_table
= &(data
->dpm_table
.mclk_table
);
5505 struct fiji_single_dpm_table
*golden_mclk_table
=
5506 &(data
->golden_dpm_table
.mclk_table
);
5509 value
= (mclk_table
->dpm_levels
[mclk_table
->count
- 1].value
-
5510 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
) *
5512 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
;
5517 static int fiji_set_mclk_od(struct pp_hwmgr
*hwmgr
, uint32_t value
)
5519 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5520 struct fiji_single_dpm_table
*golden_mclk_table
=
5521 &(data
->golden_dpm_table
.mclk_table
);
5522 struct pp_power_state
*ps
;
5523 struct fiji_power_state
*fiji_ps
;
5528 ps
= hwmgr
->request_ps
;
5533 fiji_ps
= cast_phw_fiji_power_state(&ps
->hardware
);
5535 fiji_ps
->performance_levels
[fiji_ps
->performance_level_count
- 1].memory_clock
=
5536 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
*
5538 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
;
5543 static const struct pp_hwmgr_func fiji_hwmgr_funcs
= {
5544 .backend_init
= &fiji_hwmgr_backend_init
,
5545 .backend_fini
= &fiji_hwmgr_backend_fini
,
5546 .asic_setup
= &fiji_setup_asic_task
,
5547 .dynamic_state_management_enable
= &fiji_enable_dpm_tasks
,
5548 .dynamic_state_management_disable
= &fiji_disable_dpm_tasks
,
5549 .force_dpm_level
= &fiji_dpm_force_dpm_level
,
5550 .get_num_of_pp_table_entries
= &tonga_get_number_of_powerplay_table_entries
,
5551 .get_power_state_size
= &fiji_get_power_state_size
,
5552 .get_pp_table_entry
= &fiji_get_pp_table_entry
,
5553 .patch_boot_state
= &fiji_patch_boot_state
,
5554 .apply_state_adjust_rules
= &fiji_apply_state_adjust_rules
,
5555 .power_state_set
= &fiji_set_power_state_tasks
,
5556 .get_sclk
= &fiji_dpm_get_sclk
,
5557 .get_mclk
= &fiji_dpm_get_mclk
,
5558 .print_current_perforce_level
= &fiji_print_current_perforce_level
,
5559 .powergate_uvd
= &fiji_phm_powergate_uvd
,
5560 .powergate_vce
= &fiji_phm_powergate_vce
,
5561 .disable_clock_power_gating
= &fiji_phm_disable_clock_power_gating
,
5562 .notify_smc_display_config_after_ps_adjustment
=
5563 &tonga_notify_smc_display_config_after_ps_adjustment
,
5564 .display_config_changed
= &fiji_display_configuration_changed_task
,
5565 .set_max_fan_pwm_output
= fiji_set_max_fan_pwm_output
,
5566 .set_max_fan_rpm_output
= fiji_set_max_fan_rpm_output
,
5567 .get_temperature
= fiji_thermal_get_temperature
,
5568 .stop_thermal_controller
= fiji_thermal_stop_thermal_controller
,
5569 .get_fan_speed_info
= fiji_fan_ctrl_get_fan_speed_info
,
5570 .get_fan_speed_percent
= fiji_fan_ctrl_get_fan_speed_percent
,
5571 .set_fan_speed_percent
= fiji_fan_ctrl_set_fan_speed_percent
,
5572 .reset_fan_speed_to_default
= fiji_fan_ctrl_reset_fan_speed_to_default
,
5573 .get_fan_speed_rpm
= fiji_fan_ctrl_get_fan_speed_rpm
,
5574 .set_fan_speed_rpm
= fiji_fan_ctrl_set_fan_speed_rpm
,
5575 .uninitialize_thermal_controller
= fiji_thermal_ctrl_uninitialize_thermal_controller
,
5576 .register_internal_thermal_interrupt
= fiji_register_internal_thermal_interrupt
,
5577 .set_fan_control_mode
= fiji_set_fan_control_mode
,
5578 .get_fan_control_mode
= fiji_get_fan_control_mode
,
5579 .check_states_equal
= fiji_check_states_equal
,
5580 .check_smc_update_required_for_display_configuration
= fiji_check_smc_update_required_for_display_configuration
,
5581 .force_clock_level
= fiji_force_clock_level
,
5582 .print_clock_levels
= fiji_print_clock_levels
,
5583 .get_sclk_od
= fiji_get_sclk_od
,
5584 .set_sclk_od
= fiji_set_sclk_od
,
5585 .get_mclk_od
= fiji_get_mclk_od
,
5586 .set_mclk_od
= fiji_set_mclk_od
,
5589 int fiji_hwmgr_init(struct pp_hwmgr
*hwmgr
)
5591 hwmgr
->hwmgr_func
= &fiji_hwmgr_funcs
;
5592 hwmgr
->pptable_func
= &tonga_pptable_funcs
;
5593 pp_fiji_thermal_initialize(hwmgr
);