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>
26 #include "linux/delay.h"
30 #include "tonga_hwmgr.h"
32 #include "processpptables.h"
33 #include "tonga_processpptables.h"
34 #include "tonga_pptable.h"
36 #include "tonga_ppsmc.h"
37 #include "cgs_common.h"
38 #include "pppcielanes.h"
39 #include "tonga_dyn_defaults.h"
41 #include "tonga_smumgr.h"
42 #include "tonga_clockpowergating.h"
43 #include "tonga_thermal.h"
45 #include "smu/smu_7_1_2_d.h"
46 #include "smu/smu_7_1_2_sh_mask.h"
48 #include "gmc/gmc_8_1_d.h"
49 #include "gmc/gmc_8_1_sh_mask.h"
51 #include "bif/bif_5_0_d.h"
52 #include "bif/bif_5_0_sh_mask.h"
54 #include "cgs_linux.h"
56 #include "amd_pcie_helpers.h"
58 #define MC_CG_ARB_FREQ_F0 0x0a
59 #define MC_CG_ARB_FREQ_F1 0x0b
60 #define MC_CG_ARB_FREQ_F2 0x0c
61 #define MC_CG_ARB_FREQ_F3 0x0d
63 #define MC_CG_SEQ_DRAMCONF_S0 0x05
64 #define MC_CG_SEQ_DRAMCONF_S1 0x06
65 #define MC_CG_SEQ_YCLK_SUSPEND 0x04
66 #define MC_CG_SEQ_YCLK_RESUME 0x0a
68 #define PCIE_BUS_CLK 10000
69 #define TCLK (PCIE_BUS_CLK / 10)
71 #define SMC_RAM_END 0x40000
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 200
80 #define VDDC_VDDGFX_DELTA 300
82 #define MC_SEQ_MISC0_GDDR5_SHIFT 28
83 #define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000
84 #define MC_SEQ_MISC0_GDDR5_VALUE 5
86 typedef uint32_t PECI_RegistryValue
;
88 /* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ] */
89 uint16_t PP_ClockStretcherLookupTable
[2][4] = {
93 /* [FF, SS] type, [] 4 voltage ranges, and [Floor Freq, Boundary Freq, VID min , VID max] */
94 uint32_t PP_ClockStretcherDDTTable
[2][4][4] = {
95 { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
96 { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
98 /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] (coming from PWR_CKS_CNTL.stretch_amount reg spec) */
99 uint8_t PP_ClockStretchAmountConversion
[2][6] = {
101 {0, 2, 4, 5, 6, 5} };
103 /* Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
105 DPM_EVENT_SRC_ANALOG
= 0, /* Internal analog trip point */
106 DPM_EVENT_SRC_EXTERNAL
= 1, /* External (GPIO 17) signal */
107 DPM_EVENT_SRC_DIGITAL
= 2, /* Internal digital trip point (DIG_THERM_DPM) */
108 DPM_EVENT_SRC_ANALOG_OR_EXTERNAL
= 3, /* Internal analog or external */
109 DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL
= 4 /* Internal digital or external */
111 typedef enum DPM_EVENT_SRC DPM_EVENT_SRC
;
113 const unsigned long PhwTonga_Magic
= (unsigned long)(PHM_VIslands_Magic
);
115 struct tonga_power_state
*cast_phw_tonga_power_state(
116 struct pp_hw_power_state
*hw_ps
)
121 PP_ASSERT_WITH_CODE((PhwTonga_Magic
== hw_ps
->magic
),
122 "Invalid Powerstate Type!",
125 return (struct tonga_power_state
*)hw_ps
;
128 const struct tonga_power_state
*cast_const_phw_tonga_power_state(
129 const struct pp_hw_power_state
*hw_ps
)
134 PP_ASSERT_WITH_CODE((PhwTonga_Magic
== hw_ps
->magic
),
135 "Invalid Powerstate Type!",
138 return (const struct tonga_power_state
*)hw_ps
;
141 int tonga_add_voltage(struct pp_hwmgr
*hwmgr
,
142 phm_ppt_v1_voltage_lookup_table
*look_up_table
,
143 phm_ppt_v1_voltage_lookup_record
*record
)
146 PP_ASSERT_WITH_CODE((NULL
!= look_up_table
),
147 "Lookup Table empty.", return -1;);
148 PP_ASSERT_WITH_CODE((0 != look_up_table
->count
),
149 "Lookup Table empty.", return -1;);
150 PP_ASSERT_WITH_CODE((SMU72_MAX_LEVELS_VDDGFX
>= look_up_table
->count
),
151 "Lookup Table is full.", return -1;);
153 /* This is to avoid entering duplicate calculated records. */
154 for (i
= 0; i
< look_up_table
->count
; i
++) {
155 if (look_up_table
->entries
[i
].us_vdd
== record
->us_vdd
) {
156 if (look_up_table
->entries
[i
].us_calculated
== 1)
163 look_up_table
->entries
[i
].us_calculated
= 1;
164 look_up_table
->entries
[i
].us_vdd
= record
->us_vdd
;
165 look_up_table
->entries
[i
].us_cac_low
= record
->us_cac_low
;
166 look_up_table
->entries
[i
].us_cac_mid
= record
->us_cac_mid
;
167 look_up_table
->entries
[i
].us_cac_high
= record
->us_cac_high
;
168 /* Only increment the count when we're appending, not replacing duplicate entry. */
169 if (i
== look_up_table
->count
)
170 look_up_table
->count
++;
175 int tonga_notify_smc_display_change(struct pp_hwmgr
*hwmgr
, bool has_display
)
177 PPSMC_Msg msg
= has_display
? (PPSMC_Msg
)PPSMC_HasDisplay
: (PPSMC_Msg
)PPSMC_NoDisplay
;
179 return (smum_send_msg_to_smc(hwmgr
->smumgr
, msg
) == 0) ? 0 : -1;
182 uint8_t tonga_get_voltage_id(pp_atomctrl_voltage_table
*voltage_table
,
185 uint8_t count
= (uint8_t) (voltage_table
->count
);
188 PP_ASSERT_WITH_CODE((NULL
!= voltage_table
),
189 "Voltage Table empty.", return 0;);
190 PP_ASSERT_WITH_CODE((0 != count
),
191 "Voltage Table empty.", return 0;);
193 for (i
= 0; i
< count
; i
++) {
194 /* find first voltage bigger than requested */
195 if (voltage_table
->entries
[i
].value
>= voltage
)
199 /* voltage is bigger than max voltage in the table */
204 * @brief PhwTonga_GetVoltageOrder
205 * Returns index of requested voltage record in lookup(table)
206 * @param hwmgr - pointer to hardware manager
207 * @param lookupTable - lookup list to search in
208 * @param voltage - voltage to look for
209 * @return 0 on success
211 uint8_t tonga_get_voltage_index(phm_ppt_v1_voltage_lookup_table
*look_up_table
,
214 uint8_t count
= (uint8_t) (look_up_table
->count
);
217 PP_ASSERT_WITH_CODE((NULL
!= look_up_table
), "Lookup Table empty.", return 0;);
218 PP_ASSERT_WITH_CODE((0 != count
), "Lookup Table empty.", return 0;);
220 for (i
= 0; i
< count
; i
++) {
221 /* find first voltage equal or bigger than requested */
222 if (look_up_table
->entries
[i
].us_vdd
>= voltage
)
226 /* voltage is bigger than max voltage in the table */
230 bool tonga_is_dpm_running(struct pp_hwmgr
*hwmgr
)
233 * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
234 * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
235 * whereas voltage control is a fundemental change that will not be disabled
238 return (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
239 FEATURE_STATUS
, VOLTAGE_CONTROLLER_ON
) ? 1 : 0);
243 * Re-generate the DPM level mask value
244 * @param hwmgr the address of the hardware manager
246 static uint32_t tonga_get_dpm_level_enable_mask_value(
247 struct tonga_single_dpm_table
* dpm_table
)
250 uint32_t mask_value
= 0;
252 for (i
= dpm_table
->count
; i
> 0; i
--) {
253 mask_value
= mask_value
<< 1;
255 if (dpm_table
->dpm_levels
[i
-1].enabled
)
258 mask_value
&= 0xFFFFFFFE;
264 * Retrieve DPM default values from registry (if available)
266 * @param hwmgr the address of the powerplay hardware manager.
268 void tonga_initialize_dpm_defaults(struct pp_hwmgr
*hwmgr
)
270 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
271 phw_tonga_ulv_parm
*ulv
= &(data
->ulv
);
274 ulv
->ch_ulv_parameter
= PPTONGA_CGULVPARAMETER_DFLT
;
275 data
->voting_rights_clients0
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0
;
276 data
->voting_rights_clients1
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1
;
277 data
->voting_rights_clients2
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2
;
278 data
->voting_rights_clients3
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3
;
279 data
->voting_rights_clients4
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4
;
280 data
->voting_rights_clients5
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5
;
281 data
->voting_rights_clients6
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6
;
282 data
->voting_rights_clients7
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7
;
284 data
->static_screen_threshold_unit
= PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT
;
285 data
->static_screen_threshold
= PPTONGA_STATICSCREENTHRESHOLD_DFLT
;
287 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
288 PHM_PlatformCaps_ABM
);
289 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
290 PHM_PlatformCaps_NonABMSupportInPPLib
);
294 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
295 PHM_PlatformCaps_DynamicACTiming
);
299 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
300 PHM_PlatformCaps_DisableMemoryTransition
);
302 data
->mclk_strobe_mode_threshold
= 40000;
303 data
->mclk_stutter_mode_threshold
= 30000;
304 data
->mclk_edc_enable_threshold
= 40000;
305 data
->mclk_edc_wr_enable_threshold
= 40000;
309 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
310 PHM_PlatformCaps_DisableMCLS
);
312 data
->pcie_gen_performance
.max
= PP_PCIEGen1
;
313 data
->pcie_gen_performance
.min
= PP_PCIEGen3
;
314 data
->pcie_gen_power_saving
.max
= PP_PCIEGen1
;
315 data
->pcie_gen_power_saving
.min
= PP_PCIEGen3
;
317 data
->pcie_lane_performance
.max
= 0;
318 data
->pcie_lane_performance
.min
= 16;
319 data
->pcie_lane_power_saving
.max
= 0;
320 data
->pcie_lane_power_saving
.min
= 16;
325 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
326 PHM_PlatformCaps_SclkThrottleLowNotification
);
328 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
329 PHM_PlatformCaps_DynamicUVDState
);
333 int tonga_update_sclk_threshold(struct pp_hwmgr
*hwmgr
)
335 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
338 uint32_t low_sclk_interrupt_threshold
= 0;
340 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
341 PHM_PlatformCaps_SclkThrottleLowNotification
)
342 && (hwmgr
->gfx_arbiter
.sclk_threshold
!= data
->low_sclk_interrupt_threshold
)) {
343 data
->low_sclk_interrupt_threshold
= hwmgr
->gfx_arbiter
.sclk_threshold
;
344 low_sclk_interrupt_threshold
= data
->low_sclk_interrupt_threshold
;
346 CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold
);
348 result
= tonga_copy_bytes_to_smc(
350 data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
,
351 LowSclkInterruptThreshold
),
352 (uint8_t *)&low_sclk_interrupt_threshold
,
362 * Find SCLK value that is associated with specified virtual_voltage_Id.
364 * @param hwmgr the address of the powerplay hardware manager.
365 * @param virtual_voltage_Id voltageId to look for.
366 * @param sclk output value .
367 * @return always 0 if success and 2 if association not found
369 static int tonga_get_sclk_for_voltage_evv(struct pp_hwmgr
*hwmgr
,
370 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
371 uint16_t virtual_voltage_id
, uint32_t *sclk
)
375 struct phm_ppt_v1_information
*pptable_info
=
376 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
378 PP_ASSERT_WITH_CODE(lookup_table
->count
!= 0, "Lookup table is empty", return -1);
380 /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
381 for (entryId
= 0; entryId
< pptable_info
->vdd_dep_on_sclk
->count
; entryId
++) {
382 voltageId
= pptable_info
->vdd_dep_on_sclk
->entries
[entryId
].vddInd
;
383 if (lookup_table
->entries
[voltageId
].us_vdd
== virtual_voltage_id
)
387 PP_ASSERT_WITH_CODE(entryId
< pptable_info
->vdd_dep_on_sclk
->count
,
388 "Can't find requested voltage id in vdd_dep_on_sclk table!",
392 *sclk
= pptable_info
->vdd_dep_on_sclk
->entries
[entryId
].clk
;
398 * Get Leakage VDDC based on leakage ID.
400 * @param hwmgr the address of the powerplay hardware manager.
401 * @return 2 if vddgfx returned is greater than 2V or if BIOS
403 int tonga_get_evv_voltage(struct pp_hwmgr
*hwmgr
)
405 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
406 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
407 phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
= pptable_info
->vdd_dep_on_sclk
;
408 uint16_t virtual_voltage_id
;
414 /* retrieve voltage for leakage ID (0xff01 + i) */
415 for (i
= 0; i
< TONGA_MAX_LEAKAGE_COUNT
; i
++) {
416 virtual_voltage_id
= ATOM_VIRTUAL_VOLTAGE_ID0
+ i
;
418 /* in split mode we should have only vddgfx EVV leakages */
419 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
420 if (0 == tonga_get_sclk_for_voltage_evv(hwmgr
,
421 pptable_info
->vddgfx_lookup_table
, virtual_voltage_id
, &sclk
)) {
422 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
423 PHM_PlatformCaps_ClockStretcher
)) {
424 for (j
= 1; j
< sclk_table
->count
; j
++) {
425 if (sclk_table
->entries
[j
].clk
== sclk
&&
426 sclk_table
->entries
[j
].cks_enable
== 0) {
432 PP_ASSERT_WITH_CODE(0 == atomctrl_get_voltage_evv_on_sclk
433 (hwmgr
, VOLTAGE_TYPE_VDDGFX
, sclk
,
434 virtual_voltage_id
, &vddgfx
),
435 "Error retrieving EVV voltage value!", continue);
437 /* need to make sure vddgfx is less than 2v or else, it could burn the ASIC. */
438 PP_ASSERT_WITH_CODE((vddgfx
< 2000 && vddgfx
!= 0), "Invalid VDDGFX value!", return -1);
440 /* the voltage should not be zero nor equal to leakage ID */
441 if (vddgfx
!= 0 && vddgfx
!= virtual_voltage_id
) {
442 data
->vddcgfx_leakage
.actual_voltage
[data
->vddcgfx_leakage
.count
] = vddgfx
;
443 data
->vddcgfx_leakage
.leakage_id
[data
->vddcgfx_leakage
.count
] = virtual_voltage_id
;
444 data
->vddcgfx_leakage
.count
++;
448 /* in merged mode we have only vddc EVV leakages */
449 if (0 == tonga_get_sclk_for_voltage_evv(hwmgr
,
450 pptable_info
->vddc_lookup_table
,
451 virtual_voltage_id
, &sclk
)) {
452 PP_ASSERT_WITH_CODE(0 == atomctrl_get_voltage_evv_on_sclk
453 (hwmgr
, VOLTAGE_TYPE_VDDC
, sclk
,
454 virtual_voltage_id
, &vddc
),
455 "Error retrieving EVV voltage value!", continue);
457 /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
459 printk(KERN_ERR
"[ powerplay ] Invalid VDDC value! \n");
461 /* the voltage should not be zero nor equal to leakage ID */
462 if (vddc
!= 0 && vddc
!= virtual_voltage_id
) {
463 data
->vddc_leakage
.actual_voltage
[data
->vddc_leakage
.count
] = vddc
;
464 data
->vddc_leakage
.leakage_id
[data
->vddc_leakage
.count
] = virtual_voltage_id
;
465 data
->vddc_leakage
.count
++;
474 int tonga_enable_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
476 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
478 /* enable SCLK dpm */
479 if (0 == data
->sclk_dpm_key_disabled
) {
481 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
482 PPSMC_MSG_DPM_Enable
)),
483 "Failed to enable SCLK DPM during DPM Start Function!",
487 /* enable MCLK dpm */
488 if (0 == data
->mclk_dpm_key_disabled
) {
490 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
491 PPSMC_MSG_MCLKDPM_Enable
)),
492 "Failed to enable MCLK DPM during DPM Start Function!",
495 PHM_WRITE_FIELD(hwmgr
->device
, MC_SEQ_CNTL_3
, CAC_EN
, 0x1);
497 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
498 ixLCAC_MC0_CNTL
, 0x05);/* CH0,1 read */
499 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
500 ixLCAC_MC1_CNTL
, 0x05);/* CH2,3 read */
501 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
502 ixLCAC_CPL_CNTL
, 0x100005);/*Read */
506 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
507 ixLCAC_MC0_CNTL
, 0x400005);/* CH0,1 write */
508 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
509 ixLCAC_MC1_CNTL
, 0x400005);/* CH2,3 write */
510 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
511 ixLCAC_CPL_CNTL
, 0x500005);/* write */
518 int tonga_start_dpm(struct pp_hwmgr
*hwmgr
)
520 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
522 /* enable general power management */
523 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, GLOBAL_PWRMGT_EN
, 1);
524 /* enable sclk deep sleep */
525 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
, DYNAMIC_PM_EN
, 1);
527 /* prepare for PCIE DPM */
528 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, data
->soft_regs_start
+
529 offsetof(SMU72_SoftRegisters
, VoltageChangeTimeout
), 0x1000);
531 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__PCIE
, SWRST_COMMAND_1
, RESETLC
, 0x0);
534 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
535 PPSMC_MSG_Voltage_Cntl_Enable
)),
536 "Failed to enable voltage DPM during DPM Start Function!",
539 if (0 != tonga_enable_sclk_mclk_dpm(hwmgr
)) {
540 PP_ASSERT_WITH_CODE(0, "Failed to enable Sclk DPM and Mclk DPM!", return -1);
543 /* enable PCIE dpm */
544 if (0 == data
->pcie_dpm_key_disabled
) {
546 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
547 PPSMC_MSG_PCIeDPM_Enable
)),
548 "Failed to enable pcie DPM during DPM Start Function!",
553 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
554 PHM_PlatformCaps_Falcon_QuickTransition
)) {
555 smum_send_msg_to_smc(hwmgr
->smumgr
,
556 PPSMC_MSG_EnableACDCGPIOInterrupt
);
562 int tonga_disable_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
564 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
566 /* disable SCLK dpm */
567 if (0 == data
->sclk_dpm_key_disabled
) {
568 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
570 (0 == tonga_is_dpm_running(hwmgr
)),
571 "Trying to Disable SCLK DPM when DPM is disabled",
576 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
577 PPSMC_MSG_DPM_Disable
)),
578 "Failed to disable SCLK DPM during DPM stop Function!",
582 /* disable MCLK dpm */
583 if (0 == data
->mclk_dpm_key_disabled
) {
584 /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
586 (0 == tonga_is_dpm_running(hwmgr
)),
587 "Trying to Disable MCLK DPM when DPM is disabled",
592 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
593 PPSMC_MSG_MCLKDPM_Disable
)),
594 "Failed to Disable MCLK DPM during DPM stop Function!",
601 int tonga_stop_dpm(struct pp_hwmgr
*hwmgr
)
603 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
605 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, GLOBAL_PWRMGT_EN
, 0);
606 /* disable sclk deep sleep*/
607 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
, DYNAMIC_PM_EN
, 0);
609 /* disable PCIE dpm */
610 if (0 == data
->pcie_dpm_key_disabled
) {
611 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
613 (0 == tonga_is_dpm_running(hwmgr
)),
614 "Trying to Disable PCIE DPM when DPM is disabled",
618 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
619 PPSMC_MSG_PCIeDPM_Disable
)),
620 "Failed to disable pcie DPM during DPM stop Function!",
624 if (0 != tonga_disable_sclk_mclk_dpm(hwmgr
))
625 PP_ASSERT_WITH_CODE(0, "Failed to disable Sclk DPM and Mclk DPM!", return -1);
627 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
629 (0 == tonga_is_dpm_running(hwmgr
)),
630 "Trying to Disable Voltage CNTL when DPM is disabled",
635 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
636 PPSMC_MSG_Voltage_Cntl_Disable
)),
637 "Failed to disable voltage DPM during DPM stop Function!",
643 int tonga_enable_sclk_control(struct pp_hwmgr
*hwmgr
)
645 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
, SCLK_PWRMGT_OFF
, 0);
651 * Send a message to the SMC and return a parameter
653 * @param hwmgr: the address of the powerplay hardware manager.
654 * @param msg: the message to send.
655 * @param parameter: pointer to the received parameter
656 * @return The response that came from the SMC.
658 PPSMC_Result
tonga_send_msg_to_smc_return_parameter(
659 struct pp_hwmgr
*hwmgr
,
665 result
= smum_send_msg_to_smc(hwmgr
->smumgr
, msg
);
667 if ((0 == result
) && parameter
) {
668 *parameter
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
675 * force DPM power State
677 * @param hwmgr: the address of the powerplay hardware manager.
678 * @param n : DPM level
679 * @return The response that came from the SMC.
681 int tonga_dpm_force_state(struct pp_hwmgr
*hwmgr
, uint32_t n
)
683 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
684 uint32_t level_mask
= 1 << n
;
686 /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
687 PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr
),
688 "Trying to force SCLK when DPM is disabled", return -1;);
689 if (0 == data
->sclk_dpm_key_disabled
)
690 return (0 == smum_send_msg_to_smc_with_parameter(
692 (PPSMC_Msg
)(PPSMC_MSG_SCLKDPM_SetEnabledMask
),
693 level_mask
) ? 0 : 1);
699 * force DPM power State
701 * @param hwmgr: the address of the powerplay hardware manager.
702 * @param n : DPM level
703 * @return The response that came from the SMC.
705 int tonga_dpm_force_state_mclk(struct pp_hwmgr
*hwmgr
, uint32_t n
)
707 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
708 uint32_t level_mask
= 1 << n
;
710 /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
711 PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr
),
712 "Trying to Force MCLK when DPM is disabled", return -1;);
713 if (0 == data
->mclk_dpm_key_disabled
)
714 return (0 == smum_send_msg_to_smc_with_parameter(
716 (PPSMC_Msg
)(PPSMC_MSG_MCLKDPM_SetEnabledMask
),
717 level_mask
) ? 0 : 1);
723 * force DPM power State
725 * @param hwmgr: the address of the powerplay hardware manager.
726 * @param n : DPM level
727 * @return The response that came from the SMC.
729 int tonga_dpm_force_state_pcie(struct pp_hwmgr
*hwmgr
, uint32_t n
)
731 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
733 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
734 PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr
),
735 "Trying to Force PCIE level when DPM is disabled", return -1;);
736 if (0 == data
->pcie_dpm_key_disabled
)
737 return (0 == smum_send_msg_to_smc_with_parameter(
739 (PPSMC_Msg
)(PPSMC_MSG_PCIeDPM_ForceLevel
),
746 * Set the initial state by calling SMC to switch to this state directly
748 * @param hwmgr the address of the powerplay hardware manager.
751 int tonga_set_boot_state(struct pp_hwmgr
*hwmgr
)
754 * SMC only stores one state that SW will ask to switch too,
755 * so we switch the the just uploaded one
757 return (0 == tonga_disable_sclk_mclk_dpm(hwmgr
)) ? 0 : 1;
761 * Get the location of various tables inside the FW image.
763 * @param hwmgr the address of the powerplay hardware manager.
766 int tonga_process_firmware_header(struct pp_hwmgr
*hwmgr
)
768 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
769 struct tonga_smumgr
*tonga_smu
= (struct tonga_smumgr
*)(hwmgr
->smumgr
->backend
);
775 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
776 SMU72_FIRMWARE_HEADER_LOCATION
+
777 offsetof(SMU72_Firmware_Header
, DpmTable
),
778 &tmp
, data
->sram_end
);
781 data
->dpm_table_start
= tmp
;
784 error
|= (0 != result
);
786 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
787 SMU72_FIRMWARE_HEADER_LOCATION
+
788 offsetof(SMU72_Firmware_Header
, SoftRegisters
),
789 &tmp
, data
->sram_end
);
792 data
->soft_regs_start
= tmp
;
793 tonga_smu
->ulSoftRegsStart
= tmp
;
796 error
|= (0 != result
);
799 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
800 SMU72_FIRMWARE_HEADER_LOCATION
+
801 offsetof(SMU72_Firmware_Header
, mcRegisterTable
),
802 &tmp
, data
->sram_end
);
805 data
->mc_reg_table_start
= tmp
;
808 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
809 SMU72_FIRMWARE_HEADER_LOCATION
+
810 offsetof(SMU72_Firmware_Header
, FanTable
),
811 &tmp
, data
->sram_end
);
814 data
->fan_table_start
= tmp
;
817 error
|= (0 != result
);
819 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
820 SMU72_FIRMWARE_HEADER_LOCATION
+
821 offsetof(SMU72_Firmware_Header
, mcArbDramTimingTable
),
822 &tmp
, data
->sram_end
);
825 data
->arb_table_start
= tmp
;
828 error
|= (0 != result
);
831 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
832 SMU72_FIRMWARE_HEADER_LOCATION
+
833 offsetof(SMU72_Firmware_Header
, Version
),
834 &tmp
, data
->sram_end
);
837 hwmgr
->microcode_version_info
.SMC
= tmp
;
840 error
|= (0 != result
);
842 return error
? 1 : 0;
846 * Read clock related registers.
848 * @param hwmgr the address of the powerplay hardware manager.
851 int tonga_read_clock_registers(struct pp_hwmgr
*hwmgr
)
853 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
855 data
->clock_registers
.vCG_SPLL_FUNC_CNTL
=
856 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL
);
857 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
=
858 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL_2
);
859 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
=
860 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL_3
);
861 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
=
862 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL_4
);
863 data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
=
864 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_SPREAD_SPECTRUM
);
865 data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
=
866 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_SPREAD_SPECTRUM_2
);
867 data
->clock_registers
.vDLL_CNTL
=
868 cgs_read_register(hwmgr
->device
, mmDLL_CNTL
);
869 data
->clock_registers
.vMCLK_PWRMGT_CNTL
=
870 cgs_read_register(hwmgr
->device
, mmMCLK_PWRMGT_CNTL
);
871 data
->clock_registers
.vMPLL_AD_FUNC_CNTL
=
872 cgs_read_register(hwmgr
->device
, mmMPLL_AD_FUNC_CNTL
);
873 data
->clock_registers
.vMPLL_DQ_FUNC_CNTL
=
874 cgs_read_register(hwmgr
->device
, mmMPLL_DQ_FUNC_CNTL
);
875 data
->clock_registers
.vMPLL_FUNC_CNTL
=
876 cgs_read_register(hwmgr
->device
, mmMPLL_FUNC_CNTL
);
877 data
->clock_registers
.vMPLL_FUNC_CNTL_1
=
878 cgs_read_register(hwmgr
->device
, mmMPLL_FUNC_CNTL_1
);
879 data
->clock_registers
.vMPLL_FUNC_CNTL_2
=
880 cgs_read_register(hwmgr
->device
, mmMPLL_FUNC_CNTL_2
);
881 data
->clock_registers
.vMPLL_SS1
=
882 cgs_read_register(hwmgr
->device
, mmMPLL_SS1
);
883 data
->clock_registers
.vMPLL_SS2
=
884 cgs_read_register(hwmgr
->device
, mmMPLL_SS2
);
890 * Find out if memory is GDDR5.
892 * @param hwmgr the address of the powerplay hardware manager.
895 int tonga_get_memory_type(struct pp_hwmgr
*hwmgr
)
897 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
900 temp
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC0
);
902 data
->is_memory_GDDR5
= (MC_SEQ_MISC0_GDDR5_VALUE
==
903 ((temp
& MC_SEQ_MISC0_GDDR5_MASK
) >>
904 MC_SEQ_MISC0_GDDR5_SHIFT
));
910 * Enables Dynamic Power Management by SMC
912 * @param hwmgr the address of the powerplay hardware manager.
915 int tonga_enable_acpi_power_management(struct pp_hwmgr
*hwmgr
)
917 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, STATIC_PM_EN
, 1);
923 * Initialize PowerGating States for different engines
925 * @param hwmgr the address of the powerplay hardware manager.
928 int tonga_init_power_gate_state(struct pp_hwmgr
*hwmgr
)
930 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
932 data
->uvd_power_gated
= 0;
933 data
->vce_power_gated
= 0;
934 data
->samu_power_gated
= 0;
935 data
->acp_power_gated
= 0;
936 data
->pg_acp_init
= 1;
942 * Checks if DPM is enabled
944 * @param hwmgr the address of the powerplay hardware manager.
947 int tonga_check_for_dpm_running(struct pp_hwmgr
*hwmgr
)
950 * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
951 * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
952 * whereas voltage control is a fundemental change that will not be disabled
954 return (0 == tonga_is_dpm_running(hwmgr
) ? 0 : 1);
958 * Checks if DPM is stopped
960 * @param hwmgr the address of the powerplay hardware manager.
963 int tonga_check_for_dpm_stopped(struct pp_hwmgr
*hwmgr
)
965 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
967 if (0 != tonga_is_dpm_running(hwmgr
)) {
968 /* If HW Virtualization is enabled, dpm_table_start will not have a valid value */
969 if (!data
->dpm_table_start
) {
978 * Remove repeated voltage values and create table with unique values.
980 * @param hwmgr the address of the powerplay hardware manager.
981 * @param voltage_table the pointer to changing voltage table
982 * @return 1 in success
985 static int tonga_trim_voltage_table(struct pp_hwmgr
*hwmgr
,
986 pp_atomctrl_voltage_table
*voltage_table
)
988 uint32_t table_size
, i
, j
;
990 bool bVoltageFound
= 0;
991 pp_atomctrl_voltage_table
*table
;
993 PP_ASSERT_WITH_CODE((NULL
!= voltage_table
), "Voltage Table empty.", return -1;);
994 table_size
= sizeof(pp_atomctrl_voltage_table
);
995 table
= kzalloc(table_size
, GFP_KERNEL
);
1000 memset(table
, 0x00, table_size
);
1001 table
->mask_low
= voltage_table
->mask_low
;
1002 table
->phase_delay
= voltage_table
->phase_delay
;
1004 for (i
= 0; i
< voltage_table
->count
; i
++) {
1005 vvalue
= voltage_table
->entries
[i
].value
;
1008 for (j
= 0; j
< table
->count
; j
++) {
1009 if (vvalue
== table
->entries
[j
].value
) {
1015 if (!bVoltageFound
) {
1016 table
->entries
[table
->count
].value
= vvalue
;
1017 table
->entries
[table
->count
].smio_low
=
1018 voltage_table
->entries
[i
].smio_low
;
1023 memcpy(table
, voltage_table
, sizeof(pp_atomctrl_voltage_table
));
1030 static int tonga_get_svi2_vdd_ci_voltage_table(
1031 struct pp_hwmgr
*hwmgr
,
1032 phm_ppt_v1_clock_voltage_dependency_table
*voltage_dependency_table
)
1036 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1037 pp_atomctrl_voltage_table
*vddci_voltage_table
= &(data
->vddci_voltage_table
);
1039 PP_ASSERT_WITH_CODE((0 != voltage_dependency_table
->count
),
1040 "Voltage Dependency Table empty.", return -1;);
1042 vddci_voltage_table
->mask_low
= 0;
1043 vddci_voltage_table
->phase_delay
= 0;
1044 vddci_voltage_table
->count
= voltage_dependency_table
->count
;
1046 for (i
= 0; i
< voltage_dependency_table
->count
; i
++) {
1047 vddci_voltage_table
->entries
[i
].value
=
1048 voltage_dependency_table
->entries
[i
].vddci
;
1049 vddci_voltage_table
->entries
[i
].smio_low
= 0;
1052 result
= tonga_trim_voltage_table(hwmgr
, vddci_voltage_table
);
1053 PP_ASSERT_WITH_CODE((0 == result
),
1054 "Failed to trim VDDCI table.", return result
;);
1061 static int tonga_get_svi2_vdd_voltage_table(
1062 struct pp_hwmgr
*hwmgr
,
1063 phm_ppt_v1_voltage_lookup_table
*look_up_table
,
1064 pp_atomctrl_voltage_table
*voltage_table
)
1068 PP_ASSERT_WITH_CODE((0 != look_up_table
->count
),
1069 "Voltage Lookup Table empty.", return -1;);
1071 voltage_table
->mask_low
= 0;
1072 voltage_table
->phase_delay
= 0;
1074 voltage_table
->count
= look_up_table
->count
;
1076 for (i
= 0; i
< voltage_table
->count
; i
++) {
1077 voltage_table
->entries
[i
].value
= look_up_table
->entries
[i
].us_vdd
;
1078 voltage_table
->entries
[i
].smio_low
= 0;
1085 * -------------------------------------------------------- Voltage Tables --------------------------------------------------------------------------
1086 * If the voltage table would be bigger than what will fit into the state table on the SMC keep only the higher entries.
1089 static void tonga_trim_voltage_table_to_fit_state_table(
1090 struct pp_hwmgr
*hwmgr
,
1091 uint32_t max_voltage_steps
,
1092 pp_atomctrl_voltage_table
*voltage_table
)
1094 unsigned int i
, diff
;
1096 if (voltage_table
->count
<= max_voltage_steps
) {
1100 diff
= voltage_table
->count
- max_voltage_steps
;
1102 for (i
= 0; i
< max_voltage_steps
; i
++) {
1103 voltage_table
->entries
[i
] = voltage_table
->entries
[i
+ diff
];
1106 voltage_table
->count
= max_voltage_steps
;
1112 * Create Voltage Tables.
1114 * @param hwmgr the address of the powerplay hardware manager.
1117 int tonga_construct_voltage_tables(struct pp_hwmgr
*hwmgr
)
1119 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1120 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1123 /* MVDD has only GPIO voltage control */
1124 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1125 result
= atomctrl_get_voltage_table_v3(hwmgr
,
1126 VOLTAGE_TYPE_MVDDC
, VOLTAGE_OBJ_GPIO_LUT
, &(data
->mvdd_voltage_table
));
1127 PP_ASSERT_WITH_CODE((0 == result
),
1128 "Failed to retrieve MVDD table.", return result
;);
1131 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->vdd_ci_control
) {
1133 result
= atomctrl_get_voltage_table_v3(hwmgr
,
1134 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_GPIO_LUT
, &(data
->vddci_voltage_table
));
1135 PP_ASSERT_WITH_CODE((0 == result
),
1136 "Failed to retrieve VDDCI table.", return result
;);
1137 } else if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_ci_control
) {
1139 result
= tonga_get_svi2_vdd_ci_voltage_table(hwmgr
,
1140 pptable_info
->vdd_dep_on_mclk
);
1141 PP_ASSERT_WITH_CODE((0 == result
),
1142 "Failed to retrieve SVI2 VDDCI table from dependancy table.", return result
;);
1145 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_gfx_control
) {
1146 /* VDDGFX has only SVI2 voltage control */
1147 result
= tonga_get_svi2_vdd_voltage_table(hwmgr
,
1148 pptable_info
->vddgfx_lookup_table
, &(data
->vddgfx_voltage_table
));
1149 PP_ASSERT_WITH_CODE((0 == result
),
1150 "Failed to retrieve SVI2 VDDGFX table from lookup table.", return result
;);
1153 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1154 /* VDDC has only SVI2 voltage control */
1155 result
= tonga_get_svi2_vdd_voltage_table(hwmgr
,
1156 pptable_info
->vddc_lookup_table
, &(data
->vddc_voltage_table
));
1157 PP_ASSERT_WITH_CODE((0 == result
),
1158 "Failed to retrieve SVI2 VDDC table from lookup table.", return result
;);
1161 PP_ASSERT_WITH_CODE(
1162 (data
->vddc_voltage_table
.count
<= (SMU72_MAX_LEVELS_VDDC
)),
1163 "Too many voltage values for VDDC. Trimming to fit state table.",
1164 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1165 SMU72_MAX_LEVELS_VDDC
, &(data
->vddc_voltage_table
));
1168 PP_ASSERT_WITH_CODE(
1169 (data
->vddgfx_voltage_table
.count
<= (SMU72_MAX_LEVELS_VDDGFX
)),
1170 "Too many voltage values for VDDGFX. Trimming to fit state table.",
1171 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1172 SMU72_MAX_LEVELS_VDDGFX
, &(data
->vddgfx_voltage_table
));
1175 PP_ASSERT_WITH_CODE(
1176 (data
->vddci_voltage_table
.count
<= (SMU72_MAX_LEVELS_VDDCI
)),
1177 "Too many voltage values for VDDCI. Trimming to fit state table.",
1178 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1179 SMU72_MAX_LEVELS_VDDCI
, &(data
->vddci_voltage_table
));
1182 PP_ASSERT_WITH_CODE(
1183 (data
->mvdd_voltage_table
.count
<= (SMU72_MAX_LEVELS_MVDD
)),
1184 "Too many voltage values for MVDD. Trimming to fit state table.",
1185 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1186 SMU72_MAX_LEVELS_MVDD
, &(data
->mvdd_voltage_table
));
1193 * Vddc table preparation for SMC.
1195 * @param hwmgr the address of the hardware manager
1196 * @param table the SMC DPM table structure to be populated
1199 static int tonga_populate_smc_vddc_table(struct pp_hwmgr
*hwmgr
,
1200 SMU72_Discrete_DpmTable
*table
)
1203 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1205 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1206 table
->VddcLevelCount
= data
->vddc_voltage_table
.count
;
1207 for (count
= 0; count
< table
->VddcLevelCount
; count
++) {
1208 table
->VddcTable
[count
] =
1209 PP_HOST_TO_SMC_US(data
->vddc_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1211 CONVERT_FROM_HOST_TO_SMC_UL(table
->VddcLevelCount
);
1217 * VddGfx table preparation for SMC.
1219 * @param hwmgr the address of the hardware manager
1220 * @param table the SMC DPM table structure to be populated
1223 static int tonga_populate_smc_vdd_gfx_table(struct pp_hwmgr
*hwmgr
,
1224 SMU72_Discrete_DpmTable
*table
)
1227 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1229 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_gfx_control
) {
1230 table
->VddGfxLevelCount
= data
->vddgfx_voltage_table
.count
;
1231 for (count
= 0; count
< data
->vddgfx_voltage_table
.count
; count
++) {
1232 table
->VddGfxTable
[count
] =
1233 PP_HOST_TO_SMC_US(data
->vddgfx_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1235 CONVERT_FROM_HOST_TO_SMC_UL(table
->VddGfxLevelCount
);
1241 * Vddci table preparation for SMC.
1243 * @param *hwmgr The address of the hardware manager.
1244 * @param *table The SMC DPM table structure to be populated.
1247 static int tonga_populate_smc_vdd_ci_table(struct pp_hwmgr
*hwmgr
,
1248 SMU72_Discrete_DpmTable
*table
)
1250 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1253 table
->VddciLevelCount
= data
->vddci_voltage_table
.count
;
1254 for (count
= 0; count
< table
->VddciLevelCount
; count
++) {
1255 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_ci_control
) {
1256 table
->VddciTable
[count
] =
1257 PP_HOST_TO_SMC_US(data
->vddci_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1258 } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->vdd_ci_control
) {
1259 table
->SmioTable1
.Pattern
[count
].Voltage
=
1260 PP_HOST_TO_SMC_US(data
->vddci_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1261 /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level. */
1262 table
->SmioTable1
.Pattern
[count
].Smio
=
1264 table
->Smio
[count
] |=
1265 data
->vddci_voltage_table
.entries
[count
].smio_low
;
1266 table
->VddciTable
[count
] =
1267 PP_HOST_TO_SMC_US(data
->vddci_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1271 table
->SmioMask1
= data
->vddci_voltage_table
.mask_low
;
1272 CONVERT_FROM_HOST_TO_SMC_UL(table
->VddciLevelCount
);
1278 * Mvdd table preparation for SMC.
1280 * @param *hwmgr The address of the hardware manager.
1281 * @param *table The SMC DPM table structure to be populated.
1284 static int tonga_populate_smc_mvdd_table(struct pp_hwmgr
*hwmgr
,
1285 SMU72_Discrete_DpmTable
*table
)
1287 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1290 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1291 table
->MvddLevelCount
= data
->mvdd_voltage_table
.count
;
1292 for (count
= 0; count
< table
->MvddLevelCount
; count
++) {
1293 table
->SmioTable2
.Pattern
[count
].Voltage
=
1294 PP_HOST_TO_SMC_US(data
->mvdd_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1295 /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/
1296 table
->SmioTable2
.Pattern
[count
].Smio
=
1298 table
->Smio
[count
] |=
1299 data
->mvdd_voltage_table
.entries
[count
].smio_low
;
1301 table
->SmioMask2
= data
->vddci_voltage_table
.mask_low
;
1303 CONVERT_FROM_HOST_TO_SMC_UL(table
->MvddLevelCount
);
1310 * Convert a voltage value in mv unit to VID number required by SMU firmware
1312 static uint8_t convert_to_vid(uint16_t vddc
)
1314 return (uint8_t) ((6200 - (vddc
* VOLTAGE_SCALE
)) / 25);
1319 * Preparation of vddc and vddgfx CAC tables for SMC.
1321 * @param hwmgr the address of the hardware manager
1322 * @param table the SMC DPM table structure to be populated
1325 static int tonga_populate_cac_tables(struct pp_hwmgr
*hwmgr
,
1326 SMU72_Discrete_DpmTable
*table
)
1331 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1332 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1333 struct phm_ppt_v1_voltage_lookup_table
*vddgfx_lookup_table
= pptable_info
->vddgfx_lookup_table
;
1334 struct phm_ppt_v1_voltage_lookup_table
*vddc_lookup_table
= pptable_info
->vddc_lookup_table
;
1336 /* pTables is already swapped, so in order to use the value from it, we need to swap it back. */
1337 uint32_t vddcLevelCount
= PP_SMC_TO_HOST_UL(table
->VddcLevelCount
);
1338 uint32_t vddgfxLevelCount
= PP_SMC_TO_HOST_UL(table
->VddGfxLevelCount
);
1340 for (count
= 0; count
< vddcLevelCount
; count
++) {
1341 /* We are populating vddc CAC data to BapmVddc table in split and merged mode */
1342 index
= tonga_get_voltage_index(vddc_lookup_table
,
1343 data
->vddc_voltage_table
.entries
[count
].value
);
1344 table
->BapmVddcVidLoSidd
[count
] =
1345 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_low
);
1346 table
->BapmVddcVidHiSidd
[count
] =
1347 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_mid
);
1348 table
->BapmVddcVidHiSidd2
[count
] =
1349 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_high
);
1352 if ((data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
)) {
1353 /* We are populating vddgfx CAC data to BapmVddgfx table in split mode */
1354 for (count
= 0; count
< vddgfxLevelCount
; count
++) {
1355 index
= tonga_get_voltage_index(vddgfx_lookup_table
,
1356 data
->vddgfx_voltage_table
.entries
[count
].value
);
1357 table
->BapmVddGfxVidLoSidd
[count
] =
1358 convert_to_vid(vddgfx_lookup_table
->entries
[index
].us_cac_low
);
1359 table
->BapmVddGfxVidHiSidd
[count
] =
1360 convert_to_vid(vddgfx_lookup_table
->entries
[index
].us_cac_mid
);
1361 table
->BapmVddGfxVidHiSidd2
[count
] =
1362 convert_to_vid(vddgfx_lookup_table
->entries
[index
].us_cac_high
);
1365 for (count
= 0; count
< vddcLevelCount
; count
++) {
1366 index
= tonga_get_voltage_index(vddc_lookup_table
,
1367 data
->vddc_voltage_table
.entries
[count
].value
);
1368 table
->BapmVddGfxVidLoSidd
[count
] =
1369 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_low
);
1370 table
->BapmVddGfxVidHiSidd
[count
] =
1371 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_mid
);
1372 table
->BapmVddGfxVidHiSidd2
[count
] =
1373 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_high
);
1382 * Preparation of voltage tables for SMC.
1384 * @param hwmgr the address of the hardware manager
1385 * @param table the SMC DPM table structure to be populated
1389 int tonga_populate_smc_voltage_tables(struct pp_hwmgr
*hwmgr
,
1390 SMU72_Discrete_DpmTable
*table
)
1394 result
= tonga_populate_smc_vddc_table(hwmgr
, table
);
1395 PP_ASSERT_WITH_CODE(0 == result
,
1396 "can not populate VDDC voltage table to SMC", return -1);
1398 result
= tonga_populate_smc_vdd_ci_table(hwmgr
, table
);
1399 PP_ASSERT_WITH_CODE(0 == result
,
1400 "can not populate VDDCI voltage table to SMC", return -1);
1402 result
= tonga_populate_smc_vdd_gfx_table(hwmgr
, table
);
1403 PP_ASSERT_WITH_CODE(0 == result
,
1404 "can not populate VDDGFX voltage table to SMC", return -1);
1406 result
= tonga_populate_smc_mvdd_table(hwmgr
, table
);
1407 PP_ASSERT_WITH_CODE(0 == result
,
1408 "can not populate MVDD voltage table to SMC", return -1);
1410 result
= tonga_populate_cac_tables(hwmgr
, table
);
1411 PP_ASSERT_WITH_CODE(0 == result
,
1412 "can not populate CAC voltage tables to SMC", return -1);
1418 * Populates the SMC VRConfig field in DPM table.
1420 * @param hwmgr the address of the hardware manager
1421 * @param table the SMC DPM table structure to be populated
1424 static int tonga_populate_vr_config(struct pp_hwmgr
*hwmgr
,
1425 SMU72_Discrete_DpmTable
*table
)
1427 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1430 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_gfx_control
) {
1432 config
= VR_SVI2_PLANE_1
;
1433 table
->VRConfig
|= (config
<<VRCONF_VDDGFX_SHIFT
);
1435 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1436 config
= VR_SVI2_PLANE_2
;
1437 table
->VRConfig
|= config
;
1439 printk(KERN_ERR
"[ powerplay ] VDDC and VDDGFX should be both on SVI2 control in splitted mode! \n");
1443 config
= VR_MERGED_WITH_VDDC
;
1444 table
->VRConfig
|= (config
<<VRCONF_VDDGFX_SHIFT
);
1446 /* Set Vddc Voltage Controller */
1447 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1448 config
= VR_SVI2_PLANE_1
;
1449 table
->VRConfig
|= config
;
1451 printk(KERN_ERR
"[ powerplay ] VDDC should be on SVI2 control in merged mode! \n");
1455 /* Set Vddci Voltage Controller */
1456 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_ci_control
) {
1457 config
= VR_SVI2_PLANE_2
; /* only in merged mode */
1458 table
->VRConfig
|= (config
<<VRCONF_VDDCI_SHIFT
);
1459 } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->vdd_ci_control
) {
1460 config
= VR_SMIO_PATTERN_1
;
1461 table
->VRConfig
|= (config
<<VRCONF_VDDCI_SHIFT
);
1464 /* Set Mvdd Voltage Controller */
1465 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1466 config
= VR_SMIO_PATTERN_2
;
1467 table
->VRConfig
|= (config
<<VRCONF_MVDD_SHIFT
);
1473 static int tonga_get_dependecy_volt_by_clk(struct pp_hwmgr
*hwmgr
,
1474 phm_ppt_v1_clock_voltage_dependency_table
*allowed_clock_voltage_table
,
1475 uint32_t clock
, SMU_VoltageLevel
*voltage
, uint32_t *mvdd
)
1478 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1479 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1481 /* clock - voltage dependency table is empty table */
1482 if (allowed_clock_voltage_table
->count
== 0)
1485 for (i
= 0; i
< allowed_clock_voltage_table
->count
; i
++) {
1486 /* find first sclk bigger than request */
1487 if (allowed_clock_voltage_table
->entries
[i
].clk
>= clock
) {
1488 voltage
->VddGfx
= tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1489 allowed_clock_voltage_table
->entries
[i
].vddgfx
);
1491 voltage
->Vddc
= tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1492 allowed_clock_voltage_table
->entries
[i
].vddc
);
1494 if (allowed_clock_voltage_table
->entries
[i
].vddci
) {
1495 voltage
->Vddci
= tonga_get_voltage_id(&data
->vddci_voltage_table
,
1496 allowed_clock_voltage_table
->entries
[i
].vddci
);
1498 voltage
->Vddci
= tonga_get_voltage_id(&data
->vddci_voltage_table
,
1499 allowed_clock_voltage_table
->entries
[i
].vddc
- data
->vddc_vddci_delta
);
1502 if (allowed_clock_voltage_table
->entries
[i
].mvdd
) {
1503 *mvdd
= (uint32_t) allowed_clock_voltage_table
->entries
[i
].mvdd
;
1506 voltage
->Phases
= 1;
1511 /* sclk is bigger than max sclk in the dependence table */
1512 voltage
->VddGfx
= tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1513 allowed_clock_voltage_table
->entries
[i
-1].vddgfx
);
1514 voltage
->Vddc
= tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1515 allowed_clock_voltage_table
->entries
[i
-1].vddc
);
1517 if (allowed_clock_voltage_table
->entries
[i
-1].vddci
) {
1518 voltage
->Vddci
= tonga_get_voltage_id(&data
->vddci_voltage_table
,
1519 allowed_clock_voltage_table
->entries
[i
-1].vddci
);
1521 if (allowed_clock_voltage_table
->entries
[i
-1].mvdd
) {
1522 *mvdd
= (uint32_t) allowed_clock_voltage_table
->entries
[i
-1].mvdd
;
1529 * Call SMC to reset S0/S1 to S1 and Reset SMIO to initial value
1531 * @param hwmgr the address of the powerplay hardware manager.
1534 int tonga_reset_to_default(struct pp_hwmgr
*hwmgr
)
1536 return (smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_ResetToDefaults
) == 0) ? 0 : 1;
1539 int tonga_populate_memory_timing_parameters(
1540 struct pp_hwmgr
*hwmgr
,
1541 uint32_t engine_clock
,
1542 uint32_t memory_clock
,
1543 struct SMU72_Discrete_MCArbDramTimingTableEntry
*arb_regs
1546 uint32_t dramTiming
;
1547 uint32_t dramTiming2
;
1551 result
= atomctrl_set_engine_dram_timings_rv770(hwmgr
,
1552 engine_clock
, memory_clock
);
1554 PP_ASSERT_WITH_CODE(result
== 0,
1555 "Error calling VBIOS to set DRAM_TIMING.", return result
);
1557 dramTiming
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
1558 dramTiming2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
1559 burstTime
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
);
1561 arb_regs
->McArbDramTiming
= PP_HOST_TO_SMC_UL(dramTiming
);
1562 arb_regs
->McArbDramTiming2
= PP_HOST_TO_SMC_UL(dramTiming2
);
1563 arb_regs
->McArbBurstTime
= (uint8_t)burstTime
;
1569 * Setup parameters for the MC ARB.
1571 * @param hwmgr the address of the powerplay hardware manager.
1573 * This function is to be called from the SetPowerState table.
1575 int tonga_program_memory_timing_parameters(struct pp_hwmgr
*hwmgr
)
1577 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1579 SMU72_Discrete_MCArbDramTimingTable arb_regs
;
1582 memset(&arb_regs
, 0x00, sizeof(SMU72_Discrete_MCArbDramTimingTable
));
1584 for (i
= 0; i
< data
->dpm_table
.sclk_table
.count
; i
++) {
1585 for (j
= 0; j
< data
->dpm_table
.mclk_table
.count
; j
++) {
1586 result
= tonga_populate_memory_timing_parameters
1587 (hwmgr
, data
->dpm_table
.sclk_table
.dpm_levels
[i
].value
,
1588 data
->dpm_table
.mclk_table
.dpm_levels
[j
].value
,
1589 &arb_regs
.entries
[i
][j
]);
1598 result
= tonga_copy_bytes_to_smc(
1600 data
->arb_table_start
,
1601 (uint8_t *)&arb_regs
,
1602 sizeof(SMU72_Discrete_MCArbDramTimingTable
),
1610 static int tonga_populate_smc_link_level(struct pp_hwmgr
*hwmgr
, SMU72_Discrete_DpmTable
*table
)
1612 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1613 struct tonga_dpm_table
*dpm_table
= &data
->dpm_table
;
1616 /* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */
1617 for (i
= 0; i
<= dpm_table
->pcie_speed_table
.count
; i
++) {
1618 table
->LinkLevel
[i
].PcieGenSpeed
=
1619 (uint8_t)dpm_table
->pcie_speed_table
.dpm_levels
[i
].value
;
1620 table
->LinkLevel
[i
].PcieLaneCount
=
1621 (uint8_t)encode_pcie_lane_width(dpm_table
->pcie_speed_table
.dpm_levels
[i
].param1
);
1622 table
->LinkLevel
[i
].EnabledForActivity
=
1624 table
->LinkLevel
[i
].SPC
=
1625 (uint8_t)(data
->pcie_spc_cap
& 0xff);
1626 table
->LinkLevel
[i
].DownThreshold
=
1627 PP_HOST_TO_SMC_UL(5);
1628 table
->LinkLevel
[i
].UpThreshold
=
1629 PP_HOST_TO_SMC_UL(30);
1632 data
->smc_state_table
.LinkLevelCount
=
1633 (uint8_t)dpm_table
->pcie_speed_table
.count
;
1634 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
=
1635 tonga_get_dpm_level_enable_mask_value(&dpm_table
->pcie_speed_table
);
1640 static int tonga_populate_smc_uvd_level(struct pp_hwmgr
*hwmgr
,
1641 SMU72_Discrete_DpmTable
*table
)
1646 pp_atomctrl_clock_dividers_vi dividers
;
1647 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1648 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1649 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1651 table
->UvdLevelCount
= (uint8_t) (mm_table
->count
);
1652 table
->UvdBootLevel
= 0;
1654 for (count
= 0; count
< table
->UvdLevelCount
; count
++) {
1655 table
->UvdLevel
[count
].VclkFrequency
= mm_table
->entries
[count
].vclk
;
1656 table
->UvdLevel
[count
].DclkFrequency
= mm_table
->entries
[count
].dclk
;
1657 table
->UvdLevel
[count
].MinVoltage
.Vddc
=
1658 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1659 mm_table
->entries
[count
].vddc
);
1660 table
->UvdLevel
[count
].MinVoltage
.VddGfx
=
1661 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1662 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1663 mm_table
->entries
[count
].vddgfx
) : 0;
1664 table
->UvdLevel
[count
].MinVoltage
.Vddci
=
1665 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1666 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1667 table
->UvdLevel
[count
].MinVoltage
.Phases
= 1;
1669 /* retrieve divider value for VBIOS */
1670 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1671 table
->UvdLevel
[count
].VclkFrequency
, ÷rs
);
1672 PP_ASSERT_WITH_CODE((0 == result
),
1673 "can not find divide id for Vclk clock", return result
);
1675 table
->UvdLevel
[count
].VclkDivider
= (uint8_t)dividers
.pll_post_divider
;
1677 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1678 table
->UvdLevel
[count
].DclkFrequency
, ÷rs
);
1679 PP_ASSERT_WITH_CODE((0 == result
),
1680 "can not find divide id for Dclk clock", return result
);
1682 table
->UvdLevel
[count
].DclkDivider
= (uint8_t)dividers
.pll_post_divider
;
1684 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].VclkFrequency
);
1685 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].DclkFrequency
);
1686 //CONVERT_FROM_HOST_TO_SMC_UL((uint32_t)table->UvdLevel[count].MinVoltage);
1693 static int tonga_populate_smc_vce_level(struct pp_hwmgr
*hwmgr
,
1694 SMU72_Discrete_DpmTable
*table
)
1699 pp_atomctrl_clock_dividers_vi dividers
;
1700 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1701 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1702 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1704 table
->VceLevelCount
= (uint8_t) (mm_table
->count
);
1705 table
->VceBootLevel
= 0;
1707 for (count
= 0; count
< table
->VceLevelCount
; count
++) {
1708 table
->VceLevel
[count
].Frequency
=
1709 mm_table
->entries
[count
].eclk
;
1710 table
->VceLevel
[count
].MinVoltage
.Vddc
=
1711 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1712 mm_table
->entries
[count
].vddc
);
1713 table
->VceLevel
[count
].MinVoltage
.VddGfx
=
1714 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1715 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1716 mm_table
->entries
[count
].vddgfx
) : 0;
1717 table
->VceLevel
[count
].MinVoltage
.Vddci
=
1718 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1719 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1720 table
->VceLevel
[count
].MinVoltage
.Phases
= 1;
1722 /* retrieve divider value for VBIOS */
1723 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1724 table
->VceLevel
[count
].Frequency
, ÷rs
);
1725 PP_ASSERT_WITH_CODE((0 == result
),
1726 "can not find divide id for VCE engine clock", return result
);
1728 table
->VceLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1730 CONVERT_FROM_HOST_TO_SMC_UL(table
->VceLevel
[count
].Frequency
);
1736 static int tonga_populate_smc_acp_level(struct pp_hwmgr
*hwmgr
,
1737 SMU72_Discrete_DpmTable
*table
)
1741 pp_atomctrl_clock_dividers_vi dividers
;
1742 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1743 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1744 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1746 table
->AcpLevelCount
= (uint8_t) (mm_table
->count
);
1747 table
->AcpBootLevel
= 0;
1749 for (count
= 0; count
< table
->AcpLevelCount
; count
++) {
1750 table
->AcpLevel
[count
].Frequency
=
1751 pptable_info
->mm_dep_table
->entries
[count
].aclk
;
1752 table
->AcpLevel
[count
].MinVoltage
.Vddc
=
1753 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1754 mm_table
->entries
[count
].vddc
);
1755 table
->AcpLevel
[count
].MinVoltage
.VddGfx
=
1756 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1757 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1758 mm_table
->entries
[count
].vddgfx
) : 0;
1759 table
->AcpLevel
[count
].MinVoltage
.Vddci
=
1760 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1761 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1762 table
->AcpLevel
[count
].MinVoltage
.Phases
= 1;
1764 /* retrieve divider value for VBIOS */
1765 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1766 table
->AcpLevel
[count
].Frequency
, ÷rs
);
1767 PP_ASSERT_WITH_CODE((0 == result
),
1768 "can not find divide id for engine clock", return result
);
1770 table
->AcpLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1772 CONVERT_FROM_HOST_TO_SMC_UL(table
->AcpLevel
[count
].Frequency
);
1778 static int tonga_populate_smc_samu_level(struct pp_hwmgr
*hwmgr
,
1779 SMU72_Discrete_DpmTable
*table
)
1783 pp_atomctrl_clock_dividers_vi dividers
;
1784 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1785 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1786 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1788 table
->SamuBootLevel
= 0;
1789 table
->SamuLevelCount
= (uint8_t) (mm_table
->count
);
1791 for (count
= 0; count
< table
->SamuLevelCount
; count
++) {
1792 /* not sure whether we need evclk or not */
1793 table
->SamuLevel
[count
].Frequency
=
1794 pptable_info
->mm_dep_table
->entries
[count
].samclock
;
1795 table
->SamuLevel
[count
].MinVoltage
.Vddc
=
1796 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1797 mm_table
->entries
[count
].vddc
);
1798 table
->SamuLevel
[count
].MinVoltage
.VddGfx
=
1799 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1800 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1801 mm_table
->entries
[count
].vddgfx
) : 0;
1802 table
->SamuLevel
[count
].MinVoltage
.Vddci
=
1803 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1804 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1805 table
->SamuLevel
[count
].MinVoltage
.Phases
= 1;
1807 /* retrieve divider value for VBIOS */
1808 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1809 table
->SamuLevel
[count
].Frequency
, ÷rs
);
1810 PP_ASSERT_WITH_CODE((0 == result
),
1811 "can not find divide id for samu clock", return result
);
1813 table
->SamuLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1815 CONVERT_FROM_HOST_TO_SMC_UL(table
->SamuLevel
[count
].Frequency
);
1822 * Populates the SMC MCLK structure using the provided memory clock
1824 * @param hwmgr the address of the hardware manager
1825 * @param memory_clock the memory clock to use to populate the structure
1826 * @param sclk the SMC SCLK structure to be populated
1828 static int tonga_calculate_mclk_params(
1829 struct pp_hwmgr
*hwmgr
,
1830 uint32_t memory_clock
,
1831 SMU72_Discrete_MemoryLevel
*mclk
,
1836 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1837 uint32_t dll_cntl
= data
->clock_registers
.vDLL_CNTL
;
1838 uint32_t mclk_pwrmgt_cntl
= data
->clock_registers
.vMCLK_PWRMGT_CNTL
;
1839 uint32_t mpll_ad_func_cntl
= data
->clock_registers
.vMPLL_AD_FUNC_CNTL
;
1840 uint32_t mpll_dq_func_cntl
= data
->clock_registers
.vMPLL_DQ_FUNC_CNTL
;
1841 uint32_t mpll_func_cntl
= data
->clock_registers
.vMPLL_FUNC_CNTL
;
1842 uint32_t mpll_func_cntl_1
= data
->clock_registers
.vMPLL_FUNC_CNTL_1
;
1843 uint32_t mpll_func_cntl_2
= data
->clock_registers
.vMPLL_FUNC_CNTL_2
;
1844 uint32_t mpll_ss1
= data
->clock_registers
.vMPLL_SS1
;
1845 uint32_t mpll_ss2
= data
->clock_registers
.vMPLL_SS2
;
1847 pp_atomctrl_memory_clock_param mpll_param
;
1850 result
= atomctrl_get_memory_pll_dividers_si(hwmgr
,
1851 memory_clock
, &mpll_param
, strobe_mode
);
1852 PP_ASSERT_WITH_CODE(0 == result
,
1853 "Error retrieving Memory Clock Parameters from VBIOS.", return result
);
1855 /* MPLL_FUNC_CNTL setup*/
1856 mpll_func_cntl
= PHM_SET_FIELD(mpll_func_cntl
, MPLL_FUNC_CNTL
, BWCTRL
, mpll_param
.bw_ctrl
);
1858 /* MPLL_FUNC_CNTL_1 setup*/
1859 mpll_func_cntl_1
= PHM_SET_FIELD(mpll_func_cntl_1
,
1860 MPLL_FUNC_CNTL_1
, CLKF
, mpll_param
.mpll_fb_divider
.cl_kf
);
1861 mpll_func_cntl_1
= PHM_SET_FIELD(mpll_func_cntl_1
,
1862 MPLL_FUNC_CNTL_1
, CLKFRAC
, mpll_param
.mpll_fb_divider
.clk_frac
);
1863 mpll_func_cntl_1
= PHM_SET_FIELD(mpll_func_cntl_1
,
1864 MPLL_FUNC_CNTL_1
, VCO_MODE
, mpll_param
.vco_mode
);
1866 /* MPLL_AD_FUNC_CNTL setup*/
1867 mpll_ad_func_cntl
= PHM_SET_FIELD(mpll_ad_func_cntl
,
1868 MPLL_AD_FUNC_CNTL
, YCLK_POST_DIV
, mpll_param
.mpll_post_divider
);
1870 if (data
->is_memory_GDDR5
) {
1871 /* MPLL_DQ_FUNC_CNTL setup*/
1872 mpll_dq_func_cntl
= PHM_SET_FIELD(mpll_dq_func_cntl
,
1873 MPLL_DQ_FUNC_CNTL
, YCLK_SEL
, mpll_param
.yclk_sel
);
1874 mpll_dq_func_cntl
= PHM_SET_FIELD(mpll_dq_func_cntl
,
1875 MPLL_DQ_FUNC_CNTL
, YCLK_POST_DIV
, mpll_param
.mpll_post_divider
);
1878 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
1879 PHM_PlatformCaps_MemorySpreadSpectrumSupport
)) {
1881 ************************************
1882 Fref = Reference Frequency
1883 NF = Feedback divider ratio
1884 NR = Reference divider ratio
1885 Fnom = Nominal VCO output frequency = Fref * NF / NR
1887 D = Percentage down-spread / 2
1888 Fint = Reference input frequency to PFD = Fref / NR
1889 NS = Spreading rate divider ratio = int(Fint / (2 * Fs))
1890 CLKS = NS - 1 = ISS_STEP_NUM[11:0]
1891 NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2)
1892 CLKV = 65536 * NV = ISS_STEP_SIZE[25:0]
1893 *************************************
1895 pp_atomctrl_internal_ss_info ss_info
;
1898 uint32_t reference_clock
= atomctrl_get_mpll_reference_clock(hwmgr
);
1900 /* for GDDR5 for all modes and DDR3 */
1901 if (1 == mpll_param
.qdr
)
1902 freq_nom
= memory_clock
* 4 * (1 << mpll_param
.mpll_post_divider
);
1904 freq_nom
= memory_clock
* 2 * (1 << mpll_param
.mpll_post_divider
);
1906 /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2 Note: S.I. reference_divider = 1*/
1907 tmp
= (freq_nom
/ reference_clock
);
1910 if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr
, freq_nom
, &ss_info
)) {
1911 /* ss_info.speed_spectrum_percentage -- in unit of 0.01% */
1912 /* ss.Info.speed_spectrum_rate -- in unit of khz */
1913 /* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */
1914 /* = reference_clock * 5 / speed_spectrum_rate */
1915 uint32_t clks
= reference_clock
* 5 / ss_info
.speed_spectrum_rate
;
1917 /* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */
1918 /* = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */
1920 (uint32_t)((((131 * ss_info
.speed_spectrum_percentage
*
1921 ss_info
.speed_spectrum_rate
) / 100) * tmp
) / freq_nom
);
1923 mpll_ss1
= PHM_SET_FIELD(mpll_ss1
, MPLL_SS1
, CLKV
, clkv
);
1924 mpll_ss2
= PHM_SET_FIELD(mpll_ss2
, MPLL_SS2
, CLKS
, clks
);
1928 /* MCLK_PWRMGT_CNTL setup */
1929 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
1930 MCLK_PWRMGT_CNTL
, DLL_SPEED
, mpll_param
.dll_speed
);
1931 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
1932 MCLK_PWRMGT_CNTL
, MRDCK0_PDNB
, dllStateOn
);
1933 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
1934 MCLK_PWRMGT_CNTL
, MRDCK1_PDNB
, dllStateOn
);
1937 /* Save the result data to outpupt memory level structure */
1938 mclk
->MclkFrequency
= memory_clock
;
1939 mclk
->MpllFuncCntl
= mpll_func_cntl
;
1940 mclk
->MpllFuncCntl_1
= mpll_func_cntl_1
;
1941 mclk
->MpllFuncCntl_2
= mpll_func_cntl_2
;
1942 mclk
->MpllAdFuncCntl
= mpll_ad_func_cntl
;
1943 mclk
->MpllDqFuncCntl
= mpll_dq_func_cntl
;
1944 mclk
->MclkPwrmgtCntl
= mclk_pwrmgt_cntl
;
1945 mclk
->DllCntl
= dll_cntl
;
1946 mclk
->MpllSs1
= mpll_ss1
;
1947 mclk
->MpllSs2
= mpll_ss2
;
1952 static uint8_t tonga_get_mclk_frequency_ratio(uint32_t memory_clock
,
1955 uint8_t mc_para_index
;
1958 if (memory_clock
< 12500) {
1959 mc_para_index
= 0x00;
1960 } else if (memory_clock
> 47500) {
1961 mc_para_index
= 0x0f;
1963 mc_para_index
= (uint8_t)((memory_clock
- 10000) / 2500);
1966 if (memory_clock
< 65000) {
1967 mc_para_index
= 0x00;
1968 } else if (memory_clock
> 135000) {
1969 mc_para_index
= 0x0f;
1971 mc_para_index
= (uint8_t)((memory_clock
- 60000) / 5000);
1975 return mc_para_index
;
1978 static uint8_t tonga_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock
)
1980 uint8_t mc_para_index
;
1982 if (memory_clock
< 10000) {
1984 } else if (memory_clock
>= 80000) {
1985 mc_para_index
= 0x0f;
1987 mc_para_index
= (uint8_t)((memory_clock
- 10000) / 5000 + 1);
1990 return mc_para_index
;
1993 static int tonga_populate_single_memory_level(
1994 struct pp_hwmgr
*hwmgr
,
1995 uint32_t memory_clock
,
1996 SMU72_Discrete_MemoryLevel
*memory_level
1999 uint32_t minMvdd
= 0;
2000 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2001 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2004 struct cgs_display_info info
= {0};
2007 if (NULL
!= pptable_info
->vdd_dep_on_mclk
) {
2008 result
= tonga_get_dependecy_volt_by_clk(hwmgr
,
2009 pptable_info
->vdd_dep_on_mclk
, memory_clock
, &memory_level
->MinVoltage
, &minMvdd
);
2010 PP_ASSERT_WITH_CODE((0 == result
),
2011 "can not find MinVddc voltage value from memory VDDC voltage dependency table", return result
);
2014 if (data
->mvdd_control
== TONGA_VOLTAGE_CONTROL_NONE
) {
2015 memory_level
->MinMvdd
= data
->vbios_boot_state
.mvdd_bootup_value
;
2017 memory_level
->MinMvdd
= minMvdd
;
2019 memory_level
->EnabledForThrottle
= 1;
2020 memory_level
->EnabledForActivity
= 0;
2021 memory_level
->UpHyst
= 0;
2022 memory_level
->DownHyst
= 100;
2023 memory_level
->VoltageDownHyst
= 0;
2025 /* Indicates maximum activity level for this performance level.*/
2026 memory_level
->ActivityLevel
= (uint16_t)data
->mclk_activity_target
;
2027 memory_level
->StutterEnable
= 0;
2028 memory_level
->StrobeEnable
= 0;
2029 memory_level
->EdcReadEnable
= 0;
2030 memory_level
->EdcWriteEnable
= 0;
2031 memory_level
->RttEnable
= 0;
2033 /* default set to low watermark. Highest level will be set to high later.*/
2034 memory_level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2036 cgs_get_active_displays_info(hwmgr
->device
, &info
);
2037 data
->display_timing
.num_existing_displays
= info
.display_count
;
2039 if ((data
->mclk_stutter_mode_threshold
!= 0) &&
2040 (memory_clock
<= data
->mclk_stutter_mode_threshold
) &&
2041 (data
->is_uvd_enabled
== 0)
2043 && (PHM_READ_FIELD(hwmgr
->device
, DPG_PIPE_STUTTER_CONTROL
, STUTTER_ENABLE
) & 0x1)
2044 && (data
->display_timing
.num_existing_displays
<= 2)
2045 && (data
->display_timing
.num_existing_displays
!= 0)
2048 memory_level
->StutterEnable
= 1;
2050 /* decide strobe mode*/
2051 memory_level
->StrobeEnable
= (data
->mclk_strobe_mode_threshold
!= 0) &&
2052 (memory_clock
<= data
->mclk_strobe_mode_threshold
);
2054 /* decide EDC mode and memory clock ratio*/
2055 if (data
->is_memory_GDDR5
) {
2056 memory_level
->StrobeRatio
= tonga_get_mclk_frequency_ratio(memory_clock
,
2057 memory_level
->StrobeEnable
);
2059 if ((data
->mclk_edc_enable_threshold
!= 0) &&
2060 (memory_clock
> data
->mclk_edc_enable_threshold
)) {
2061 memory_level
->EdcReadEnable
= 1;
2064 if ((data
->mclk_edc_wr_enable_threshold
!= 0) &&
2065 (memory_clock
> data
->mclk_edc_wr_enable_threshold
)) {
2066 memory_level
->EdcWriteEnable
= 1;
2069 if (memory_level
->StrobeEnable
) {
2070 if (tonga_get_mclk_frequency_ratio(memory_clock
, 1) >=
2071 ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC7
) >> 16) & 0xf)) {
2072 dllStateOn
= ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC5
) >> 1) & 0x1) ? 1 : 0;
2074 dllStateOn
= ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC6
) >> 1) & 0x1) ? 1 : 0;
2078 dllStateOn
= data
->dll_defaule_on
;
2081 memory_level
->StrobeRatio
=
2082 tonga_get_ddr3_mclk_frequency_ratio(memory_clock
);
2083 dllStateOn
= ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC5
) >> 1) & 0x1) ? 1 : 0;
2086 result
= tonga_calculate_mclk_params(hwmgr
,
2087 memory_clock
, memory_level
, memory_level
->StrobeEnable
, dllStateOn
);
2090 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MinMvdd
);
2091 /* MCLK frequency in units of 10KHz*/
2092 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MclkFrequency
);
2093 /* Indicates maximum activity level for this performance level.*/
2094 CONVERT_FROM_HOST_TO_SMC_US(memory_level
->ActivityLevel
);
2095 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllFuncCntl
);
2096 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllFuncCntl_1
);
2097 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllFuncCntl_2
);
2098 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllAdFuncCntl
);
2099 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllDqFuncCntl
);
2100 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MclkPwrmgtCntl
);
2101 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->DllCntl
);
2102 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllSs1
);
2103 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllSs2
);
2110 * Populates the SMC MVDD structure using the provided memory clock.
2112 * @param hwmgr the address of the hardware manager
2113 * @param mclk the MCLK value to be used in the decision if MVDD should be high or low.
2114 * @param voltage the SMC VOLTAGE structure to be populated
2116 int tonga_populate_mvdd_value(struct pp_hwmgr
*hwmgr
, uint32_t mclk
, SMIO_Pattern
*smio_pattern
)
2118 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2119 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2122 if (TONGA_VOLTAGE_CONTROL_NONE
!= data
->mvdd_control
) {
2123 /* find mvdd value which clock is more than request */
2124 for (i
= 0; i
< pptable_info
->vdd_dep_on_mclk
->count
; i
++) {
2125 if (mclk
<= pptable_info
->vdd_dep_on_mclk
->entries
[i
].clk
) {
2126 /* Always round to higher voltage. */
2127 smio_pattern
->Voltage
= data
->mvdd_voltage_table
.entries
[i
].value
;
2132 PP_ASSERT_WITH_CODE(i
< pptable_info
->vdd_dep_on_mclk
->count
,
2133 "MVDD Voltage is outside the supported range.", return -1);
2143 static int tonga_populate_smv_acpi_level(struct pp_hwmgr
*hwmgr
,
2144 SMU72_Discrete_DpmTable
*table
)
2147 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2148 pp_atomctrl_clock_dividers_vi dividers
;
2149 SMIO_Pattern voltage_level
;
2150 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
2151 uint32_t spll_func_cntl_2
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
;
2152 uint32_t dll_cntl
= data
->clock_registers
.vDLL_CNTL
;
2153 uint32_t mclk_pwrmgt_cntl
= data
->clock_registers
.vMCLK_PWRMGT_CNTL
;
2155 /* The ACPI state should not do DPM on DC (or ever).*/
2156 table
->ACPILevel
.Flags
&= ~PPSMC_SWSTATE_FLAG_DC
;
2158 table
->ACPILevel
.MinVoltage
= data
->smc_state_table
.GraphicsLevel
[0].MinVoltage
;
2160 /* assign zero for now*/
2161 table
->ACPILevel
.SclkFrequency
= atomctrl_get_reference_clock(hwmgr
);
2163 /* get the engine clock dividers for this clock value*/
2164 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
,
2165 table
->ACPILevel
.SclkFrequency
, ÷rs
);
2167 PP_ASSERT_WITH_CODE(result
== 0,
2168 "Error retrieving Engine Clock dividers from VBIOS.", return result
);
2170 /* divider ID for required SCLK*/
2171 table
->ACPILevel
.SclkDid
= (uint8_t)dividers
.pll_post_divider
;
2172 table
->ACPILevel
.DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2173 table
->ACPILevel
.DeepSleepDivId
= 0;
2175 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2176 CG_SPLL_FUNC_CNTL
, SPLL_PWRON
, 0);
2177 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2178 CG_SPLL_FUNC_CNTL
, SPLL_RESET
, 1);
2179 spll_func_cntl_2
= PHM_SET_FIELD(spll_func_cntl_2
,
2180 CG_SPLL_FUNC_CNTL_2
, SCLK_MUX_SEL
, 4);
2182 table
->ACPILevel
.CgSpllFuncCntl
= spll_func_cntl
;
2183 table
->ACPILevel
.CgSpllFuncCntl2
= spll_func_cntl_2
;
2184 table
->ACPILevel
.CgSpllFuncCntl3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
2185 table
->ACPILevel
.CgSpllFuncCntl4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
2186 table
->ACPILevel
.SpllSpreadSpectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
2187 table
->ACPILevel
.SpllSpreadSpectrum2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
2188 table
->ACPILevel
.CcPwrDynRm
= 0;
2189 table
->ACPILevel
.CcPwrDynRm1
= 0;
2192 /* For various features to be enabled/disabled while this level is active.*/
2193 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.Flags
);
2194 /* SCLK frequency in units of 10KHz*/
2195 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SclkFrequency
);
2196 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl
);
2197 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl2
);
2198 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl3
);
2199 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl4
);
2200 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum
);
2201 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum2
);
2202 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm
);
2203 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm1
);
2205 /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
2206 table
->MemoryACPILevel
.MinVoltage
= data
->smc_state_table
.MemoryLevel
[0].MinVoltage
;
2208 /* CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);*/
2210 if (0 == tonga_populate_mvdd_value(hwmgr
, 0, &voltage_level
))
2211 table
->MemoryACPILevel
.MinMvdd
=
2212 PP_HOST_TO_SMC_UL(voltage_level
.Voltage
* VOLTAGE_SCALE
);
2214 table
->MemoryACPILevel
.MinMvdd
= 0;
2216 /* Force reset on DLL*/
2217 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2218 MCLK_PWRMGT_CNTL
, MRDCK0_RESET
, 0x1);
2219 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2220 MCLK_PWRMGT_CNTL
, MRDCK1_RESET
, 0x1);
2222 /* Disable DLL in ACPIState*/
2223 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2224 MCLK_PWRMGT_CNTL
, MRDCK0_PDNB
, 0);
2225 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2226 MCLK_PWRMGT_CNTL
, MRDCK1_PDNB
, 0);
2228 /* Enable DLL bypass signal*/
2229 dll_cntl
= PHM_SET_FIELD(dll_cntl
,
2230 DLL_CNTL
, MRDCK0_BYPASS
, 0);
2231 dll_cntl
= PHM_SET_FIELD(dll_cntl
,
2232 DLL_CNTL
, MRDCK1_BYPASS
, 0);
2234 table
->MemoryACPILevel
.DllCntl
=
2235 PP_HOST_TO_SMC_UL(dll_cntl
);
2236 table
->MemoryACPILevel
.MclkPwrmgtCntl
=
2237 PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl
);
2238 table
->MemoryACPILevel
.MpllAdFuncCntl
=
2239 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_AD_FUNC_CNTL
);
2240 table
->MemoryACPILevel
.MpllDqFuncCntl
=
2241 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_DQ_FUNC_CNTL
);
2242 table
->MemoryACPILevel
.MpllFuncCntl
=
2243 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_FUNC_CNTL
);
2244 table
->MemoryACPILevel
.MpllFuncCntl_1
=
2245 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_FUNC_CNTL_1
);
2246 table
->MemoryACPILevel
.MpllFuncCntl_2
=
2247 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_FUNC_CNTL_2
);
2248 table
->MemoryACPILevel
.MpllSs1
=
2249 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_SS1
);
2250 table
->MemoryACPILevel
.MpllSs2
=
2251 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_SS2
);
2253 table
->MemoryACPILevel
.EnabledForThrottle
= 0;
2254 table
->MemoryACPILevel
.EnabledForActivity
= 0;
2255 table
->MemoryACPILevel
.UpHyst
= 0;
2256 table
->MemoryACPILevel
.DownHyst
= 100;
2257 table
->MemoryACPILevel
.VoltageDownHyst
= 0;
2258 /* Indicates maximum activity level for this performance level.*/
2259 table
->MemoryACPILevel
.ActivityLevel
= PP_HOST_TO_SMC_US((uint16_t)data
->mclk_activity_target
);
2261 table
->MemoryACPILevel
.StutterEnable
= 0;
2262 table
->MemoryACPILevel
.StrobeEnable
= 0;
2263 table
->MemoryACPILevel
.EdcReadEnable
= 0;
2264 table
->MemoryACPILevel
.EdcWriteEnable
= 0;
2265 table
->MemoryACPILevel
.RttEnable
= 0;
2270 static int tonga_find_boot_level(struct tonga_single_dpm_table
*table
, uint32_t value
, uint32_t *boot_level
)
2275 for (i
= 0; i
< table
->count
; i
++) {
2276 if (value
== table
->dpm_levels
[i
].value
) {
2284 static int tonga_populate_smc_boot_level(struct pp_hwmgr
*hwmgr
,
2285 SMU72_Discrete_DpmTable
*table
)
2288 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2290 table
->GraphicsBootLevel
= 0; /* 0 == DPM[0] (low), etc. */
2291 table
->MemoryBootLevel
= 0; /* 0 == DPM[0] (low), etc. */
2293 /* find boot level from dpm table*/
2294 result
= tonga_find_boot_level(&(data
->dpm_table
.sclk_table
),
2295 data
->vbios_boot_state
.sclk_bootup_value
,
2296 (uint32_t *)&(data
->smc_state_table
.GraphicsBootLevel
));
2299 data
->smc_state_table
.GraphicsBootLevel
= 0;
2300 printk(KERN_ERR
"[ powerplay ] VBIOS did not find boot engine clock value \
2301 in dependency table. Using Graphics DPM level 0!");
2305 result
= tonga_find_boot_level(&(data
->dpm_table
.mclk_table
),
2306 data
->vbios_boot_state
.mclk_bootup_value
,
2307 (uint32_t *)&(data
->smc_state_table
.MemoryBootLevel
));
2310 data
->smc_state_table
.MemoryBootLevel
= 0;
2311 printk(KERN_ERR
"[ powerplay ] VBIOS did not find boot engine clock value \
2312 in dependency table. Using Memory DPM level 0!");
2316 table
->BootVoltage
.Vddc
=
2317 tonga_get_voltage_id(&(data
->vddc_voltage_table
),
2318 data
->vbios_boot_state
.vddc_bootup_value
);
2319 table
->BootVoltage
.VddGfx
=
2320 tonga_get_voltage_id(&(data
->vddgfx_voltage_table
),
2321 data
->vbios_boot_state
.vddgfx_bootup_value
);
2322 table
->BootVoltage
.Vddci
=
2323 tonga_get_voltage_id(&(data
->vddci_voltage_table
),
2324 data
->vbios_boot_state
.vddci_bootup_value
);
2325 table
->BootMVdd
= data
->vbios_boot_state
.mvdd_bootup_value
;
2327 CONVERT_FROM_HOST_TO_SMC_US(table
->BootMVdd
);
2334 * Calculates the SCLK dividers using the provided engine clock
2336 * @param hwmgr the address of the hardware manager
2337 * @param engine_clock the engine clock to use to populate the structure
2338 * @param sclk the SMC SCLK structure to be populated
2340 int tonga_calculate_sclk_params(struct pp_hwmgr
*hwmgr
,
2341 uint32_t engine_clock
, SMU72_Discrete_GraphicsLevel
*sclk
)
2343 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2344 pp_atomctrl_clock_dividers_vi dividers
;
2345 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
2346 uint32_t spll_func_cntl_3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
2347 uint32_t spll_func_cntl_4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
2348 uint32_t cg_spll_spread_spectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
2349 uint32_t cg_spll_spread_spectrum_2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
2350 uint32_t reference_clock
;
2351 uint32_t reference_divider
;
2355 /* get the engine clock dividers for this clock value*/
2356 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
, engine_clock
, ÷rs
);
2358 PP_ASSERT_WITH_CODE(result
== 0,
2359 "Error retrieving Engine Clock dividers from VBIOS.", return result
);
2361 /* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/
2362 reference_clock
= atomctrl_get_reference_clock(hwmgr
);
2364 reference_divider
= 1 + dividers
.uc_pll_ref_div
;
2366 /* low 14 bits is fraction and high 12 bits is divider*/
2367 fbdiv
= dividers
.ul_fb_div
.ul_fb_divider
& 0x3FFFFFF;
2369 /* SPLL_FUNC_CNTL setup*/
2370 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2371 CG_SPLL_FUNC_CNTL
, SPLL_REF_DIV
, dividers
.uc_pll_ref_div
);
2372 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2373 CG_SPLL_FUNC_CNTL
, SPLL_PDIV_A
, dividers
.uc_pll_post_div
);
2375 /* SPLL_FUNC_CNTL_3 setup*/
2376 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
,
2377 CG_SPLL_FUNC_CNTL_3
, SPLL_FB_DIV
, fbdiv
);
2379 /* set to use fractional accumulation*/
2380 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
,
2381 CG_SPLL_FUNC_CNTL_3
, SPLL_DITHEN
, 1);
2383 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2384 PHM_PlatformCaps_EngineSpreadSpectrumSupport
)) {
2385 pp_atomctrl_internal_ss_info ss_info
;
2387 uint32_t vcoFreq
= engine_clock
* dividers
.uc_pll_post_div
;
2388 if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr
, vcoFreq
, &ss_info
)) {
2390 * ss_info.speed_spectrum_percentage -- in unit of 0.01%
2391 * ss_info.speed_spectrum_rate -- in unit of khz
2393 /* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */
2394 uint32_t clkS
= reference_clock
* 5 / (reference_divider
* ss_info
.speed_spectrum_rate
);
2396 /* clkv = 2 * D * fbdiv / NS */
2397 uint32_t clkV
= 4 * ss_info
.speed_spectrum_percentage
* fbdiv
/ (clkS
* 10000);
2399 cg_spll_spread_spectrum
=
2400 PHM_SET_FIELD(cg_spll_spread_spectrum
, CG_SPLL_SPREAD_SPECTRUM
, CLKS
, clkS
);
2401 cg_spll_spread_spectrum
=
2402 PHM_SET_FIELD(cg_spll_spread_spectrum
, CG_SPLL_SPREAD_SPECTRUM
, SSEN
, 1);
2403 cg_spll_spread_spectrum_2
=
2404 PHM_SET_FIELD(cg_spll_spread_spectrum_2
, CG_SPLL_SPREAD_SPECTRUM_2
, CLKV
, clkV
);
2408 sclk
->SclkFrequency
= engine_clock
;
2409 sclk
->CgSpllFuncCntl3
= spll_func_cntl_3
;
2410 sclk
->CgSpllFuncCntl4
= spll_func_cntl_4
;
2411 sclk
->SpllSpreadSpectrum
= cg_spll_spread_spectrum
;
2412 sclk
->SpllSpreadSpectrum2
= cg_spll_spread_spectrum_2
;
2413 sclk
->SclkDid
= (uint8_t)dividers
.pll_post_divider
;
2419 * Populates single SMC SCLK structure using the provided engine clock
2421 * @param hwmgr the address of the hardware manager
2422 * @param engine_clock the engine clock to use to populate the structure
2423 * @param sclk the SMC SCLK structure to be populated
2425 static int tonga_populate_single_graphic_level(struct pp_hwmgr
*hwmgr
, uint32_t engine_clock
, uint16_t sclk_activity_level_threshold
, SMU72_Discrete_GraphicsLevel
*graphic_level
)
2430 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2431 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2433 result
= tonga_calculate_sclk_params(hwmgr
, engine_clock
, graphic_level
);
2436 /* populate graphics levels*/
2437 result
= tonga_get_dependecy_volt_by_clk(hwmgr
,
2438 pptable_info
->vdd_dep_on_sclk
, engine_clock
,
2439 &graphic_level
->MinVoltage
, &mvdd
);
2440 PP_ASSERT_WITH_CODE((0 == result
),
2441 "can not find VDDC voltage value for VDDC \
2442 engine clock dependency table", return result
);
2444 /* SCLK frequency in units of 10KHz*/
2445 graphic_level
->SclkFrequency
= engine_clock
;
2447 /* Indicates maximum activity level for this performance level. 50% for now*/
2448 graphic_level
->ActivityLevel
= sclk_activity_level_threshold
;
2450 graphic_level
->CcPwrDynRm
= 0;
2451 graphic_level
->CcPwrDynRm1
= 0;
2452 /* this level can be used if activity is high enough.*/
2453 graphic_level
->EnabledForActivity
= 0;
2454 /* this level can be used for throttling.*/
2455 graphic_level
->EnabledForThrottle
= 1;
2456 graphic_level
->UpHyst
= 0;
2457 graphic_level
->DownHyst
= 0;
2458 graphic_level
->VoltageDownHyst
= 0;
2459 graphic_level
->PowerThrottle
= 0;
2461 threshold
= engine_clock
* data
->fast_watemark_threshold
/ 100;
2463 *get the DAL clock. do it in funture.
2464 PECI_GetMinClockSettings(hwmgr->peci, &minClocks);
2465 data->display_timing.min_clock_insr = minClocks.engineClockInSR;
2467 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
2469 graphic_level->DeepSleepDivId = PhwTonga_GetSleepDividerIdFromClock(hwmgr, engine_clock, minClocks.engineClockInSR);
2473 /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
2474 graphic_level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2477 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVoltage);*/
2478 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases);*/
2479 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->SclkFrequency
);
2480 CONVERT_FROM_HOST_TO_SMC_US(graphic_level
->ActivityLevel
);
2481 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CgSpllFuncCntl3
);
2482 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CgSpllFuncCntl4
);
2483 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->SpllSpreadSpectrum
);
2484 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->SpllSpreadSpectrum2
);
2485 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CcPwrDynRm
);
2486 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CcPwrDynRm1
);
2493 * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
2495 * @param hwmgr the address of the hardware manager
2497 static int tonga_populate_all_graphic_levels(struct pp_hwmgr
*hwmgr
)
2499 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2500 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2501 struct tonga_dpm_table
*dpm_table
= &data
->dpm_table
;
2502 phm_ppt_v1_pcie_table
*pcie_table
= pptable_info
->pcie_table
;
2503 uint8_t pcie_entry_count
= (uint8_t) data
->dpm_table
.pcie_speed_table
.count
;
2505 uint32_t level_array_adress
= data
->dpm_table_start
+
2506 offsetof(SMU72_Discrete_DpmTable
, GraphicsLevel
);
2507 uint32_t level_array_size
= sizeof(SMU72_Discrete_GraphicsLevel
) *
2508 SMU72_MAX_LEVELS_GRAPHICS
; /* 64 -> long; 32 -> int*/
2509 SMU72_Discrete_GraphicsLevel
*levels
= data
->smc_state_table
.GraphicsLevel
;
2510 uint32_t i
, maxEntry
;
2511 uint8_t highest_pcie_level_enabled
= 0, lowest_pcie_level_enabled
= 0, mid_pcie_level_enabled
= 0, count
= 0;
2512 PECI_RegistryValue reg_value
;
2513 memset(levels
, 0x00, level_array_size
);
2515 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
2516 result
= tonga_populate_single_graphic_level(hwmgr
,
2517 dpm_table
->sclk_table
.dpm_levels
[i
].value
,
2518 (uint16_t)data
->activity_target
[i
],
2519 &(data
->smc_state_table
.GraphicsLevel
[i
]));
2524 /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
2526 data
->smc_state_table
.GraphicsLevel
[i
].DeepSleepDivId
= 0;
2531 data
->smc_state_table
.GraphicsLevel
[0].UpHyst
= (uint8_t)reg_value
;
2537 data
->smc_state_table
.GraphicsLevel
[1].UpHyst
= (uint8_t)reg_value
;
2541 /* Only enable level 0 for now. */
2542 data
->smc_state_table
.GraphicsLevel
[0].EnabledForActivity
= 1;
2544 /* set highest level watermark to high */
2545 if (dpm_table
->sclk_table
.count
> 1)
2546 data
->smc_state_table
.GraphicsLevel
[dpm_table
->sclk_table
.count
-1].DisplayWatermark
=
2547 PPSMC_DISPLAY_WATERMARK_HIGH
;
2549 data
->smc_state_table
.GraphicsDpmLevelCount
=
2550 (uint8_t)dpm_table
->sclk_table
.count
;
2551 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
=
2552 tonga_get_dpm_level_enable_mask_value(&dpm_table
->sclk_table
);
2554 if (pcie_table
!= NULL
) {
2555 PP_ASSERT_WITH_CODE((pcie_entry_count
>= 1),
2556 "There must be 1 or more PCIE levels defined in PPTable.", return -1);
2557 maxEntry
= pcie_entry_count
- 1; /* for indexing, we need to decrement by 1.*/
2558 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
2559 data
->smc_state_table
.GraphicsLevel
[i
].pcieDpmLevel
=
2560 (uint8_t) ((i
< maxEntry
) ? i
: maxEntry
);
2563 if (0 == data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
)
2564 printk(KERN_ERR
"[ powerplay ] Pcie Dpm Enablemask is 0!");
2566 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
2567 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2568 (1<<(highest_pcie_level_enabled
+1))) != 0)) {
2569 highest_pcie_level_enabled
++;
2572 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
2573 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2574 (1<<lowest_pcie_level_enabled
)) == 0)) {
2575 lowest_pcie_level_enabled
++;
2578 while ((count
< highest_pcie_level_enabled
) &&
2579 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2580 (1<<(lowest_pcie_level_enabled
+1+count
))) == 0)) {
2583 mid_pcie_level_enabled
= (lowest_pcie_level_enabled
+1+count
) < highest_pcie_level_enabled
?
2584 (lowest_pcie_level_enabled
+1+count
) : highest_pcie_level_enabled
;
2587 /* set pcieDpmLevel to highest_pcie_level_enabled*/
2588 for (i
= 2; i
< dpm_table
->sclk_table
.count
; i
++) {
2589 data
->smc_state_table
.GraphicsLevel
[i
].pcieDpmLevel
= highest_pcie_level_enabled
;
2592 /* set pcieDpmLevel to lowest_pcie_level_enabled*/
2593 data
->smc_state_table
.GraphicsLevel
[0].pcieDpmLevel
= lowest_pcie_level_enabled
;
2595 /* set pcieDpmLevel to mid_pcie_level_enabled*/
2596 data
->smc_state_table
.GraphicsLevel
[1].pcieDpmLevel
= mid_pcie_level_enabled
;
2598 /* level count will send to smc once at init smc table and never change*/
2599 result
= tonga_copy_bytes_to_smc(hwmgr
->smumgr
, level_array_adress
, (uint8_t *)levels
, (uint32_t)level_array_size
, data
->sram_end
);
2608 * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
2610 * @param hwmgr the address of the hardware manager
2613 static int tonga_populate_all_memory_levels(struct pp_hwmgr
*hwmgr
)
2615 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2616 struct tonga_dpm_table
*dpm_table
= &data
->dpm_table
;
2618 /* populate MCLK dpm table to SMU7 */
2619 uint32_t level_array_adress
= data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
, MemoryLevel
);
2620 uint32_t level_array_size
= sizeof(SMU72_Discrete_MemoryLevel
) * SMU72_MAX_LEVELS_MEMORY
;
2621 SMU72_Discrete_MemoryLevel
*levels
= data
->smc_state_table
.MemoryLevel
;
2624 memset(levels
, 0x00, level_array_size
);
2626 for (i
= 0; i
< dpm_table
->mclk_table
.count
; i
++) {
2627 PP_ASSERT_WITH_CODE((0 != dpm_table
->mclk_table
.dpm_levels
[i
].value
),
2628 "can not populate memory level as memory clock is zero", return -1);
2629 result
= tonga_populate_single_memory_level(hwmgr
, dpm_table
->mclk_table
.dpm_levels
[i
].value
,
2630 &(data
->smc_state_table
.MemoryLevel
[i
]));
2636 /* Only enable level 0 for now.*/
2637 data
->smc_state_table
.MemoryLevel
[0].EnabledForActivity
= 1;
2640 * in order to prevent MC activity from stutter mode to push DPM up.
2641 * the UVD change complements this by putting the MCLK in a higher state
2642 * by default such that we are not effected by up threshold or and MCLK DPM latency.
2644 data
->smc_state_table
.MemoryLevel
[0].ActivityLevel
= 0x1F;
2645 CONVERT_FROM_HOST_TO_SMC_US(data
->smc_state_table
.MemoryLevel
[0].ActivityLevel
);
2647 data
->smc_state_table
.MemoryDpmLevelCount
= (uint8_t)dpm_table
->mclk_table
.count
;
2648 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&dpm_table
->mclk_table
);
2649 /* set highest level watermark to high*/
2650 data
->smc_state_table
.MemoryLevel
[dpm_table
->mclk_table
.count
-1].DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_HIGH
;
2652 /* level count will send to smc once at init smc table and never change*/
2653 result
= tonga_copy_bytes_to_smc(hwmgr
->smumgr
,
2654 level_array_adress
, (uint8_t *)levels
, (uint32_t)level_array_size
, data
->sram_end
);
2663 struct TONGA_DLL_SPEED_SETTING
{
2664 uint16_t Min
; /* Minimum Data Rate*/
2665 uint16_t Max
; /* Maximum Data Rate*/
2666 uint32_t dll_speed
; /* The desired DLL_SPEED setting*/
2669 static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr
*hwmgr
)
2674 /* ---------------------------------------- ULV related functions ----------------------------------------------------*/
2677 static int tonga_reset_single_dpm_table(
2678 struct pp_hwmgr
*hwmgr
,
2679 struct tonga_single_dpm_table
*dpm_table
,
2683 if (!(count
<= MAX_REGULAR_DPM_NUMBER
))
2684 printk(KERN_ERR
"[ powerplay ] Fatal error, can not set up single DPM \
2685 table entries to exceed max number! \n");
2687 dpm_table
->count
= count
;
2688 for (i
= 0; i
< MAX_REGULAR_DPM_NUMBER
; i
++) {
2689 dpm_table
->dpm_levels
[i
].enabled
= 0;
2695 static void tonga_setup_pcie_table_entry(
2696 struct tonga_single_dpm_table
*dpm_table
,
2697 uint32_t index
, uint32_t pcie_gen
,
2698 uint32_t pcie_lanes
)
2700 dpm_table
->dpm_levels
[index
].value
= pcie_gen
;
2701 dpm_table
->dpm_levels
[index
].param1
= pcie_lanes
;
2702 dpm_table
->dpm_levels
[index
].enabled
= 1;
2705 static int tonga_setup_default_pcie_tables(struct pp_hwmgr
*hwmgr
)
2707 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2708 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2709 phm_ppt_v1_pcie_table
*pcie_table
= pptable_info
->pcie_table
;
2710 uint32_t i
, maxEntry
;
2712 if (data
->use_pcie_performance_levels
&& !data
->use_pcie_power_saving_levels
) {
2713 data
->pcie_gen_power_saving
= data
->pcie_gen_performance
;
2714 data
->pcie_lane_power_saving
= data
->pcie_lane_performance
;
2715 } else if (!data
->use_pcie_performance_levels
&& data
->use_pcie_power_saving_levels
) {
2716 data
->pcie_gen_performance
= data
->pcie_gen_power_saving
;
2717 data
->pcie_lane_performance
= data
->pcie_lane_power_saving
;
2720 tonga_reset_single_dpm_table(hwmgr
, &data
->dpm_table
.pcie_speed_table
, SMU72_MAX_LEVELS_LINK
);
2722 if (pcie_table
!= NULL
) {
2724 * maxEntry is used to make sure we reserve one PCIE level for boot level (fix for A+A PSPP issue).
2725 * If PCIE table from PPTable have ULV entry + 8 entries, then ignore the last entry.
2727 maxEntry
= (SMU72_MAX_LEVELS_LINK
< pcie_table
->count
) ?
2728 SMU72_MAX_LEVELS_LINK
: pcie_table
->count
;
2729 for (i
= 1; i
< maxEntry
; i
++) {
2730 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, i
-1,
2731 get_pcie_gen_support(data
->pcie_gen_cap
, pcie_table
->entries
[i
].gen_speed
),
2732 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2734 data
->dpm_table
.pcie_speed_table
.count
= maxEntry
- 1;
2736 /* Hardcode Pcie Table */
2737 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 0,
2738 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Min_PCIEGen
),
2739 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2740 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 1,
2741 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Min_PCIEGen
),
2742 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2743 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 2,
2744 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2745 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2746 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 3,
2747 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2748 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2749 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 4,
2750 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2751 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2752 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 5,
2753 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2754 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2755 data
->dpm_table
.pcie_speed_table
.count
= 6;
2757 /* Populate last level for boot PCIE level, but do not increment count. */
2758 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
,
2759 data
->dpm_table
.pcie_speed_table
.count
,
2760 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Min_PCIEGen
),
2761 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2768 * This function is to initalize all DPM state tables for SMU7 based on the dependency table.
2769 * Dynamic state patching function will then trim these state tables to the allowed range based
2770 * on the power policy or external client requests, such as UVD request, etc.
2772 static int tonga_setup_default_dpm_tables(struct pp_hwmgr
*hwmgr
)
2774 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2775 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2778 phm_ppt_v1_clock_voltage_dependency_table
*allowed_vdd_sclk_table
=
2779 pptable_info
->vdd_dep_on_sclk
;
2780 phm_ppt_v1_clock_voltage_dependency_table
*allowed_vdd_mclk_table
=
2781 pptable_info
->vdd_dep_on_mclk
;
2783 PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table
!= NULL
,
2784 "SCLK dependency table is missing. This table is mandatory", return -1);
2785 PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table
->count
>= 1,
2786 "SCLK dependency table has to have is missing. This table is mandatory", return -1);
2788 PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table
!= NULL
,
2789 "MCLK dependency table is missing. This table is mandatory", return -1);
2790 PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table
->count
>= 1,
2791 "VMCLK dependency table has to have is missing. This table is mandatory", return -1);
2793 /* clear the state table to reset everything to default */
2794 memset(&(data
->dpm_table
), 0x00, sizeof(data
->dpm_table
));
2795 tonga_reset_single_dpm_table(hwmgr
, &data
->dpm_table
.sclk_table
, SMU72_MAX_LEVELS_GRAPHICS
);
2796 tonga_reset_single_dpm_table(hwmgr
, &data
->dpm_table
.mclk_table
, SMU72_MAX_LEVELS_MEMORY
);
2797 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.VddcTable, SMU72_MAX_LEVELS_VDDC); */
2798 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_gfx_table, SMU72_MAX_LEVELS_VDDGFX);*/
2799 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_ci_table, SMU72_MAX_LEVELS_VDDCI);*/
2800 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.mvdd_table, SMU72_MAX_LEVELS_MVDD);*/
2802 PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table
!= NULL
,
2803 "SCLK dependency table is missing. This table is mandatory", return -1);
2804 /* Initialize Sclk DPM table based on allow Sclk values*/
2805 data
->dpm_table
.sclk_table
.count
= 0;
2807 for (i
= 0; i
< allowed_vdd_sclk_table
->count
; i
++) {
2808 if (i
== 0 || data
->dpm_table
.sclk_table
.dpm_levels
[data
->dpm_table
.sclk_table
.count
-1].value
!=
2809 allowed_vdd_sclk_table
->entries
[i
].clk
) {
2810 data
->dpm_table
.sclk_table
.dpm_levels
[data
->dpm_table
.sclk_table
.count
].value
=
2811 allowed_vdd_sclk_table
->entries
[i
].clk
;
2812 data
->dpm_table
.sclk_table
.dpm_levels
[data
->dpm_table
.sclk_table
.count
].enabled
= 1; /*(i==0) ? 1 : 0; to do */
2813 data
->dpm_table
.sclk_table
.count
++;
2817 PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table
!= NULL
,
2818 "MCLK dependency table is missing. This table is mandatory", return -1);
2819 /* Initialize Mclk DPM table based on allow Mclk values */
2820 data
->dpm_table
.mclk_table
.count
= 0;
2821 for (i
= 0; i
< allowed_vdd_mclk_table
->count
; i
++) {
2822 if (i
== 0 || data
->dpm_table
.mclk_table
.dpm_levels
[data
->dpm_table
.mclk_table
.count
-1].value
!=
2823 allowed_vdd_mclk_table
->entries
[i
].clk
) {
2824 data
->dpm_table
.mclk_table
.dpm_levels
[data
->dpm_table
.mclk_table
.count
].value
=
2825 allowed_vdd_mclk_table
->entries
[i
].clk
;
2826 data
->dpm_table
.mclk_table
.dpm_levels
[data
->dpm_table
.mclk_table
.count
].enabled
= 1; /*(i==0) ? 1 : 0; */
2827 data
->dpm_table
.mclk_table
.count
++;
2831 /* Initialize Vddc DPM table based on allow Vddc values. And populate corresponding std values. */
2832 for (i
= 0; i
< allowed_vdd_sclk_table
->count
; i
++) {
2833 data
->dpm_table
.vddc_table
.dpm_levels
[i
].value
= allowed_vdd_mclk_table
->entries
[i
].vddc
;
2834 /* tonga_hwmgr->dpm_table.VddcTable.dpm_levels[i].param1 = stdVoltageTable->entries[i].Leakage; */
2835 /* param1 is for corresponding std voltage */
2836 data
->dpm_table
.vddc_table
.dpm_levels
[i
].enabled
= 1;
2838 data
->dpm_table
.vddc_table
.count
= allowed_vdd_sclk_table
->count
;
2840 if (NULL
!= allowed_vdd_mclk_table
) {
2841 /* Initialize Vddci DPM table based on allow Mclk values */
2842 for (i
= 0; i
< allowed_vdd_mclk_table
->count
; i
++) {
2843 data
->dpm_table
.vdd_ci_table
.dpm_levels
[i
].value
= allowed_vdd_mclk_table
->entries
[i
].vddci
;
2844 data
->dpm_table
.vdd_ci_table
.dpm_levels
[i
].enabled
= 1;
2845 data
->dpm_table
.mvdd_table
.dpm_levels
[i
].value
= allowed_vdd_mclk_table
->entries
[i
].mvdd
;
2846 data
->dpm_table
.mvdd_table
.dpm_levels
[i
].enabled
= 1;
2848 data
->dpm_table
.vdd_ci_table
.count
= allowed_vdd_mclk_table
->count
;
2849 data
->dpm_table
.mvdd_table
.count
= allowed_vdd_mclk_table
->count
;
2852 /* setup PCIE gen speed levels*/
2853 tonga_setup_default_pcie_tables(hwmgr
);
2855 /* save a copy of the default DPM table*/
2856 memcpy(&(data
->golden_dpm_table
), &(data
->dpm_table
), sizeof(struct tonga_dpm_table
));
2861 int tonga_populate_smc_initial_state(struct pp_hwmgr
*hwmgr
,
2862 const struct tonga_power_state
*bootState
)
2864 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2865 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2866 uint8_t count
, level
;
2868 count
= (uint8_t) (pptable_info
->vdd_dep_on_sclk
->count
);
2869 for (level
= 0; level
< count
; level
++) {
2870 if (pptable_info
->vdd_dep_on_sclk
->entries
[level
].clk
>=
2871 bootState
->performance_levels
[0].engine_clock
) {
2872 data
->smc_state_table
.GraphicsBootLevel
= level
;
2877 count
= (uint8_t) (pptable_info
->vdd_dep_on_mclk
->count
);
2878 for (level
= 0; level
< count
; level
++) {
2879 if (pptable_info
->vdd_dep_on_mclk
->entries
[level
].clk
>=
2880 bootState
->performance_levels
[0].memory_clock
) {
2881 data
->smc_state_table
.MemoryBootLevel
= level
;
2890 * Initializes the SMC table and uploads it
2892 * @param hwmgr the address of the powerplay hardware manager.
2893 * @param pInput the pointer to input data (PowerState)
2896 int tonga_init_smc_table(struct pp_hwmgr
*hwmgr
)
2899 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2900 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2901 SMU72_Discrete_DpmTable
*table
= &(data
->smc_state_table
);
2902 const phw_tonga_ulv_parm
*ulv
= &(data
->ulv
);
2904 PECI_RegistryValue reg_value
;
2905 pp_atomctrl_gpio_pin_assignment gpio_pin_assignment
;
2907 result
= tonga_setup_default_dpm_tables(hwmgr
);
2908 PP_ASSERT_WITH_CODE(0 == result
,
2909 "Failed to setup default DPM tables!", return result
;);
2910 memset(&(data
->smc_state_table
), 0x00, sizeof(data
->smc_state_table
));
2911 if (TONGA_VOLTAGE_CONTROL_NONE
!= data
->voltage_control
) {
2912 tonga_populate_smc_voltage_tables(hwmgr
, table
);
2915 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2916 PHM_PlatformCaps_AutomaticDCTransition
)) {
2917 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GPIO_DC
;
2920 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2921 PHM_PlatformCaps_StepVddc
)) {
2922 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_STEPVDDC
;
2925 if (data
->is_memory_GDDR5
) {
2926 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GDDR5
;
2929 i
= PHM_READ_FIELD(hwmgr
->device
, CC_MC_MAX_CHANNEL
, NOOFCHAN
);
2931 if (i
== 1 || i
== 0) {
2932 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_12CHANNEL
;
2935 if (ulv
->ulv_supported
&& pptable_info
->us_ulv_voltage_offset
) {
2936 PP_ASSERT_WITH_CODE(0 == result
,
2937 "Failed to initialize ULV state!", return result
;);
2939 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
2940 ixCG_ULV_PARAMETER
, ulv
->ch_ulv_parameter
);
2943 result
= tonga_populate_smc_link_level(hwmgr
, table
);
2944 PP_ASSERT_WITH_CODE(0 == result
,
2945 "Failed to initialize Link Level!", return result
;);
2947 result
= tonga_populate_all_graphic_levels(hwmgr
);
2948 PP_ASSERT_WITH_CODE(0 == result
,
2949 "Failed to initialize Graphics Level!", return result
;);
2951 result
= tonga_populate_all_memory_levels(hwmgr
);
2952 PP_ASSERT_WITH_CODE(0 == result
,
2953 "Failed to initialize Memory Level!", return result
;);
2955 result
= tonga_populate_smv_acpi_level(hwmgr
, table
);
2956 PP_ASSERT_WITH_CODE(0 == result
,
2957 "Failed to initialize ACPI Level!", return result
;);
2959 result
= tonga_populate_smc_vce_level(hwmgr
, table
);
2960 PP_ASSERT_WITH_CODE(0 == result
,
2961 "Failed to initialize VCE Level!", return result
;);
2963 result
= tonga_populate_smc_acp_level(hwmgr
, table
);
2964 PP_ASSERT_WITH_CODE(0 == result
,
2965 "Failed to initialize ACP Level!", return result
;);
2967 result
= tonga_populate_smc_samu_level(hwmgr
, table
);
2968 PP_ASSERT_WITH_CODE(0 == result
,
2969 "Failed to initialize SAMU Level!", return result
;);
2971 /* Since only the initial state is completely set up at this point (the other states are just copies of the boot state) we only */
2972 /* need to populate the ARB settings for the initial state. */
2973 result
= tonga_program_memory_timing_parameters(hwmgr
);
2974 PP_ASSERT_WITH_CODE(0 == result
,
2975 "Failed to Write ARB settings for the initial state.", return result
;);
2977 result
= tonga_populate_smc_uvd_level(hwmgr
, table
);
2978 PP_ASSERT_WITH_CODE(0 == result
,
2979 "Failed to initialize UVD Level!", return result
;);
2981 result
= tonga_populate_smc_boot_level(hwmgr
, table
);
2982 PP_ASSERT_WITH_CODE(0 == result
,
2983 "Failed to initialize Boot Level!", return result
;);
2985 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2986 PHM_PlatformCaps_ClockStretcher
)) {
2987 result
= tonga_populate_clock_stretcher_data_table(hwmgr
);
2988 PP_ASSERT_WITH_CODE(0 == result
,
2989 "Failed to populate Clock Stretcher Data Table!", return result
;);
2991 table
->GraphicsVoltageChangeEnable
= 1;
2992 table
->GraphicsThermThrottleEnable
= 1;
2993 table
->GraphicsInterval
= 1;
2994 table
->VoltageInterval
= 1;
2995 table
->ThermalInterval
= 1;
2996 table
->TemperatureLimitHigh
=
2997 pptable_info
->cac_dtp_table
->usTargetOperatingTemp
*
2998 TONGA_Q88_FORMAT_CONVERSION_UNIT
;
2999 table
->TemperatureLimitLow
=
3000 (pptable_info
->cac_dtp_table
->usTargetOperatingTemp
- 1) *
3001 TONGA_Q88_FORMAT_CONVERSION_UNIT
;
3002 table
->MemoryVoltageChangeEnable
= 1;
3003 table
->MemoryInterval
= 1;
3004 table
->VoltageResponseTime
= 0;
3005 table
->PhaseResponseTime
= 0;
3006 table
->MemoryThermThrottleEnable
= 1;
3009 * Cail reads current link status and reports it as cap (we cannot change this due to some previous issues we had)
3010 * SMC drops the link status to lowest level after enabling DPM by PowerPlay. After pnp or toggling CF, driver gets reloaded again
3011 * but this time Cail reads current link status which was set to low by SMC and reports it as cap to powerplay
3012 * To avoid it, we set PCIeBootLinkLevel to highest dpm level
3014 PP_ASSERT_WITH_CODE((1 <= data
->dpm_table
.pcie_speed_table
.count
),
3015 "There must be 1 or more PCIE levels defined in PPTable.",
3018 table
->PCIeBootLinkLevel
= (uint8_t) (data
->dpm_table
.pcie_speed_table
.count
);
3020 table
->PCIeGenInterval
= 1;
3022 result
= tonga_populate_vr_config(hwmgr
, table
);
3023 PP_ASSERT_WITH_CODE(0 == result
,
3024 "Failed to populate VRConfig setting!", return result
);
3026 table
->ThermGpio
= 17;
3027 table
->SclkStepSize
= 0x4000;
3030 if ((0 == reg_value
) &&
3031 (0 == atomctrl_get_pp_assign_pin(hwmgr
,
3032 VDDC_VRHOT_GPIO_PINID
, &gpio_pin_assignment
))) {
3033 table
->VRHotGpio
= gpio_pin_assignment
.uc_gpio_pin_bit_shift
;
3034 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3035 PHM_PlatformCaps_RegulatorHot
);
3037 table
->VRHotGpio
= TONGA_UNUSED_GPIO_PIN
;
3038 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3039 PHM_PlatformCaps_RegulatorHot
);
3042 /* ACDC Switch GPIO */
3044 if ((0 == reg_value
) &&
3045 (0 == atomctrl_get_pp_assign_pin(hwmgr
,
3046 PP_AC_DC_SWITCH_GPIO_PINID
, &gpio_pin_assignment
))) {
3047 table
->AcDcGpio
= gpio_pin_assignment
.uc_gpio_pin_bit_shift
;
3048 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3049 PHM_PlatformCaps_AutomaticDCTransition
);
3051 table
->AcDcGpio
= TONGA_UNUSED_GPIO_PIN
;
3052 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3053 PHM_PlatformCaps_AutomaticDCTransition
);
3056 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3057 PHM_PlatformCaps_Falcon_QuickTransition
);
3060 if (1 == reg_value
) {
3061 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3062 PHM_PlatformCaps_AutomaticDCTransition
);
3063 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3064 PHM_PlatformCaps_Falcon_QuickTransition
);
3068 if ((0 == reg_value
) &&
3069 (0 == atomctrl_get_pp_assign_pin(hwmgr
,
3070 THERMAL_INT_OUTPUT_GPIO_PINID
, &gpio_pin_assignment
))) {
3071 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3072 PHM_PlatformCaps_ThermalOutGPIO
);
3074 table
->ThermOutGpio
= gpio_pin_assignment
.uc_gpio_pin_bit_shift
;
3076 table
->ThermOutPolarity
=
3077 (0 == (cgs_read_register(hwmgr
->device
, mmGPIOPAD_A
) &
3078 (1 << gpio_pin_assignment
.uc_gpio_pin_bit_shift
))) ? 1:0;
3080 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_ONLY
;
3082 /* if required, combine VRHot/PCC with thermal out GPIO*/
3083 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3084 PHM_PlatformCaps_RegulatorHot
) &&
3085 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3086 PHM_PlatformCaps_CombinePCCWithThermalSignal
)){
3087 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_VRHOT
;
3090 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3091 PHM_PlatformCaps_ThermalOutGPIO
);
3093 table
->ThermOutGpio
= 17;
3094 table
->ThermOutPolarity
= 1;
3095 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_DISABLE
;
3098 for (i
= 0; i
< SMU72_MAX_ENTRIES_SMIO
; i
++) {
3099 table
->Smio
[i
] = PP_HOST_TO_SMC_UL(table
->Smio
[i
]);
3101 CONVERT_FROM_HOST_TO_SMC_UL(table
->SystemFlags
);
3102 CONVERT_FROM_HOST_TO_SMC_UL(table
->VRConfig
);
3103 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask1
);
3104 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask2
);
3105 CONVERT_FROM_HOST_TO_SMC_UL(table
->SclkStepSize
);
3106 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitHigh
);
3107 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitLow
);
3108 CONVERT_FROM_HOST_TO_SMC_US(table
->VoltageResponseTime
);
3109 CONVERT_FROM_HOST_TO_SMC_US(table
->PhaseResponseTime
);
3111 /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
3112 result
= tonga_copy_bytes_to_smc(hwmgr
->smumgr
, data
->dpm_table_start
+
3113 offsetof(SMU72_Discrete_DpmTable
, SystemFlags
),
3114 (uint8_t *)&(table
->SystemFlags
),
3115 sizeof(SMU72_Discrete_DpmTable
)-3 * sizeof(SMU72_PIDController
),
3118 PP_ASSERT_WITH_CODE(0 == result
,
3119 "Failed to upload dpm data to SMC memory!", return result
;);
3124 /* Look up the voltaged based on DAL's requested level. and then send the requested VDDC voltage to SMC*/
3125 static void tonga_apply_dal_minimum_voltage_request(struct pp_hwmgr
*hwmgr
)
3130 int tonga_upload_dpm_level_enable_mask(struct pp_hwmgr
*hwmgr
)
3132 PPSMC_Result result
;
3133 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3135 /* Apply minimum voltage based on DAL's request level */
3136 tonga_apply_dal_minimum_voltage_request(hwmgr
);
3138 if (0 == data
->sclk_dpm_key_disabled
) {
3139 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
3140 if (0 != tonga_is_dpm_running(hwmgr
))
3141 printk(KERN_ERR
"[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
3143 if (0 != data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
3144 result
= smum_send_msg_to_smc_with_parameter(
3146 (PPSMC_Msg
)PPSMC_MSG_SCLKDPM_SetEnabledMask
,
3147 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
3148 PP_ASSERT_WITH_CODE((0 == result
),
3149 "Set Sclk Dpm enable Mask failed", return -1);
3153 if (0 == data
->mclk_dpm_key_disabled
) {
3154 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
3155 if (0 != tonga_is_dpm_running(hwmgr
))
3156 printk(KERN_ERR
"[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
3158 if (0 != data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
) {
3159 result
= smum_send_msg_to_smc_with_parameter(
3161 (PPSMC_Msg
)PPSMC_MSG_MCLKDPM_SetEnabledMask
,
3162 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
);
3163 PP_ASSERT_WITH_CODE((0 == result
),
3164 "Set Mclk Dpm enable Mask failed", return -1);
3172 int tonga_force_dpm_highest(struct pp_hwmgr
*hwmgr
)
3174 uint32_t level
, tmp
;
3175 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3177 if (0 == data
->pcie_dpm_key_disabled
) {
3179 if (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
!= 0) {
3181 tmp
= data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
;
3186 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr
, level
)),
3187 "force highest pcie dpm state failed!", return -1);
3192 if (0 == data
->sclk_dpm_key_disabled
) {
3194 if (data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
!= 0) {
3196 tmp
= data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
;
3201 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr
, level
)),
3202 "force highest sclk dpm state failed!", return -1);
3203 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
,
3204 CGS_IND_REG__SMC
, TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_SCLK_INDEX
) != level
)
3205 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3206 Curr_Sclk_Index does not match the level \n");
3212 if (0 == data
->mclk_dpm_key_disabled
) {
3214 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
!= 0) {
3216 tmp
= data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
;
3221 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr
, level
)),
3222 "force highest mclk dpm state failed!", return -1);
3223 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3224 TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_MCLK_INDEX
) != level
)
3225 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3226 Curr_Mclk_Index does not match the level \n");
3235 * Find the MC microcode version and store it in the HwMgr struct
3237 * @param hwmgr the address of the powerplay hardware manager.
3240 int tonga_get_mc_microcode_version (struct pp_hwmgr
*hwmgr
)
3242 cgs_write_register(hwmgr
->device
, mmMC_SEQ_IO_DEBUG_INDEX
, 0x9F);
3244 hwmgr
->microcode_version_info
.MC
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_IO_DEBUG_DATA
);
3250 * Initialize Dynamic State Adjustment Rule Settings
3252 * @param hwmgr the address of the powerplay hardware manager.
3254 int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr
*hwmgr
)
3256 uint32_t table_size
;
3257 struct phm_clock_voltage_dependency_table
*table_clk_vlt
;
3258 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3260 hwmgr
->dyn_state
.mclk_sclk_ratio
= 4;
3261 hwmgr
->dyn_state
.sclk_mclk_delta
= 15000; /* 150 MHz */
3262 hwmgr
->dyn_state
.vddc_vddci_delta
= 200; /* 200mV */
3264 /* initialize vddc_dep_on_dal_pwrl table */
3265 table_size
= sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record
);
3266 table_clk_vlt
= (struct phm_clock_voltage_dependency_table
*)kzalloc(table_size
, GFP_KERNEL
);
3268 if (NULL
== table_clk_vlt
) {
3269 printk(KERN_ERR
"[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
3272 table_clk_vlt
->count
= 4;
3273 table_clk_vlt
->entries
[0].clk
= PP_DAL_POWERLEVEL_ULTRALOW
;
3274 table_clk_vlt
->entries
[0].v
= 0;
3275 table_clk_vlt
->entries
[1].clk
= PP_DAL_POWERLEVEL_LOW
;
3276 table_clk_vlt
->entries
[1].v
= 720;
3277 table_clk_vlt
->entries
[2].clk
= PP_DAL_POWERLEVEL_NOMINAL
;
3278 table_clk_vlt
->entries
[2].v
= 810;
3279 table_clk_vlt
->entries
[3].clk
= PP_DAL_POWERLEVEL_PERFORMANCE
;
3280 table_clk_vlt
->entries
[3].v
= 900;
3281 pptable_info
->vddc_dep_on_dal_pwrl
= table_clk_vlt
;
3282 hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
= table_clk_vlt
;
3288 static int tonga_set_private_var_based_on_pptale(struct pp_hwmgr
*hwmgr
)
3290 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3291 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3293 phm_ppt_v1_clock_voltage_dependency_table
*allowed_sclk_vdd_table
=
3294 pptable_info
->vdd_dep_on_sclk
;
3295 phm_ppt_v1_clock_voltage_dependency_table
*allowed_mclk_vdd_table
=
3296 pptable_info
->vdd_dep_on_mclk
;
3298 PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table
!= NULL
,
3299 "VDD dependency on SCLK table is missing. \
3300 This table is mandatory", return -1);
3301 PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table
->count
>= 1,
3302 "VDD dependency on SCLK table has to have is missing. \
3303 This table is mandatory", return -1);
3305 PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table
!= NULL
,
3306 "VDD dependency on MCLK table is missing. \
3307 This table is mandatory", return -1);
3308 PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table
->count
>= 1,
3309 "VDD dependency on MCLK table has to have is missing. \
3310 This table is mandatory", return -1);
3312 data
->min_vddc_in_pp_table
= (uint16_t)allowed_sclk_vdd_table
->entries
[0].vddc
;
3313 data
->max_vddc_in_pp_table
= (uint16_t)allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].vddc
;
3315 pptable_info
->max_clock_voltage_on_ac
.sclk
=
3316 allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].clk
;
3317 pptable_info
->max_clock_voltage_on_ac
.mclk
=
3318 allowed_mclk_vdd_table
->entries
[allowed_mclk_vdd_table
->count
- 1].clk
;
3319 pptable_info
->max_clock_voltage_on_ac
.vddc
=
3320 allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].vddc
;
3321 pptable_info
->max_clock_voltage_on_ac
.vddci
=
3322 allowed_mclk_vdd_table
->entries
[allowed_mclk_vdd_table
->count
- 1].vddci
;
3324 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.sclk
=
3325 pptable_info
->max_clock_voltage_on_ac
.sclk
;
3326 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.mclk
=
3327 pptable_info
->max_clock_voltage_on_ac
.mclk
;
3328 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.vddc
=
3329 pptable_info
->max_clock_voltage_on_ac
.vddc
;
3330 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.vddci
=
3331 pptable_info
->max_clock_voltage_on_ac
.vddci
;
3336 int tonga_unforce_dpm_levels(struct pp_hwmgr
*hwmgr
)
3338 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3341 PP_ASSERT_WITH_CODE (0 == tonga_is_dpm_running(hwmgr
),
3342 "Trying to Unforce DPM when DPM is disabled. Returning without sending SMC message.",
3345 if (0 == data
->pcie_dpm_key_disabled
) {
3346 PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(
3348 PPSMC_MSG_PCIeDPM_UnForceLevel
)),
3349 "unforce pcie level failed!",
3353 result
= tonga_upload_dpm_level_enable_mask(hwmgr
);
3358 static uint32_t tonga_get_lowest_enable_level(
3359 struct pp_hwmgr
*hwmgr
, uint32_t level_mask
)
3363 while (0 == (level_mask
& (1 << level
)))
3369 static int tonga_force_dpm_lowest(struct pp_hwmgr
*hwmgr
)
3372 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3374 if (0 == data
->pcie_dpm_key_disabled
) {
3376 if (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
!= 0) {
3377 level
= tonga_get_lowest_enable_level(hwmgr
,
3378 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
);
3379 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr
, level
)),
3380 "force lowest pcie dpm state failed!", return -1);
3384 if (0 == data
->sclk_dpm_key_disabled
) {
3386 if (0 != data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
3387 level
= tonga_get_lowest_enable_level(hwmgr
,
3388 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
3390 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr
, level
)),
3391 "force sclk dpm state failed!", return -1);
3393 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
,
3394 CGS_IND_REG__SMC
, TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_SCLK_INDEX
) != level
)
3395 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3396 Curr_Sclk_Index does not match the level \n");
3400 if (0 == data
->mclk_dpm_key_disabled
) {
3402 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
!= 0) {
3403 level
= tonga_get_lowest_enable_level(hwmgr
,
3404 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
);
3405 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr
, level
)),
3406 "force lowest mclk dpm state failed!", return -1);
3407 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3408 TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_MCLK_INDEX
) != level
)
3409 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3410 Curr_Mclk_Index does not match the level \n");
3417 static int tonga_patch_voltage_dependency_tables_with_lookup_table(struct pp_hwmgr
*hwmgr
)
3421 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3422 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3424 phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
= pptable_info
->vdd_dep_on_sclk
;
3425 phm_ppt_v1_clock_voltage_dependency_table
*mclk_table
= pptable_info
->vdd_dep_on_mclk
;
3426 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
3428 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3429 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
3430 voltageId
= sclk_table
->entries
[entryId
].vddInd
;
3431 sclk_table
->entries
[entryId
].vddgfx
=
3432 pptable_info
->vddgfx_lookup_table
->entries
[voltageId
].us_vdd
;
3435 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
3436 voltageId
= sclk_table
->entries
[entryId
].vddInd
;
3437 sclk_table
->entries
[entryId
].vddc
=
3438 pptable_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
3442 for (entryId
= 0; entryId
< mclk_table
->count
; ++entryId
) {
3443 voltageId
= mclk_table
->entries
[entryId
].vddInd
;
3444 mclk_table
->entries
[entryId
].vddc
=
3445 pptable_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
3448 for (entryId
= 0; entryId
< mm_table
->count
; ++entryId
) {
3449 voltageId
= mm_table
->entries
[entryId
].vddcInd
;
3450 mm_table
->entries
[entryId
].vddc
=
3451 pptable_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
3458 static int tonga_calc_voltage_dependency_tables(struct pp_hwmgr
*hwmgr
)
3461 phm_ppt_v1_voltage_lookup_record v_record
;
3462 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3463 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3465 phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
= pptable_info
->vdd_dep_on_sclk
;
3466 phm_ppt_v1_clock_voltage_dependency_table
*mclk_table
= pptable_info
->vdd_dep_on_mclk
;
3468 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3469 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
3470 if (sclk_table
->entries
[entryId
].vdd_offset
& (1 << 15))
3471 v_record
.us_vdd
= sclk_table
->entries
[entryId
].vddgfx
+
3472 sclk_table
->entries
[entryId
].vdd_offset
- 0xFFFF;
3474 v_record
.us_vdd
= sclk_table
->entries
[entryId
].vddgfx
+
3475 sclk_table
->entries
[entryId
].vdd_offset
;
3477 sclk_table
->entries
[entryId
].vddc
=
3478 v_record
.us_cac_low
= v_record
.us_cac_mid
=
3479 v_record
.us_cac_high
= v_record
.us_vdd
;
3481 tonga_add_voltage(hwmgr
, pptable_info
->vddc_lookup_table
, &v_record
);
3484 for (entryId
= 0; entryId
< mclk_table
->count
; ++entryId
) {
3485 if (mclk_table
->entries
[entryId
].vdd_offset
& (1 << 15))
3486 v_record
.us_vdd
= mclk_table
->entries
[entryId
].vddc
+
3487 mclk_table
->entries
[entryId
].vdd_offset
- 0xFFFF;
3489 v_record
.us_vdd
= mclk_table
->entries
[entryId
].vddc
+
3490 mclk_table
->entries
[entryId
].vdd_offset
;
3492 mclk_table
->entries
[entryId
].vddgfx
= v_record
.us_cac_low
=
3493 v_record
.us_cac_mid
= v_record
.us_cac_high
= v_record
.us_vdd
;
3494 tonga_add_voltage(hwmgr
, pptable_info
->vddgfx_lookup_table
, &v_record
);
3502 static int tonga_calc_mm_voltage_dependency_table(struct pp_hwmgr
*hwmgr
)
3505 phm_ppt_v1_voltage_lookup_record v_record
;
3506 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3507 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3508 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
3510 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3511 for (entryId
= 0; entryId
< mm_table
->count
; entryId
++) {
3512 if (mm_table
->entries
[entryId
].vddgfx_offset
& (1 << 15))
3513 v_record
.us_vdd
= mm_table
->entries
[entryId
].vddc
+
3514 mm_table
->entries
[entryId
].vddgfx_offset
- 0xFFFF;
3516 v_record
.us_vdd
= mm_table
->entries
[entryId
].vddc
+
3517 mm_table
->entries
[entryId
].vddgfx_offset
;
3519 /* Add the calculated VDDGFX to the VDDGFX lookup table */
3520 mm_table
->entries
[entryId
].vddgfx
= v_record
.us_cac_low
=
3521 v_record
.us_cac_mid
= v_record
.us_cac_high
= v_record
.us_vdd
;
3522 tonga_add_voltage(hwmgr
, pptable_info
->vddgfx_lookup_table
, &v_record
);
3530 * Change virtual leakage voltage to actual value.
3532 * @param hwmgr the address of the powerplay hardware manager.
3533 * @param pointer to changing voltage
3534 * @param pointer to leakage table
3536 static void tonga_patch_with_vdd_leakage(struct pp_hwmgr
*hwmgr
,
3537 uint16_t *voltage
, phw_tonga_leakage_voltage
*pLeakageTable
)
3539 uint32_t leakage_index
;
3541 /* search for leakage voltage ID 0xff01 ~ 0xff08 */
3542 for (leakage_index
= 0; leakage_index
< pLeakageTable
->count
; leakage_index
++) {
3543 /* if this voltage matches a leakage voltage ID */
3544 /* patch with actual leakage voltage */
3545 if (pLeakageTable
->leakage_id
[leakage_index
] == *voltage
) {
3546 *voltage
= pLeakageTable
->actual_voltage
[leakage_index
];
3551 if (*voltage
> ATOM_VIRTUAL_VOLTAGE_ID0
)
3552 printk(KERN_ERR
"[ powerplay ] Voltage value looks like a Leakage ID but it's not patched \n");
3556 * Patch voltage lookup table by EVV leakages.
3558 * @param hwmgr the address of the powerplay hardware manager.
3559 * @param pointer to voltage lookup table
3560 * @param pointer to leakage table
3563 static int tonga_patch_lookup_table_with_leakage(struct pp_hwmgr
*hwmgr
,
3564 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
3565 phw_tonga_leakage_voltage
*pLeakageTable
)
3569 for (i
= 0; i
< lookup_table
->count
; i
++) {
3570 tonga_patch_with_vdd_leakage(hwmgr
,
3571 &lookup_table
->entries
[i
].us_vdd
, pLeakageTable
);
3577 static int tonga_patch_clock_voltage_lomits_with_vddc_leakage(struct pp_hwmgr
*hwmgr
,
3578 phw_tonga_leakage_voltage
*pLeakageTable
, uint16_t *Vddc
)
3580 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3582 tonga_patch_with_vdd_leakage(hwmgr
, (uint16_t *)Vddc
, pLeakageTable
);
3583 hwmgr
->dyn_state
.max_clock_voltage_on_dc
.vddc
=
3584 pptable_info
->max_clock_voltage_on_dc
.vddc
;
3589 static int tonga_patch_clock_voltage_limits_with_vddgfx_leakage(
3590 struct pp_hwmgr
*hwmgr
, phw_tonga_leakage_voltage
*pLeakageTable
,
3593 tonga_patch_with_vdd_leakage(hwmgr
, (uint16_t *)Vddgfx
, pLeakageTable
);
3597 int tonga_sort_lookup_table(struct pp_hwmgr
*hwmgr
,
3598 phm_ppt_v1_voltage_lookup_table
*lookup_table
)
3600 uint32_t table_size
, i
, j
;
3601 phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record
;
3602 table_size
= lookup_table
->count
;
3604 PP_ASSERT_WITH_CODE(0 != lookup_table
->count
,
3605 "Lookup table is empty", return -1);
3607 /* Sorting voltages */
3608 for (i
= 0; i
< table_size
- 1; i
++) {
3609 for (j
= i
+ 1; j
> 0; j
--) {
3610 if (lookup_table
->entries
[j
].us_vdd
< lookup_table
->entries
[j
-1].us_vdd
) {
3611 tmp_voltage_lookup_record
= lookup_table
->entries
[j
-1];
3612 lookup_table
->entries
[j
-1] = lookup_table
->entries
[j
];
3613 lookup_table
->entries
[j
] = tmp_voltage_lookup_record
;
3621 static int tonga_complete_dependency_tables(struct pp_hwmgr
*hwmgr
)
3625 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
3626 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3628 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3629 tmp_result
= tonga_patch_lookup_table_with_leakage(hwmgr
,
3630 pptable_info
->vddgfx_lookup_table
, &(data
->vddcgfx_leakage
));
3631 if (tmp_result
!= 0)
3632 result
= tmp_result
;
3634 tmp_result
= tonga_patch_clock_voltage_limits_with_vddgfx_leakage(hwmgr
,
3635 &(data
->vddcgfx_leakage
), &pptable_info
->max_clock_voltage_on_dc
.vddgfx
);
3636 if (tmp_result
!= 0)
3637 result
= tmp_result
;
3639 tmp_result
= tonga_patch_lookup_table_with_leakage(hwmgr
,
3640 pptable_info
->vddc_lookup_table
, &(data
->vddc_leakage
));
3641 if (tmp_result
!= 0)
3642 result
= tmp_result
;
3644 tmp_result
= tonga_patch_clock_voltage_lomits_with_vddc_leakage(hwmgr
,
3645 &(data
->vddc_leakage
), &pptable_info
->max_clock_voltage_on_dc
.vddc
);
3646 if (tmp_result
!= 0)
3647 result
= tmp_result
;
3650 tmp_result
= tonga_patch_voltage_dependency_tables_with_lookup_table(hwmgr
);
3651 if (tmp_result
!= 0)
3652 result
= tmp_result
;
3654 tmp_result
= tonga_calc_voltage_dependency_tables(hwmgr
);
3655 if (tmp_result
!= 0)
3656 result
= tmp_result
;
3658 tmp_result
= tonga_calc_mm_voltage_dependency_table(hwmgr
);
3659 if (tmp_result
!= 0)
3660 result
= tmp_result
;
3662 tmp_result
= tonga_sort_lookup_table(hwmgr
, pptable_info
->vddgfx_lookup_table
);
3663 if (tmp_result
!= 0)
3664 result
= tmp_result
;
3666 tmp_result
= tonga_sort_lookup_table(hwmgr
, pptable_info
->vddc_lookup_table
);
3667 if (tmp_result
!= 0)
3668 result
= tmp_result
;
3673 int tonga_init_sclk_threshold(struct pp_hwmgr
*hwmgr
)
3675 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3676 data
->low_sclk_interrupt_threshold
= 0;
3681 int tonga_setup_asic_task(struct pp_hwmgr
*hwmgr
)
3683 int tmp_result
, result
= 0;
3685 tmp_result
= tonga_read_clock_registers(hwmgr
);
3686 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3687 "Failed to read clock registers!", result
= tmp_result
);
3689 tmp_result
= tonga_get_memory_type(hwmgr
);
3690 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3691 "Failed to get memory type!", result
= tmp_result
);
3693 tmp_result
= tonga_enable_acpi_power_management(hwmgr
);
3694 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3695 "Failed to enable ACPI power management!", result
= tmp_result
);
3697 tmp_result
= tonga_init_power_gate_state(hwmgr
);
3698 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3699 "Failed to init power gate state!", result
= tmp_result
);
3701 tmp_result
= tonga_get_mc_microcode_version(hwmgr
);
3702 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3703 "Failed to get MC microcode version!", result
= tmp_result
);
3705 tmp_result
= tonga_init_sclk_threshold(hwmgr
);
3706 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3707 "Failed to init sclk threshold!", result
= tmp_result
);
3713 * Enable voltage control
3715 * @param hwmgr the address of the powerplay hardware manager.
3718 int tonga_enable_voltage_control(struct pp_hwmgr
*hwmgr
)
3720 /* enable voltage control */
3721 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, VOLT_PWRMGT_EN
, 1);
3727 * Checks if we want to support voltage control
3729 * @param hwmgr the address of the powerplay hardware manager.
3731 bool cf_tonga_voltage_control(const struct pp_hwmgr
*hwmgr
)
3733 const struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
3735 return(TONGA_VOLTAGE_CONTROL_NONE
!= data
->voltage_control
);
3738 /*---------------------------MC----------------------------*/
3740 uint8_t tonga_get_memory_modile_index(struct pp_hwmgr
*hwmgr
)
3742 return (uint8_t) (0xFF & (cgs_read_register(hwmgr
->device
, mmBIOS_SCRATCH_4
) >> 16));
3745 bool tonga_check_s0_mc_reg_index(uint16_t inReg
, uint16_t *outReg
)
3750 case mmMC_SEQ_RAS_TIMING
:
3751 *outReg
= mmMC_SEQ_RAS_TIMING_LP
;
3754 case mmMC_SEQ_DLL_STBY
:
3755 *outReg
= mmMC_SEQ_DLL_STBY_LP
;
3758 case mmMC_SEQ_G5PDX_CMD0
:
3759 *outReg
= mmMC_SEQ_G5PDX_CMD0_LP
;
3762 case mmMC_SEQ_G5PDX_CMD1
:
3763 *outReg
= mmMC_SEQ_G5PDX_CMD1_LP
;
3766 case mmMC_SEQ_G5PDX_CTRL
:
3767 *outReg
= mmMC_SEQ_G5PDX_CTRL_LP
;
3770 case mmMC_SEQ_CAS_TIMING
:
3771 *outReg
= mmMC_SEQ_CAS_TIMING_LP
;
3774 case mmMC_SEQ_MISC_TIMING
:
3775 *outReg
= mmMC_SEQ_MISC_TIMING_LP
;
3778 case mmMC_SEQ_MISC_TIMING2
:
3779 *outReg
= mmMC_SEQ_MISC_TIMING2_LP
;
3782 case mmMC_SEQ_PMG_DVS_CMD
:
3783 *outReg
= mmMC_SEQ_PMG_DVS_CMD_LP
;
3786 case mmMC_SEQ_PMG_DVS_CTL
:
3787 *outReg
= mmMC_SEQ_PMG_DVS_CTL_LP
;
3790 case mmMC_SEQ_RD_CTL_D0
:
3791 *outReg
= mmMC_SEQ_RD_CTL_D0_LP
;
3794 case mmMC_SEQ_RD_CTL_D1
:
3795 *outReg
= mmMC_SEQ_RD_CTL_D1_LP
;
3798 case mmMC_SEQ_WR_CTL_D0
:
3799 *outReg
= mmMC_SEQ_WR_CTL_D0_LP
;
3802 case mmMC_SEQ_WR_CTL_D1
:
3803 *outReg
= mmMC_SEQ_WR_CTL_D1_LP
;
3806 case mmMC_PMG_CMD_EMRS
:
3807 *outReg
= mmMC_SEQ_PMG_CMD_EMRS_LP
;
3810 case mmMC_PMG_CMD_MRS
:
3811 *outReg
= mmMC_SEQ_PMG_CMD_MRS_LP
;
3814 case mmMC_PMG_CMD_MRS1
:
3815 *outReg
= mmMC_SEQ_PMG_CMD_MRS1_LP
;
3818 case mmMC_SEQ_PMG_TIMING
:
3819 *outReg
= mmMC_SEQ_PMG_TIMING_LP
;
3822 case mmMC_PMG_CMD_MRS2
:
3823 *outReg
= mmMC_SEQ_PMG_CMD_MRS2_LP
;
3826 case mmMC_SEQ_WR_CTL_2
:
3827 *outReg
= mmMC_SEQ_WR_CTL_2_LP
;
3838 int tonga_set_s0_mc_reg_index(phw_tonga_mc_reg_table
*table
)
3843 for (i
= 0; i
< table
->last
; i
++) {
3844 table
->mc_reg_address
[i
].s0
=
3845 tonga_check_s0_mc_reg_index(table
->mc_reg_address
[i
].s1
, &address
)
3846 ? address
: table
->mc_reg_address
[i
].s1
;
3851 int tonga_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table
*table
, phw_tonga_mc_reg_table
*ni_table
)
3855 PP_ASSERT_WITH_CODE((table
->last
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3856 "Invalid VramInfo table.", return -1);
3857 PP_ASSERT_WITH_CODE((table
->num_entries
<= MAX_AC_TIMING_ENTRIES
),
3858 "Invalid VramInfo table.", return -1);
3860 for (i
= 0; i
< table
->last
; i
++) {
3861 ni_table
->mc_reg_address
[i
].s1
= table
->mc_reg_address
[i
].s1
;
3863 ni_table
->last
= table
->last
;
3865 for (i
= 0; i
< table
->num_entries
; i
++) {
3866 ni_table
->mc_reg_table_entry
[i
].mclk_max
=
3867 table
->mc_reg_table_entry
[i
].mclk_max
;
3868 for (j
= 0; j
< table
->last
; j
++) {
3869 ni_table
->mc_reg_table_entry
[i
].mc_data
[j
] =
3870 table
->mc_reg_table_entry
[i
].mc_data
[j
];
3874 ni_table
->num_entries
= table
->num_entries
;
3880 * VBIOS omits some information to reduce size, we need to recover them here.
3881 * 1. when we see mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to mmMC_PMG_CMD_EMRS /_LP[15:0].
3882 * Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
3883 * 2. when we see mmMC_SEQ_RESERVE_M, bit[15:0] EMRS2, need to be write to mmMC_PMG_CMD_MRS1/_LP[15:0].
3884 * 3. need to set these data for each clock range
3886 * @param hwmgr the address of the powerplay hardware manager.
3887 * @param table the address of MCRegTable
3890 int tonga_set_mc_special_registers(struct pp_hwmgr
*hwmgr
, phw_tonga_mc_reg_table
*table
)
3894 const tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
3896 for (i
= 0, j
= table
->last
; i
< table
->last
; i
++) {
3897 PP_ASSERT_WITH_CODE((j
< SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3898 "Invalid VramInfo table.", return -1);
3899 switch (table
->mc_reg_address
[i
].s1
) {
3901 * mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to mmMC_PMG_CMD_EMRS /_LP[15:0].
3902 * Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
3904 case mmMC_SEQ_MISC1
:
3905 temp_reg
= cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_EMRS
);
3906 table
->mc_reg_address
[j
].s1
= mmMC_PMG_CMD_EMRS
;
3907 table
->mc_reg_address
[j
].s0
= mmMC_SEQ_PMG_CMD_EMRS_LP
;
3908 for (k
= 0; k
< table
->num_entries
; k
++) {
3909 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3910 ((temp_reg
& 0xffff0000)) |
3911 ((table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0xffff0000) >> 16);
3914 PP_ASSERT_WITH_CODE((j
< SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3915 "Invalid VramInfo table.", return -1);
3917 temp_reg
= cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS
);
3918 table
->mc_reg_address
[j
].s1
= mmMC_PMG_CMD_MRS
;
3919 table
->mc_reg_address
[j
].s0
= mmMC_SEQ_PMG_CMD_MRS_LP
;
3920 for (k
= 0; k
< table
->num_entries
; k
++) {
3921 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3922 (temp_reg
& 0xffff0000) |
3923 (table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0x0000ffff);
3925 if (!data
->is_memory_GDDR5
) {
3926 table
->mc_reg_table_entry
[k
].mc_data
[j
] |= 0x100;
3930 PP_ASSERT_WITH_CODE((j
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3931 "Invalid VramInfo table.", return -1);
3933 if (!data
->is_memory_GDDR5
) {
3934 table
->mc_reg_address
[j
].s1
= mmMC_PMG_AUTO_CMD
;
3935 table
->mc_reg_address
[j
].s0
= mmMC_PMG_AUTO_CMD
;
3936 for (k
= 0; k
< table
->num_entries
; k
++) {
3937 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3938 (table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0xffff0000) >> 16;
3941 PP_ASSERT_WITH_CODE((j
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3942 "Invalid VramInfo table.", return -1);
3947 case mmMC_SEQ_RESERVE_M
:
3948 temp_reg
= cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS1
);
3949 table
->mc_reg_address
[j
].s1
= mmMC_PMG_CMD_MRS1
;
3950 table
->mc_reg_address
[j
].s0
= mmMC_SEQ_PMG_CMD_MRS1_LP
;
3951 for (k
= 0; k
< table
->num_entries
; k
++) {
3952 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3953 (temp_reg
& 0xffff0000) |
3954 (table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0x0000ffff);
3957 PP_ASSERT_WITH_CODE((j
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3958 "Invalid VramInfo table.", return -1);
3972 int tonga_set_valid_flag(phw_tonga_mc_reg_table
*table
)
3975 for (i
= 0; i
< table
->last
; i
++) {
3976 for (j
= 1; j
< table
->num_entries
; j
++) {
3977 if (table
->mc_reg_table_entry
[j
-1].mc_data
[i
] !=
3978 table
->mc_reg_table_entry
[j
].mc_data
[i
]) {
3979 table
->validflag
|= (1<<i
);
3988 int tonga_initialize_mc_reg_table(struct pp_hwmgr
*hwmgr
)
3991 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3992 pp_atomctrl_mc_reg_table
*table
;
3993 phw_tonga_mc_reg_table
*ni_table
= &data
->tonga_mc_reg_table
;
3994 uint8_t module_index
= tonga_get_memory_modile_index(hwmgr
);
3996 table
= kzalloc(sizeof(pp_atomctrl_mc_reg_table
), GFP_KERNEL
);
4001 /* Program additional LP registers that are no longer programmed by VBIOS */
4002 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING
));
4003 cgs_write_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING
));
4004 cgs_write_register(hwmgr
->device
, mmMC_SEQ_DLL_STBY_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_DLL_STBY
));
4005 cgs_write_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD0_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD0
));
4006 cgs_write_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD1_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD1
));
4007 cgs_write_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CTRL_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CTRL
));
4008 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CMD_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CMD
));
4009 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CTL_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CTL
));
4010 cgs_write_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING
));
4011 cgs_write_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2
));
4012 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_EMRS_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_EMRS
));
4013 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_MRS_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS
));
4014 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_MRS1_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS1
));
4015 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D0_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D0
));
4016 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1
));
4017 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0
));
4018 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1
));
4019 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING
));
4020 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_MRS2_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS2
));
4021 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_2_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_2
));
4023 memset(table
, 0x00, sizeof(pp_atomctrl_mc_reg_table
));
4025 result
= atomctrl_initialize_mc_reg_table(hwmgr
, module_index
, table
);
4028 result
= tonga_copy_vbios_smc_reg_table(table
, ni_table
);
4031 tonga_set_s0_mc_reg_index(ni_table
);
4032 result
= tonga_set_mc_special_registers(hwmgr
, ni_table
);
4036 tonga_set_valid_flag(ni_table
);
4043 * Copy one arb setting to another and then switch the active set.
4044 * arbFreqSrc and arbFreqDest is one of the MC_CG_ARB_FREQ_Fx constants.
4046 int tonga_copy_and_switch_arb_sets(struct pp_hwmgr
*hwmgr
,
4047 uint32_t arbFreqSrc
, uint32_t arbFreqDest
)
4049 uint32_t mc_arb_dram_timing
;
4050 uint32_t mc_arb_dram_timing2
;
4051 uint32_t burst_time
;
4052 uint32_t mc_cg_config
;
4054 switch (arbFreqSrc
) {
4055 case MC_CG_ARB_FREQ_F0
:
4056 mc_arb_dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
4057 mc_arb_dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
4058 burst_time
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
);
4061 case MC_CG_ARB_FREQ_F1
:
4062 mc_arb_dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING_1
);
4063 mc_arb_dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2_1
);
4064 burst_time
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE1
);
4071 switch (arbFreqDest
) {
4072 case MC_CG_ARB_FREQ_F0
:
4073 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
, mc_arb_dram_timing
);
4074 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
, mc_arb_dram_timing2
);
4075 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
, burst_time
);
4078 case MC_CG_ARB_FREQ_F1
:
4079 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING_1
, mc_arb_dram_timing
);
4080 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2_1
, mc_arb_dram_timing2
);
4081 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE1
, burst_time
);
4088 mc_cg_config
= cgs_read_register(hwmgr
->device
, mmMC_CG_CONFIG
);
4089 mc_cg_config
|= 0x0000000F;
4090 cgs_write_register(hwmgr
->device
, mmMC_CG_CONFIG
, mc_cg_config
);
4091 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_CG
, CG_ARB_REQ
, arbFreqDest
);
4097 * Initial switch from ARB F0->F1
4099 * @param hwmgr the address of the powerplay hardware manager.
4101 * This function is to be called from the SetPowerState table.
4103 int tonga_initial_switch_from_arb_f0_to_f1(struct pp_hwmgr
*hwmgr
)
4105 return tonga_copy_and_switch_arb_sets(hwmgr
, MC_CG_ARB_FREQ_F0
, MC_CG_ARB_FREQ_F1
);
4109 * Initialize the ARB DRAM timing table's index field.
4111 * @param hwmgr the address of the powerplay hardware manager.
4114 int tonga_init_arb_table_index(struct pp_hwmgr
*hwmgr
)
4116 const tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4121 * This is a read-modify-write on the first byte of the ARB table.
4122 * The first byte in the SMU72_Discrete_MCArbDramTimingTable structure is the field 'current'.
4123 * This solution is ugly, but we never write the whole table only individual fields in it.
4124 * In reality this field should not be in that structure but in a soft register.
4126 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
4127 data
->arb_table_start
, &tmp
, data
->sram_end
);
4133 tmp
|= ((uint32_t)MC_CG_ARB_FREQ_F1
) << 24;
4135 return tonga_write_smc_sram_dword(hwmgr
->smumgr
,
4136 data
->arb_table_start
, tmp
, data
->sram_end
);
4139 int tonga_populate_mc_reg_address(struct pp_hwmgr
*hwmgr
, SMU72_Discrete_MCRegisters
*mc_reg_table
)
4141 const struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4145 for (i
= 0, j
= 0; j
< data
->tonga_mc_reg_table
.last
; j
++) {
4146 if (data
->tonga_mc_reg_table
.validflag
& 1<<j
) {
4147 PP_ASSERT_WITH_CODE(i
< SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
,
4148 "Index of mc_reg_table->address[] array out of boundary", return -1);
4149 mc_reg_table
->address
[i
].s0
=
4150 PP_HOST_TO_SMC_US(data
->tonga_mc_reg_table
.mc_reg_address
[j
].s0
);
4151 mc_reg_table
->address
[i
].s1
=
4152 PP_HOST_TO_SMC_US(data
->tonga_mc_reg_table
.mc_reg_address
[j
].s1
);
4157 mc_reg_table
->last
= (uint8_t)i
;
4162 /*convert register values from driver to SMC format */
4163 void tonga_convert_mc_registers(
4164 const phw_tonga_mc_reg_entry
* pEntry
,
4165 SMU72_Discrete_MCRegisterSet
*pData
,
4166 uint32_t numEntries
, uint32_t validflag
)
4170 for (i
= 0, j
= 0; j
< numEntries
; j
++) {
4171 if (validflag
& 1<<j
) {
4172 pData
->value
[i
] = PP_HOST_TO_SMC_UL(pEntry
->mc_data
[j
]);
4178 /* find the entry in the memory range table, then populate the value to SMC's tonga_mc_reg_table */
4179 int tonga_convert_mc_reg_table_entry_to_smc(
4180 struct pp_hwmgr
*hwmgr
,
4181 const uint32_t memory_clock
,
4182 SMU72_Discrete_MCRegisterSet
*mc_reg_table_data
4185 const tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4188 for (i
= 0; i
< data
->tonga_mc_reg_table
.num_entries
; i
++) {
4190 data
->tonga_mc_reg_table
.mc_reg_table_entry
[i
].mclk_max
) {
4195 if ((i
== data
->tonga_mc_reg_table
.num_entries
) && (i
> 0))
4198 tonga_convert_mc_registers(&data
->tonga_mc_reg_table
.mc_reg_table_entry
[i
],
4199 mc_reg_table_data
, data
->tonga_mc_reg_table
.last
, data
->tonga_mc_reg_table
.validflag
);
4204 int tonga_convert_mc_reg_table_to_smc(struct pp_hwmgr
*hwmgr
,
4205 SMU72_Discrete_MCRegisters
*mc_reg_table
)
4208 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4212 for (i
= 0; i
< data
->dpm_table
.mclk_table
.count
; i
++) {
4213 res
= tonga_convert_mc_reg_table_entry_to_smc(
4215 data
->dpm_table
.mclk_table
.dpm_levels
[i
].value
,
4216 &mc_reg_table
->data
[i
]
4226 int tonga_populate_initial_mc_reg_table(struct pp_hwmgr
*hwmgr
)
4229 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4231 memset(&data
->mc_reg_table
, 0x00, sizeof(SMU72_Discrete_MCRegisters
));
4232 result
= tonga_populate_mc_reg_address(hwmgr
, &(data
->mc_reg_table
));
4233 PP_ASSERT_WITH_CODE(0 == result
,
4234 "Failed to initialize MCRegTable for the MC register addresses!", return result
;);
4236 result
= tonga_convert_mc_reg_table_to_smc(hwmgr
, &data
->mc_reg_table
);
4237 PP_ASSERT_WITH_CODE(0 == result
,
4238 "Failed to initialize MCRegTable for driver state!", return result
;);
4240 return tonga_copy_bytes_to_smc(hwmgr
->smumgr
, data
->mc_reg_table_start
,
4241 (uint8_t *)&data
->mc_reg_table
, sizeof(SMU72_Discrete_MCRegisters
), data
->sram_end
);
4245 * Programs static screed detection parameters
4247 * @param hwmgr the address of the powerplay hardware manager.
4250 int tonga_program_static_screen_threshold_parameters(struct pp_hwmgr
*hwmgr
)
4252 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
4254 /* Set static screen threshold unit*/
4255 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
,
4256 CGS_IND_REG__SMC
, CG_STATIC_SCREEN_PARAMETER
, STATIC_SCREEN_THRESHOLD_UNIT
,
4257 data
->static_screen_threshold_unit
);
4258 /* Set static screen threshold*/
4259 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
,
4260 CGS_IND_REG__SMC
, CG_STATIC_SCREEN_PARAMETER
, STATIC_SCREEN_THRESHOLD
,
4261 data
->static_screen_threshold
);
4267 * Setup display gap for glitch free memory clock switching.
4269 * @param hwmgr the address of the powerplay hardware manager.
4272 int tonga_enable_display_gap(struct pp_hwmgr
*hwmgr
)
4274 uint32_t display_gap
= cgs_read_ind_register(hwmgr
->device
,
4275 CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
);
4277 display_gap
= PHM_SET_FIELD(display_gap
,
4278 CG_DISPLAY_GAP_CNTL
, DISP_GAP
, DISPLAY_GAP_IGNORE
);
4280 display_gap
= PHM_SET_FIELD(display_gap
,
4281 CG_DISPLAY_GAP_CNTL
, DISP_GAP_MCHG
, DISPLAY_GAP_VBLANK
);
4283 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4284 ixCG_DISPLAY_GAP_CNTL
, display_gap
);
4290 * Programs activity state transition voting clients
4292 * @param hwmgr the address of the powerplay hardware manager.
4295 int tonga_program_voting_clients(struct pp_hwmgr
*hwmgr
)
4297 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
4299 /* Clear reset for voting clients before enabling DPM */
4300 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
4301 SCLK_PWRMGT_CNTL
, RESET_SCLK_CNT
, 0);
4302 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
4303 SCLK_PWRMGT_CNTL
, RESET_BUSY_CNT
, 0);
4305 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4306 ixCG_FREQ_TRAN_VOTING_0
, data
->voting_rights_clients0
);
4307 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4308 ixCG_FREQ_TRAN_VOTING_1
, data
->voting_rights_clients1
);
4309 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4310 ixCG_FREQ_TRAN_VOTING_2
, data
->voting_rights_clients2
);
4311 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4312 ixCG_FREQ_TRAN_VOTING_3
, data
->voting_rights_clients3
);
4313 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4314 ixCG_FREQ_TRAN_VOTING_4
, data
->voting_rights_clients4
);
4315 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4316 ixCG_FREQ_TRAN_VOTING_5
, data
->voting_rights_clients5
);
4317 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4318 ixCG_FREQ_TRAN_VOTING_6
, data
->voting_rights_clients6
);
4319 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4320 ixCG_FREQ_TRAN_VOTING_7
, data
->voting_rights_clients7
);
4326 int tonga_enable_dpm_tasks(struct pp_hwmgr
*hwmgr
)
4328 int tmp_result
, result
= 0;
4330 tmp_result
= tonga_check_for_dpm_stopped(hwmgr
);
4332 if (cf_tonga_voltage_control(hwmgr
)) {
4333 tmp_result
= tonga_enable_voltage_control(hwmgr
);
4334 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4335 "Failed to enable voltage control!", result
= tmp_result
);
4337 tmp_result
= tonga_construct_voltage_tables(hwmgr
);
4338 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4339 "Failed to contruct voltage tables!", result
= tmp_result
);
4342 tmp_result
= tonga_initialize_mc_reg_table(hwmgr
);
4343 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4344 "Failed to initialize MC reg table!", result
= tmp_result
);
4346 tmp_result
= tonga_program_static_screen_threshold_parameters(hwmgr
);
4347 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4348 "Failed to program static screen threshold parameters!", result
= tmp_result
);
4350 tmp_result
= tonga_enable_display_gap(hwmgr
);
4351 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4352 "Failed to enable display gap!", result
= tmp_result
);
4354 tmp_result
= tonga_program_voting_clients(hwmgr
);
4355 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4356 "Failed to program voting clients!", result
= tmp_result
);
4358 tmp_result
= tonga_process_firmware_header(hwmgr
);
4359 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4360 "Failed to process firmware header!", result
= tmp_result
);
4362 tmp_result
= tonga_initial_switch_from_arb_f0_to_f1(hwmgr
);
4363 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4364 "Failed to initialize switch from ArbF0 to F1!", result
= tmp_result
);
4366 tmp_result
= tonga_init_smc_table(hwmgr
);
4367 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4368 "Failed to initialize SMC table!", result
= tmp_result
);
4370 tmp_result
= tonga_init_arb_table_index(hwmgr
);
4371 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4372 "Failed to initialize ARB table index!", result
= tmp_result
);
4374 tmp_result
= tonga_populate_initial_mc_reg_table(hwmgr
);
4375 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4376 "Failed to populate initialize MC Reg table!", result
= tmp_result
);
4378 tmp_result
= tonga_notify_smc_display_change(hwmgr
, false);
4379 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4380 "Failed to notify no display!", result
= tmp_result
);
4382 /* enable SCLK control */
4383 tmp_result
= tonga_enable_sclk_control(hwmgr
);
4384 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4385 "Failed to enable SCLK control!", result
= tmp_result
);
4388 tmp_result
= tonga_start_dpm(hwmgr
);
4389 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4390 "Failed to start DPM!", result
= tmp_result
);
4395 int tonga_disable_dpm_tasks(struct pp_hwmgr
*hwmgr
)
4397 int tmp_result
, result
= 0;
4399 tmp_result
= tonga_check_for_dpm_running(hwmgr
);
4400 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4401 "SMC is still running!", return 0);
4403 tmp_result
= tonga_stop_dpm(hwmgr
);
4404 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4405 "Failed to stop DPM!", result
= tmp_result
);
4407 tmp_result
= tonga_reset_to_default(hwmgr
);
4408 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4409 "Failed to reset to default!", result
= tmp_result
);
4414 int tonga_reset_asic_tasks(struct pp_hwmgr
*hwmgr
)
4418 result
= tonga_set_boot_state(hwmgr
);
4420 printk(KERN_ERR
"[ powerplay ] Failed to reset asic via set boot state! \n");
4425 int tonga_hwmgr_backend_fini(struct pp_hwmgr
*hwmgr
)
4427 if (NULL
!= hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
) {
4428 kfree(hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
);
4429 hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
= NULL
;
4432 if (NULL
!= hwmgr
->backend
) {
4433 kfree(hwmgr
->backend
);
4434 hwmgr
->backend
= NULL
;
4441 * Initializes the Volcanic Islands Hardware Manager
4443 * @param hwmgr the address of the powerplay hardware manager.
4444 * @return 1 if success; otherwise appropriate error code.
4446 int tonga_hwmgr_backend_init(struct pp_hwmgr
*hwmgr
)
4449 SMU72_Discrete_DpmTable
*table
= NULL
;
4450 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4451 pp_atomctrl_gpio_pin_assignment gpio_pin_assignment
;
4452 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4453 phw_tonga_ulv_parm
*ulv
;
4455 PP_ASSERT_WITH_CODE((NULL
!= hwmgr
),
4456 "Invalid Parameter!", return -1;);
4458 data
->dll_defaule_on
= 0;
4459 data
->sram_end
= SMC_RAM_END
;
4461 data
->activity_target
[0] = PPTONGA_TARGETACTIVITY_DFLT
;
4462 data
->activity_target
[1] = PPTONGA_TARGETACTIVITY_DFLT
;
4463 data
->activity_target
[2] = PPTONGA_TARGETACTIVITY_DFLT
;
4464 data
->activity_target
[3] = PPTONGA_TARGETACTIVITY_DFLT
;
4465 data
->activity_target
[4] = PPTONGA_TARGETACTIVITY_DFLT
;
4466 data
->activity_target
[5] = PPTONGA_TARGETACTIVITY_DFLT
;
4467 data
->activity_target
[6] = PPTONGA_TARGETACTIVITY_DFLT
;
4468 data
->activity_target
[7] = PPTONGA_TARGETACTIVITY_DFLT
;
4470 data
->vddc_vddci_delta
= VDDC_VDDCI_DELTA
;
4471 data
->vddc_vddgfx_delta
= VDDC_VDDGFX_DELTA
;
4472 data
->mclk_activity_target
= PPTONGA_MCLK_TARGETACTIVITY_DFLT
;
4474 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4475 PHM_PlatformCaps_DisableVoltageIsland
);
4477 data
->sclk_dpm_key_disabled
= 0;
4478 data
->mclk_dpm_key_disabled
= 0;
4479 data
->pcie_dpm_key_disabled
= 0;
4480 data
->pcc_monitor_enabled
= 0;
4482 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4483 PHM_PlatformCaps_UnTabledHardwareInterface
);
4485 data
->gpio_debug
= 0;
4486 data
->engine_clock_data
= 0;
4487 data
->memory_clock_data
= 0;
4488 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4489 PHM_PlatformCaps_DynamicPatchPowerState
);
4491 /* need to set voltage control types before EVV patching*/
4492 data
->voltage_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4493 data
->vdd_ci_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4494 data
->vdd_gfx_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4495 data
->mvdd_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4497 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4498 VOLTAGE_TYPE_VDDC
, VOLTAGE_OBJ_SVID2
)) {
4499 data
->voltage_control
= TONGA_VOLTAGE_CONTROL_BY_SVID2
;
4502 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4503 PHM_PlatformCaps_ControlVDDGFX
)) {
4504 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4505 VOLTAGE_TYPE_VDDGFX
, VOLTAGE_OBJ_SVID2
)) {
4506 data
->vdd_gfx_control
= TONGA_VOLTAGE_CONTROL_BY_SVID2
;
4510 if (TONGA_VOLTAGE_CONTROL_NONE
== data
->vdd_gfx_control
) {
4511 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4512 PHM_PlatformCaps_ControlVDDGFX
);
4515 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4516 PHM_PlatformCaps_EnableMVDDControl
)) {
4517 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4518 VOLTAGE_TYPE_MVDDC
, VOLTAGE_OBJ_GPIO_LUT
)) {
4519 data
->mvdd_control
= TONGA_VOLTAGE_CONTROL_BY_GPIO
;
4523 if (TONGA_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
) {
4524 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4525 PHM_PlatformCaps_EnableMVDDControl
);
4528 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4529 PHM_PlatformCaps_ControlVDDCI
)) {
4530 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4531 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_GPIO_LUT
))
4532 data
->vdd_ci_control
= TONGA_VOLTAGE_CONTROL_BY_GPIO
;
4533 else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4534 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_SVID2
))
4535 data
->vdd_ci_control
= TONGA_VOLTAGE_CONTROL_BY_SVID2
;
4538 if (TONGA_VOLTAGE_CONTROL_NONE
== data
->vdd_ci_control
)
4539 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4540 PHM_PlatformCaps_ControlVDDCI
);
4542 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4543 PHM_PlatformCaps_TablelessHardwareInterface
);
4545 if (pptable_info
->cac_dtp_table
->usClockStretchAmount
!= 0)
4546 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4547 PHM_PlatformCaps_ClockStretcher
);
4549 /* Initializes DPM default values*/
4550 tonga_initialize_dpm_defaults(hwmgr
);
4552 /* Get leakage voltage based on leakage ID.*/
4553 PP_ASSERT_WITH_CODE((0 == tonga_get_evv_voltage(hwmgr
)),
4554 "Get EVV Voltage Failed. Abort Driver loading!", return -1);
4556 tonga_complete_dependency_tables(hwmgr
);
4558 /* Parse pptable data read from VBIOS*/
4559 tonga_set_private_var_based_on_pptale(hwmgr
);
4563 ulv
->ulv_supported
= 0;
4565 /* Initalize Dynamic State Adjustment Rule Settings*/
4566 result
= tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr
);
4568 printk(KERN_ERR
"[ powerplay ] tonga_initializa_dynamic_state_adjustment_rule_settings failed!\n");
4569 data
->uvd_enabled
= 0;
4571 table
= &(data
->smc_state_table
);
4574 * if ucGPIO_ID=VDDC_PCC_GPIO_PINID in GPIO_LUTable,
4575 * Peak Current Control feature is enabled and we should program PCC HW register
4577 if (0 == atomctrl_get_pp_assign_pin(hwmgr
, VDDC_PCC_GPIO_PINID
, &gpio_pin_assignment
)) {
4578 uint32_t temp_reg
= cgs_read_ind_register(hwmgr
->device
,
4579 CGS_IND_REG__SMC
, ixCNB_PWRMGT_CNTL
);
4581 switch (gpio_pin_assignment
.uc_gpio_pin_bit_shift
) {
4583 temp_reg
= PHM_SET_FIELD(temp_reg
,
4584 CNB_PWRMGT_CNTL
, GNB_SLOW_MODE
, 0x1);
4587 temp_reg
= PHM_SET_FIELD(temp_reg
,
4588 CNB_PWRMGT_CNTL
, GNB_SLOW_MODE
, 0x2);
4591 temp_reg
= PHM_SET_FIELD(temp_reg
,
4592 CNB_PWRMGT_CNTL
, GNB_SLOW
, 0x1);
4595 temp_reg
= PHM_SET_FIELD(temp_reg
,
4596 CNB_PWRMGT_CNTL
, FORCE_NB_PS1
, 0x1);
4599 temp_reg
= PHM_SET_FIELD(temp_reg
,
4600 CNB_PWRMGT_CNTL
, DPM_ENABLED
, 0x1);
4603 printk(KERN_ERR
"[ powerplay ] Failed to setup PCC HW register! \
4604 Wrong GPIO assigned for VDDC_PCC_GPIO_PINID! \n");
4607 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4608 ixCNB_PWRMGT_CNTL
, temp_reg
);
4611 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4612 PHM_PlatformCaps_EnableSMU7ThermalManagement
);
4613 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4614 PHM_PlatformCaps_SMU7
);
4616 data
->vddc_phase_shed_control
= 0;
4619 struct cgs_system_info sys_info
= {0};
4621 data
->is_tlu_enabled
= 0;
4622 hwmgr
->platform_descriptor
.hardwareActivityPerformanceLevels
=
4623 TONGA_MAX_HARDWARE_POWERLEVELS
;
4624 hwmgr
->platform_descriptor
.hardwarePerformanceLevels
= 2;
4625 hwmgr
->platform_descriptor
.minimumClocksReductionPercentage
= 50;
4627 sys_info
.size
= sizeof(struct cgs_system_info
);
4628 sys_info
.info_id
= CGS_SYSTEM_INFO_PCIE_GEN_INFO
;
4629 result
= cgs_query_system_info(hwmgr
->device
, &sys_info
);
4631 data
->pcie_gen_cap
= 0x30007;
4633 data
->pcie_gen_cap
= (uint32_t)sys_info
.value
;
4634 if (data
->pcie_gen_cap
& CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3
)
4635 data
->pcie_spc_cap
= 20;
4636 sys_info
.size
= sizeof(struct cgs_system_info
);
4637 sys_info
.info_id
= CGS_SYSTEM_INFO_PCIE_MLW
;
4638 result
= cgs_query_system_info(hwmgr
->device
, &sys_info
);
4640 data
->pcie_lane_cap
= 0x2f0000;
4642 data
->pcie_lane_cap
= (uint32_t)sys_info
.value
;
4644 /* Ignore return value in here, we are cleaning up a mess. */
4645 tonga_hwmgr_backend_fini(hwmgr
);
4651 static int tonga_force_dpm_level(struct pp_hwmgr
*hwmgr
,
4652 enum amd_dpm_forced_level level
)
4657 case AMD_DPM_FORCED_LEVEL_HIGH
:
4658 ret
= tonga_force_dpm_highest(hwmgr
);
4662 case AMD_DPM_FORCED_LEVEL_LOW
:
4663 ret
= tonga_force_dpm_lowest(hwmgr
);
4667 case AMD_DPM_FORCED_LEVEL_AUTO
:
4668 ret
= tonga_unforce_dpm_levels(hwmgr
);
4676 hwmgr
->dpm_level
= level
;
4680 static int tonga_apply_state_adjust_rules(struct pp_hwmgr
*hwmgr
,
4681 struct pp_power_state
*prequest_ps
,
4682 const struct pp_power_state
*pcurrent_ps
)
4684 struct tonga_power_state
*tonga_ps
=
4685 cast_phw_tonga_power_state(&prequest_ps
->hardware
);
4689 struct PP_Clocks minimum_clocks
= {0};
4690 bool disable_mclk_switching
;
4691 bool disable_mclk_switching_for_frame_lock
;
4692 struct cgs_display_info info
= {0};
4693 const struct phm_clock_and_voltage_limits
*max_limits
;
4695 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4696 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4699 int32_t stable_pstate_sclk
= 0, stable_pstate_mclk
= 0;
4701 data
->battery_state
= (PP_StateUILabel_Battery
== prequest_ps
->classification
.ui_label
);
4703 PP_ASSERT_WITH_CODE(tonga_ps
->performance_level_count
== 2,
4704 "VI should always have 2 performance levels",
4707 max_limits
= (PP_PowerSource_AC
== hwmgr
->power_source
) ?
4708 &(hwmgr
->dyn_state
.max_clock_voltage_on_ac
) :
4709 &(hwmgr
->dyn_state
.max_clock_voltage_on_dc
);
4711 if (PP_PowerSource_DC
== hwmgr
->power_source
) {
4712 for (i
= 0; i
< tonga_ps
->performance_level_count
; i
++) {
4713 if (tonga_ps
->performance_levels
[i
].memory_clock
> max_limits
->mclk
)
4714 tonga_ps
->performance_levels
[i
].memory_clock
= max_limits
->mclk
;
4715 if (tonga_ps
->performance_levels
[i
].engine_clock
> max_limits
->sclk
)
4716 tonga_ps
->performance_levels
[i
].engine_clock
= max_limits
->sclk
;
4720 tonga_ps
->vce_clocks
.EVCLK
= hwmgr
->vce_arbiter
.evclk
;
4721 tonga_ps
->vce_clocks
.ECCLK
= hwmgr
->vce_arbiter
.ecclk
;
4723 tonga_ps
->acp_clk
= hwmgr
->acp_arbiter
.acpclk
;
4725 cgs_get_active_displays_info(hwmgr
->device
, &info
);
4727 /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
4729 /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
4731 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
)) {
4733 max_limits
= &(hwmgr
->dyn_state
.max_clock_voltage_on_ac
);
4734 stable_pstate_sclk
= (max_limits
->sclk
* 75) / 100;
4736 for (count
= pptable_info
->vdd_dep_on_sclk
->count
-1; count
>= 0; count
--) {
4737 if (stable_pstate_sclk
>= pptable_info
->vdd_dep_on_sclk
->entries
[count
].clk
) {
4738 stable_pstate_sclk
= pptable_info
->vdd_dep_on_sclk
->entries
[count
].clk
;
4744 stable_pstate_sclk
= pptable_info
->vdd_dep_on_sclk
->entries
[0].clk
;
4746 stable_pstate_mclk
= max_limits
->mclk
;
4748 minimum_clocks
.engineClock
= stable_pstate_sclk
;
4749 minimum_clocks
.memoryClock
= stable_pstate_mclk
;
4752 if (minimum_clocks
.engineClock
< hwmgr
->gfx_arbiter
.sclk
)
4753 minimum_clocks
.engineClock
= hwmgr
->gfx_arbiter
.sclk
;
4755 if (minimum_clocks
.memoryClock
< hwmgr
->gfx_arbiter
.mclk
)
4756 minimum_clocks
.memoryClock
= hwmgr
->gfx_arbiter
.mclk
;
4758 tonga_ps
->sclk_threshold
= hwmgr
->gfx_arbiter
.sclk_threshold
;
4760 if (0 != hwmgr
->gfx_arbiter
.sclk_over_drive
) {
4761 PP_ASSERT_WITH_CODE((hwmgr
->gfx_arbiter
.sclk_over_drive
<= hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
),
4762 "Overdrive sclk exceeds limit",
4763 hwmgr
->gfx_arbiter
.sclk_over_drive
= hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
);
4765 if (hwmgr
->gfx_arbiter
.sclk_over_drive
>= hwmgr
->gfx_arbiter
.sclk
)
4766 tonga_ps
->performance_levels
[1].engine_clock
= hwmgr
->gfx_arbiter
.sclk_over_drive
;
4769 if (0 != hwmgr
->gfx_arbiter
.mclk_over_drive
) {
4770 PP_ASSERT_WITH_CODE((hwmgr
->gfx_arbiter
.mclk_over_drive
<= hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
),
4771 "Overdrive mclk exceeds limit",
4772 hwmgr
->gfx_arbiter
.mclk_over_drive
= hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
);
4774 if (hwmgr
->gfx_arbiter
.mclk_over_drive
>= hwmgr
->gfx_arbiter
.mclk
)
4775 tonga_ps
->performance_levels
[1].memory_clock
= hwmgr
->gfx_arbiter
.mclk_over_drive
;
4778 disable_mclk_switching_for_frame_lock
= phm_cap_enabled(
4779 hwmgr
->platform_descriptor
.platformCaps
,
4780 PHM_PlatformCaps_DisableMclkSwitchingForFrameLock
);
4782 disable_mclk_switching
= (1 < info
.display_count
) ||
4783 disable_mclk_switching_for_frame_lock
;
4785 sclk
= tonga_ps
->performance_levels
[0].engine_clock
;
4786 mclk
= tonga_ps
->performance_levels
[0].memory_clock
;
4788 if (disable_mclk_switching
)
4789 mclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
- 1].memory_clock
;
4791 if (sclk
< minimum_clocks
.engineClock
)
4792 sclk
= (minimum_clocks
.engineClock
> max_limits
->sclk
) ? max_limits
->sclk
: minimum_clocks
.engineClock
;
4794 if (mclk
< minimum_clocks
.memoryClock
)
4795 mclk
= (minimum_clocks
.memoryClock
> max_limits
->mclk
) ? max_limits
->mclk
: minimum_clocks
.memoryClock
;
4797 tonga_ps
->performance_levels
[0].engine_clock
= sclk
;
4798 tonga_ps
->performance_levels
[0].memory_clock
= mclk
;
4800 tonga_ps
->performance_levels
[1].engine_clock
=
4801 (tonga_ps
->performance_levels
[1].engine_clock
>= tonga_ps
->performance_levels
[0].engine_clock
) ?
4802 tonga_ps
->performance_levels
[1].engine_clock
:
4803 tonga_ps
->performance_levels
[0].engine_clock
;
4805 if (disable_mclk_switching
) {
4806 if (mclk
< tonga_ps
->performance_levels
[1].memory_clock
)
4807 mclk
= tonga_ps
->performance_levels
[1].memory_clock
;
4809 tonga_ps
->performance_levels
[0].memory_clock
= mclk
;
4810 tonga_ps
->performance_levels
[1].memory_clock
= mclk
;
4812 if (tonga_ps
->performance_levels
[1].memory_clock
< tonga_ps
->performance_levels
[0].memory_clock
)
4813 tonga_ps
->performance_levels
[1].memory_clock
= tonga_ps
->performance_levels
[0].memory_clock
;
4816 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
)) {
4817 for (i
=0; i
< tonga_ps
->performance_level_count
; i
++) {
4818 tonga_ps
->performance_levels
[i
].engine_clock
= stable_pstate_sclk
;
4819 tonga_ps
->performance_levels
[i
].memory_clock
= stable_pstate_mclk
;
4820 tonga_ps
->performance_levels
[i
].pcie_gen
= data
->pcie_gen_performance
.max
;
4821 tonga_ps
->performance_levels
[i
].pcie_lane
= data
->pcie_gen_performance
.max
;
4828 int tonga_get_power_state_size(struct pp_hwmgr
*hwmgr
)
4830 return sizeof(struct tonga_power_state
);
4833 static int tonga_dpm_get_mclk(struct pp_hwmgr
*hwmgr
, bool low
)
4835 struct pp_power_state
*ps
;
4836 struct tonga_power_state
*tonga_ps
;
4841 ps
= hwmgr
->request_ps
;
4846 tonga_ps
= cast_phw_tonga_power_state(&ps
->hardware
);
4849 return tonga_ps
->performance_levels
[0].memory_clock
;
4851 return tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].memory_clock
;
4854 static int tonga_dpm_get_sclk(struct pp_hwmgr
*hwmgr
, bool low
)
4856 struct pp_power_state
*ps
;
4857 struct tonga_power_state
*tonga_ps
;
4862 ps
= hwmgr
->request_ps
;
4867 tonga_ps
= cast_phw_tonga_power_state(&ps
->hardware
);
4870 return tonga_ps
->performance_levels
[0].engine_clock
;
4872 return tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].engine_clock
;
4875 static uint16_t tonga_get_current_pcie_speed(
4876 struct pp_hwmgr
*hwmgr
)
4878 uint32_t speed_cntl
= 0;
4880 speed_cntl
= cgs_read_ind_register(hwmgr
->device
,
4882 ixPCIE_LC_SPEED_CNTL
);
4883 return((uint16_t)PHM_GET_FIELD(speed_cntl
,
4884 PCIE_LC_SPEED_CNTL
, LC_CURRENT_DATA_RATE
));
4887 static int tonga_get_current_pcie_lane_number(
4888 struct pp_hwmgr
*hwmgr
)
4890 uint32_t link_width
;
4892 link_width
= PHM_READ_INDIRECT_FIELD(hwmgr
->device
,
4894 PCIE_LC_LINK_WIDTH_CNTL
,
4897 PP_ASSERT_WITH_CODE((7 >= link_width
),
4898 "Invalid PCIe lane width!", return 0);
4900 return decode_pcie_lane_width(link_width
);
4903 static int tonga_dpm_patch_boot_state(struct pp_hwmgr
*hwmgr
,
4904 struct pp_hw_power_state
*hw_ps
)
4906 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4907 struct tonga_power_state
*ps
= (struct tonga_power_state
*)hw_ps
;
4908 ATOM_FIRMWARE_INFO_V2_2
*fw_info
;
4911 int index
= GetIndexIntoMasterTable(DATA
, FirmwareInfo
);
4913 /* First retrieve the Boot clocks and VDDC from the firmware info table.
4914 * We assume here that fw_info is unchanged if this call fails.
4916 fw_info
= (ATOM_FIRMWARE_INFO_V2_2
*)cgs_atom_get_data_table(
4917 hwmgr
->device
, index
,
4918 &size
, &frev
, &crev
);
4920 /* During a test, there is no firmware info table. */
4923 /* Patch the state. */
4924 data
->vbios_boot_state
.sclk_bootup_value
= le32_to_cpu(fw_info
->ulDefaultEngineClock
);
4925 data
->vbios_boot_state
.mclk_bootup_value
= le32_to_cpu(fw_info
->ulDefaultMemoryClock
);
4926 data
->vbios_boot_state
.mvdd_bootup_value
= le16_to_cpu(fw_info
->usBootUpMVDDCVoltage
);
4927 data
->vbios_boot_state
.vddc_bootup_value
= le16_to_cpu(fw_info
->usBootUpVDDCVoltage
);
4928 data
->vbios_boot_state
.vddci_bootup_value
= le16_to_cpu(fw_info
->usBootUpVDDCIVoltage
);
4929 data
->vbios_boot_state
.pcie_gen_bootup_value
= tonga_get_current_pcie_speed(hwmgr
);
4930 data
->vbios_boot_state
.pcie_lane_bootup_value
=
4931 (uint16_t)tonga_get_current_pcie_lane_number(hwmgr
);
4933 /* set boot power state */
4934 ps
->performance_levels
[0].memory_clock
= data
->vbios_boot_state
.mclk_bootup_value
;
4935 ps
->performance_levels
[0].engine_clock
= data
->vbios_boot_state
.sclk_bootup_value
;
4936 ps
->performance_levels
[0].pcie_gen
= data
->vbios_boot_state
.pcie_gen_bootup_value
;
4937 ps
->performance_levels
[0].pcie_lane
= data
->vbios_boot_state
.pcie_lane_bootup_value
;
4942 static int tonga_get_pp_table_entry_callback_func(struct pp_hwmgr
*hwmgr
,
4943 void *state
, struct pp_power_state
*power_state
,
4944 void *pp_table
, uint32_t classification_flag
)
4946 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4948 struct tonga_power_state
*tonga_ps
=
4949 (struct tonga_power_state
*)(&(power_state
->hardware
));
4951 struct tonga_performance_level
*performance_level
;
4953 ATOM_Tonga_State
*state_entry
= (ATOM_Tonga_State
*)state
;
4955 ATOM_Tonga_POWERPLAYTABLE
*powerplay_table
=
4956 (ATOM_Tonga_POWERPLAYTABLE
*)pp_table
;
4958 ATOM_Tonga_SCLK_Dependency_Table
*sclk_dep_table
=
4959 (ATOM_Tonga_SCLK_Dependency_Table
*)
4960 (((unsigned long)powerplay_table
) +
4961 le16_to_cpu(powerplay_table
->usSclkDependencyTableOffset
));
4963 ATOM_Tonga_MCLK_Dependency_Table
*mclk_dep_table
=
4964 (ATOM_Tonga_MCLK_Dependency_Table
*)
4965 (((unsigned long)powerplay_table
) +
4966 le16_to_cpu(powerplay_table
->usMclkDependencyTableOffset
));
4968 /* The following fields are not initialized here: id orderedList allStatesList */
4969 power_state
->classification
.ui_label
=
4970 (le16_to_cpu(state_entry
->usClassification
) &
4971 ATOM_PPLIB_CLASSIFICATION_UI_MASK
) >>
4972 ATOM_PPLIB_CLASSIFICATION_UI_SHIFT
;
4973 power_state
->classification
.flags
= classification_flag
;
4974 /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
4976 power_state
->classification
.temporary_state
= false;
4977 power_state
->classification
.to_be_deleted
= false;
4979 power_state
->validation
.disallowOnDC
=
4980 (0 != (le32_to_cpu(state_entry
->ulCapsAndSettings
) & ATOM_Tonga_DISALLOW_ON_DC
));
4982 power_state
->pcie
.lanes
= 0;
4984 power_state
->display
.disableFrameModulation
= false;
4985 power_state
->display
.limitRefreshrate
= false;
4986 power_state
->display
.enableVariBright
=
4987 (0 != (le32_to_cpu(state_entry
->ulCapsAndSettings
) & ATOM_Tonga_ENABLE_VARIBRIGHT
));
4989 power_state
->validation
.supportedPowerLevels
= 0;
4990 power_state
->uvd_clocks
.VCLK
= 0;
4991 power_state
->uvd_clocks
.DCLK
= 0;
4992 power_state
->temperatures
.min
= 0;
4993 power_state
->temperatures
.max
= 0;
4995 performance_level
= &(tonga_ps
->performance_levels
4996 [tonga_ps
->performance_level_count
++]);
4998 PP_ASSERT_WITH_CODE(
4999 (tonga_ps
->performance_level_count
< SMU72_MAX_LEVELS_GRAPHICS
),
5000 "Performance levels exceeds SMC limit!",
5003 PP_ASSERT_WITH_CODE(
5004 (tonga_ps
->performance_level_count
<=
5005 hwmgr
->platform_descriptor
.hardwareActivityPerformanceLevels
),
5006 "Performance levels exceeds Driver limit!",
5009 /* Performance levels are arranged from low to high. */
5010 performance_level
->memory_clock
=
5011 le32_to_cpu(mclk_dep_table
->entries
[state_entry
->ucMemoryClockIndexLow
].ulMclk
);
5013 performance_level
->engine_clock
=
5014 le32_to_cpu(sclk_dep_table
->entries
[state_entry
->ucEngineClockIndexLow
].ulSclk
);
5016 performance_level
->pcie_gen
= get_pcie_gen_support(
5018 state_entry
->ucPCIEGenLow
);
5020 performance_level
->pcie_lane
= get_pcie_lane_support(
5021 data
->pcie_lane_cap
,
5022 state_entry
->ucPCIELaneHigh
);
5025 &(tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
++]);
5027 performance_level
->memory_clock
=
5028 le32_to_cpu(mclk_dep_table
->entries
[state_entry
->ucMemoryClockIndexHigh
].ulMclk
);
5030 performance_level
->engine_clock
=
5031 le32_to_cpu(sclk_dep_table
->entries
[state_entry
->ucEngineClockIndexHigh
].ulSclk
);
5033 performance_level
->pcie_gen
= get_pcie_gen_support(
5035 state_entry
->ucPCIEGenHigh
);
5037 performance_level
->pcie_lane
= get_pcie_lane_support(
5038 data
->pcie_lane_cap
,
5039 state_entry
->ucPCIELaneHigh
);
5044 static int tonga_get_pp_table_entry(struct pp_hwmgr
*hwmgr
,
5045 unsigned long entry_index
, struct pp_power_state
*ps
)
5048 struct tonga_power_state
*tonga_ps
;
5049 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5051 struct phm_ppt_v1_information
*table_info
=
5052 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
5054 struct phm_ppt_v1_clock_voltage_dependency_table
*dep_mclk_table
=
5055 table_info
->vdd_dep_on_mclk
;
5057 ps
->hardware
.magic
= PhwTonga_Magic
;
5059 tonga_ps
= cast_phw_tonga_power_state(&(ps
->hardware
));
5061 result
= tonga_get_powerplay_table_entry(hwmgr
, entry_index
, ps
,
5062 tonga_get_pp_table_entry_callback_func
);
5064 /* This is the earliest time we have all the dependency table and the VBIOS boot state
5065 * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
5066 * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
5068 if (dep_mclk_table
!= NULL
&& dep_mclk_table
->count
== 1) {
5069 if (dep_mclk_table
->entries
[0].clk
!=
5070 data
->vbios_boot_state
.mclk_bootup_value
)
5071 printk(KERN_ERR
"Single MCLK entry VDDCI/MCLK dependency table "
5072 "does not match VBIOS boot MCLK level");
5073 if (dep_mclk_table
->entries
[0].vddci
!=
5074 data
->vbios_boot_state
.vddci_bootup_value
)
5075 printk(KERN_ERR
"Single VDDCI entry VDDCI/MCLK dependency table "
5076 "does not match VBIOS boot VDDCI level");
5079 /* set DC compatible flag if this state supports DC */
5080 if (!ps
->validation
.disallowOnDC
)
5081 tonga_ps
->dc_compatible
= true;
5083 if (ps
->classification
.flags
& PP_StateClassificationFlag_ACPI
)
5084 data
->acpi_pcie_gen
= tonga_ps
->performance_levels
[0].pcie_gen
;
5085 else if (ps
->classification
.flags
& PP_StateClassificationFlag_Boot
) {
5086 if (data
->bacos
.best_match
== 0xffff) {
5087 /* For V.I. use boot state as base BACO state */
5088 data
->bacos
.best_match
= PP_StateClassificationFlag_Boot
;
5089 data
->bacos
.performance_level
= tonga_ps
->performance_levels
[0];
5093 tonga_ps
->uvd_clocks
.VCLK
= ps
->uvd_clocks
.VCLK
;
5094 tonga_ps
->uvd_clocks
.DCLK
= ps
->uvd_clocks
.DCLK
;
5099 switch (ps
->classification
.ui_label
) {
5100 case PP_StateUILabel_Performance
:
5101 data
->use_pcie_performance_levels
= true;
5103 for (i
= 0; i
< tonga_ps
->performance_level_count
; i
++) {
5104 if (data
->pcie_gen_performance
.max
<
5105 tonga_ps
->performance_levels
[i
].pcie_gen
)
5106 data
->pcie_gen_performance
.max
=
5107 tonga_ps
->performance_levels
[i
].pcie_gen
;
5109 if (data
->pcie_gen_performance
.min
>
5110 tonga_ps
->performance_levels
[i
].pcie_gen
)
5111 data
->pcie_gen_performance
.min
=
5112 tonga_ps
->performance_levels
[i
].pcie_gen
;
5114 if (data
->pcie_lane_performance
.max
<
5115 tonga_ps
->performance_levels
[i
].pcie_lane
)
5116 data
->pcie_lane_performance
.max
=
5117 tonga_ps
->performance_levels
[i
].pcie_lane
;
5119 if (data
->pcie_lane_performance
.min
>
5120 tonga_ps
->performance_levels
[i
].pcie_lane
)
5121 data
->pcie_lane_performance
.min
=
5122 tonga_ps
->performance_levels
[i
].pcie_lane
;
5125 case PP_StateUILabel_Battery
:
5126 data
->use_pcie_power_saving_levels
= true;
5128 for (i
= 0; i
< tonga_ps
->performance_level_count
; i
++) {
5129 if (data
->pcie_gen_power_saving
.max
<
5130 tonga_ps
->performance_levels
[i
].pcie_gen
)
5131 data
->pcie_gen_power_saving
.max
=
5132 tonga_ps
->performance_levels
[i
].pcie_gen
;
5134 if (data
->pcie_gen_power_saving
.min
>
5135 tonga_ps
->performance_levels
[i
].pcie_gen
)
5136 data
->pcie_gen_power_saving
.min
=
5137 tonga_ps
->performance_levels
[i
].pcie_gen
;
5139 if (data
->pcie_lane_power_saving
.max
<
5140 tonga_ps
->performance_levels
[i
].pcie_lane
)
5141 data
->pcie_lane_power_saving
.max
=
5142 tonga_ps
->performance_levels
[i
].pcie_lane
;
5144 if (data
->pcie_lane_power_saving
.min
>
5145 tonga_ps
->performance_levels
[i
].pcie_lane
)
5146 data
->pcie_lane_power_saving
.min
=
5147 tonga_ps
->performance_levels
[i
].pcie_lane
;
5158 tonga_print_current_perforce_level(struct pp_hwmgr
*hwmgr
, struct seq_file
*m
)
5160 uint32_t sclk
, mclk
, activity_percent
;
5162 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5164 smum_send_msg_to_smc(hwmgr
->smumgr
, (PPSMC_Msg
)(PPSMC_MSG_API_GetSclkFrequency
));
5166 sclk
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5168 smum_send_msg_to_smc(hwmgr
->smumgr
, (PPSMC_Msg
)(PPSMC_MSG_API_GetMclkFrequency
));
5170 mclk
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5171 seq_printf(m
, "\n [ mclk ]: %u MHz\n\n [ sclk ]: %u MHz\n", mclk
/100, sclk
/100);
5174 offset
= data
->soft_regs_start
+ offsetof(SMU72_SoftRegisters
, AverageGraphicsActivity
);
5175 activity_percent
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, offset
);
5176 activity_percent
+= 0x80;
5177 activity_percent
>>= 8;
5179 seq_printf(m
, "\n [GPU load]: %u%%\n\n", activity_percent
> 100 ? 100 : activity_percent
);
5183 static int tonga_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr
*hwmgr
, const void *input
)
5185 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5186 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5187 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5188 struct tonga_single_dpm_table
*psclk_table
= &(data
->dpm_table
.sclk_table
);
5189 uint32_t sclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].engine_clock
;
5190 struct tonga_single_dpm_table
*pmclk_table
= &(data
->dpm_table
.mclk_table
);
5191 uint32_t mclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].memory_clock
;
5192 struct PP_Clocks min_clocks
= {0};
5194 struct cgs_display_info info
= {0};
5196 data
->need_update_smu7_dpm_table
= 0;
5198 for (i
= 0; i
< psclk_table
->count
; i
++) {
5199 if (sclk
== psclk_table
->dpm_levels
[i
].value
)
5203 if (i
>= psclk_table
->count
)
5204 data
->need_update_smu7_dpm_table
|= DPMTABLE_OD_UPDATE_SCLK
;
5206 /* TODO: Check SCLK in DAL's minimum clocks in case DeepSleep divider update is required.*/
5207 if(data
->display_timing
.min_clock_insr
!= min_clocks
.engineClockInSR
)
5208 data
->need_update_smu7_dpm_table
|= DPMTABLE_UPDATE_SCLK
;
5211 for (i
=0; i
< pmclk_table
->count
; i
++) {
5212 if (mclk
== pmclk_table
->dpm_levels
[i
].value
)
5216 if (i
>= pmclk_table
->count
)
5217 data
->need_update_smu7_dpm_table
|= DPMTABLE_OD_UPDATE_MCLK
;
5219 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5221 if (data
->display_timing
.num_existing_displays
!= info
.display_count
)
5222 data
->need_update_smu7_dpm_table
|= DPMTABLE_UPDATE_MCLK
;
5227 static uint16_t tonga_get_maximum_link_speed(struct pp_hwmgr
*hwmgr
, const struct tonga_power_state
*hw_ps
)
5230 uint32_t sclk
, max_sclk
= 0;
5231 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5232 struct tonga_dpm_table
*pdpm_table
= &data
->dpm_table
;
5234 for (i
= 0; i
< hw_ps
->performance_level_count
; i
++) {
5235 sclk
= hw_ps
->performance_levels
[i
].engine_clock
;
5236 if (max_sclk
< sclk
)
5240 for (i
= 0; i
< pdpm_table
->sclk_table
.count
; i
++) {
5241 if (pdpm_table
->sclk_table
.dpm_levels
[i
].value
== max_sclk
)
5242 return (uint16_t) ((i
>= pdpm_table
->pcie_speed_table
.count
) ?
5243 pdpm_table
->pcie_speed_table
.dpm_levels
[pdpm_table
->pcie_speed_table
.count
-1].value
:
5244 pdpm_table
->pcie_speed_table
.dpm_levels
[i
].value
);
5250 static int tonga_request_link_speed_change_before_state_change(struct pp_hwmgr
*hwmgr
, const void *input
)
5252 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5253 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5254 const struct tonga_power_state
*tonga_nps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5255 const struct tonga_power_state
*tonga_cps
= cast_const_phw_tonga_power_state(states
->pcurrent_state
);
5257 uint16_t target_link_speed
= tonga_get_maximum_link_speed(hwmgr
, tonga_nps
);
5258 uint16_t current_link_speed
;
5260 if (data
->force_pcie_gen
== PP_PCIEGenInvalid
)
5261 current_link_speed
= tonga_get_maximum_link_speed(hwmgr
, tonga_cps
);
5263 current_link_speed
= data
->force_pcie_gen
;
5265 data
->force_pcie_gen
= PP_PCIEGenInvalid
;
5266 data
->pspp_notify_required
= false;
5267 if (target_link_speed
> current_link_speed
) {
5268 switch(target_link_speed
) {
5270 if (0 == acpi_pcie_perf_request(hwmgr
->device
, PCIE_PERF_REQ_GEN3
, false))
5272 data
->force_pcie_gen
= PP_PCIEGen2
;
5273 if (current_link_speed
== PP_PCIEGen2
)
5276 if (0 == acpi_pcie_perf_request(hwmgr
->device
, PCIE_PERF_REQ_GEN2
, false))
5279 data
->force_pcie_gen
= tonga_get_current_pcie_speed(hwmgr
);
5283 if (target_link_speed
< current_link_speed
)
5284 data
->pspp_notify_required
= true;
5290 static int tonga_freeze_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
5292 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5294 if (0 == data
->need_update_smu7_dpm_table
)
5297 if ((0 == data
->sclk_dpm_key_disabled
) &&
5298 (data
->need_update_smu7_dpm_table
&
5299 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
))) {
5300 PP_ASSERT_WITH_CODE(
5301 true == tonga_is_dpm_running(hwmgr
),
5302 "Trying to freeze SCLK DPM when DPM is disabled",
5304 PP_ASSERT_WITH_CODE(
5305 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5306 PPSMC_MSG_SCLKDPM_FreezeLevel
),
5307 "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
5311 if ((0 == data
->mclk_dpm_key_disabled
) &&
5312 (data
->need_update_smu7_dpm_table
&
5313 DPMTABLE_OD_UPDATE_MCLK
)) {
5314 PP_ASSERT_WITH_CODE(true == tonga_is_dpm_running(hwmgr
),
5315 "Trying to freeze MCLK DPM when DPM is disabled",
5317 PP_ASSERT_WITH_CODE(
5318 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5319 PPSMC_MSG_MCLKDPM_FreezeLevel
),
5320 "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
5327 static int tonga_populate_and_upload_sclk_mclk_dpm_levels(struct pp_hwmgr
*hwmgr
, const void *input
)
5331 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5332 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5333 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5334 uint32_t sclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].engine_clock
;
5335 uint32_t mclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].memory_clock
;
5336 struct tonga_dpm_table
*pdpm_table
= &data
->dpm_table
;
5338 struct tonga_dpm_table
*pgolden_dpm_table
= &data
->golden_dpm_table
;
5339 uint32_t dpm_count
, clock_percent
;
5342 if (0 == data
->need_update_smu7_dpm_table
)
5345 if (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_SCLK
) {
5346 pdpm_table
->sclk_table
.dpm_levels
[pdpm_table
->sclk_table
.count
-1].value
= sclk
;
5348 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinACSupport
) ||
5349 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinDCSupport
)) {
5350 /* Need to do calculation based on the golden DPM table
5351 * as the Heatmap GPU Clock axis is also based on the default values
5353 PP_ASSERT_WITH_CODE(
5354 (pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
!= 0),
5357 dpm_count
= pdpm_table
->sclk_table
.count
< 2 ? 0 : pdpm_table
->sclk_table
.count
-2;
5358 for (i
= dpm_count
; i
> 1; i
--) {
5359 if (sclk
> pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
) {
5360 clock_percent
= ((sclk
- pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
)*100) /
5361 pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
;
5363 pdpm_table
->sclk_table
.dpm_levels
[i
].value
=
5364 pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
+
5365 (pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5367 } else if (pgolden_dpm_table
->sclk_table
.dpm_levels
[pdpm_table
->sclk_table
.count
-1].value
> sclk
) {
5368 clock_percent
= ((pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
- sclk
)*100) /
5369 pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
;
5371 pdpm_table
->sclk_table
.dpm_levels
[i
].value
=
5372 pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
-
5373 (pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5375 pdpm_table
->sclk_table
.dpm_levels
[i
].value
=
5376 pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
;
5381 if (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
) {
5382 pdpm_table
->mclk_table
.dpm_levels
[pdpm_table
->mclk_table
.count
-1].value
= mclk
;
5384 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinACSupport
) ||
5385 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinDCSupport
)) {
5387 PP_ASSERT_WITH_CODE(
5388 (pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
!= 0),
5391 dpm_count
= pdpm_table
->mclk_table
.count
< 2? 0 : pdpm_table
->mclk_table
.count
-2;
5392 for (i
= dpm_count
; i
> 1; i
--) {
5393 if (mclk
> pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
) {
5394 clock_percent
= ((mclk
- pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
)*100) /
5395 pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
;
5397 pdpm_table
->mclk_table
.dpm_levels
[i
].value
=
5398 pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
+
5399 (pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5401 } else if (pgolden_dpm_table
->mclk_table
.dpm_levels
[pdpm_table
->mclk_table
.count
-1].value
> mclk
) {
5402 clock_percent
= ((pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
- mclk
)*100) /
5403 pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
;
5405 pdpm_table
->mclk_table
.dpm_levels
[i
].value
=
5406 pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
-
5407 (pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5409 pdpm_table
->mclk_table
.dpm_levels
[i
].value
= pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
;
5414 if (data
->need_update_smu7_dpm_table
& (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
)) {
5415 result
= tonga_populate_all_memory_levels(hwmgr
);
5416 PP_ASSERT_WITH_CODE((0 == result
),
5417 "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
5421 if (data
->need_update_smu7_dpm_table
& (DPMTABLE_OD_UPDATE_MCLK
+ DPMTABLE_UPDATE_MCLK
)) {
5422 /*populate MCLK dpm table to SMU7 */
5423 result
= tonga_populate_all_memory_levels(hwmgr
);
5424 PP_ASSERT_WITH_CODE((0 == result
),
5425 "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
5432 static int tonga_trim_single_dpm_states(struct pp_hwmgr
*hwmgr
,
5433 struct tonga_single_dpm_table
* pdpm_table
,
5434 uint32_t low_limit
, uint32_t high_limit
)
5438 for (i
= 0; i
< pdpm_table
->count
; i
++) {
5439 if ((pdpm_table
->dpm_levels
[i
].value
< low_limit
) ||
5440 (pdpm_table
->dpm_levels
[i
].value
> high_limit
))
5441 pdpm_table
->dpm_levels
[i
].enabled
= false;
5443 pdpm_table
->dpm_levels
[i
].enabled
= true;
5448 static int tonga_trim_dpm_states(struct pp_hwmgr
*hwmgr
, const struct tonga_power_state
*hw_state
)
5451 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5452 uint32_t high_limit_count
;
5454 PP_ASSERT_WITH_CODE((hw_state
->performance_level_count
>= 1),
5455 "power state did not have any performance level",
5458 high_limit_count
= (1 == hw_state
->performance_level_count
) ? 0: 1;
5460 tonga_trim_single_dpm_states(hwmgr
,
5461 &(data
->dpm_table
.sclk_table
),
5462 hw_state
->performance_levels
[0].engine_clock
,
5463 hw_state
->performance_levels
[high_limit_count
].engine_clock
);
5465 tonga_trim_single_dpm_states(hwmgr
,
5466 &(data
->dpm_table
.mclk_table
),
5467 hw_state
->performance_levels
[0].memory_clock
,
5468 hw_state
->performance_levels
[high_limit_count
].memory_clock
);
5473 static int tonga_generate_dpm_level_enable_mask(struct pp_hwmgr
*hwmgr
, const void *input
)
5476 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5477 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5478 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5480 result
= tonga_trim_dpm_states(hwmgr
, tonga_ps
);
5484 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&data
->dpm_table
.sclk_table
);
5485 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&data
->dpm_table
.mclk_table
);
5486 data
->last_mclk_dpm_enable_mask
= data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
;
5487 if (data
->uvd_enabled
)
5488 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
&= 0xFFFFFFFE;
5490 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&data
->dpm_table
.pcie_speed_table
);
5495 int tonga_enable_disable_vce_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
5497 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
5498 (PPSMC_Msg
)PPSMC_MSG_VCEDPM_Enable
:
5499 (PPSMC_Msg
)PPSMC_MSG_VCEDPM_Disable
);
5502 int tonga_enable_disable_uvd_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
5504 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
5505 (PPSMC_Msg
)PPSMC_MSG_UVDDPM_Enable
:
5506 (PPSMC_Msg
)PPSMC_MSG_UVDDPM_Disable
);
5509 int tonga_update_uvd_dpm(struct pp_hwmgr
*hwmgr
, bool bgate
)
5511 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5512 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
5513 struct phm_ppt_v1_information
*ptable_information
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
5516 data
->smc_state_table
.UvdBootLevel
= (uint8_t) (ptable_information
->mm_dep_table
->count
- 1);
5517 mm_boot_level_offset
= data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
, UvdBootLevel
);
5518 mm_boot_level_offset
/= 4;
5519 mm_boot_level_offset
*= 4;
5520 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
);
5521 mm_boot_level_value
&= 0x00FFFFFF;
5522 mm_boot_level_value
|= data
->smc_state_table
.UvdBootLevel
<< 24;
5523 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
5525 if (!phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_UVDDPM
) ||
5526 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
))
5527 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5528 PPSMC_MSG_UVDDPM_SetEnabledMask
,
5529 (uint32_t)(1 << data
->smc_state_table
.UvdBootLevel
));
5532 return tonga_enable_disable_uvd_dpm(hwmgr
, !bgate
);
5535 int tonga_update_vce_dpm(struct pp_hwmgr
*hwmgr
, const void *input
)
5537 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5538 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5539 const struct tonga_power_state
*tonga_nps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5540 const struct tonga_power_state
*tonga_cps
= cast_const_phw_tonga_power_state(states
->pcurrent_state
);
5542 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
5543 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
5545 if (tonga_nps
->vce_clocks
.EVCLK
> 0 && (tonga_cps
== NULL
|| tonga_cps
->vce_clocks
.EVCLK
== 0)) {
5546 data
->smc_state_table
.VceBootLevel
= (uint8_t) (pptable_info
->mm_dep_table
->count
- 1);
5548 mm_boot_level_offset
= data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
, VceBootLevel
);
5549 mm_boot_level_offset
/= 4;
5550 mm_boot_level_offset
*= 4;
5551 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
);
5552 mm_boot_level_value
&= 0xFF00FFFF;
5553 mm_boot_level_value
|= data
->smc_state_table
.VceBootLevel
<< 16;
5554 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
5556 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
))
5557 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5558 PPSMC_MSG_VCEDPM_SetEnabledMask
,
5559 (uint32_t)(1 << data
->smc_state_table
.VceBootLevel
));
5561 tonga_enable_disable_vce_dpm(hwmgr
, true);
5562 } else if (tonga_nps
->vce_clocks
.EVCLK
== 0 && tonga_cps
!= NULL
&& tonga_cps
->vce_clocks
.EVCLK
> 0)
5563 tonga_enable_disable_vce_dpm(hwmgr
, false);
5568 static int tonga_update_and_upload_mc_reg_table(struct pp_hwmgr
*hwmgr
)
5570 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5575 if (0 == (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
))
5579 memset(&data
->mc_reg_table
, 0, sizeof(SMU72_Discrete_MCRegisters
));
5581 result
= tonga_convert_mc_reg_table_to_smc(hwmgr
, &(data
->mc_reg_table
));
5587 address
= data
->mc_reg_table_start
+ (uint32_t)offsetof(SMU72_Discrete_MCRegisters
, data
[0]);
5589 return tonga_copy_bytes_to_smc(hwmgr
->smumgr
, address
,
5590 (uint8_t *)&data
->mc_reg_table
.data
[0],
5591 sizeof(SMU72_Discrete_MCRegisterSet
) * data
->dpm_table
.mclk_table
.count
,
5595 static int tonga_program_memory_timing_parameters_conditionally(struct pp_hwmgr
*hwmgr
)
5597 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5599 if (data
->need_update_smu7_dpm_table
&
5600 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_OD_UPDATE_MCLK
))
5601 return tonga_program_memory_timing_parameters(hwmgr
);
5606 static int tonga_unfreeze_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
5608 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5610 if (0 == data
->need_update_smu7_dpm_table
)
5613 if ((0 == data
->sclk_dpm_key_disabled
) &&
5614 (data
->need_update_smu7_dpm_table
&
5615 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
))) {
5617 PP_ASSERT_WITH_CODE(true == tonga_is_dpm_running(hwmgr
),
5618 "Trying to Unfreeze SCLK DPM when DPM is disabled",
5620 PP_ASSERT_WITH_CODE(
5621 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5622 PPSMC_MSG_SCLKDPM_UnfreezeLevel
),
5623 "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
5627 if ((0 == data
->mclk_dpm_key_disabled
) &&
5628 (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
)) {
5630 PP_ASSERT_WITH_CODE(
5631 true == tonga_is_dpm_running(hwmgr
),
5632 "Trying to Unfreeze MCLK DPM when DPM is disabled",
5634 PP_ASSERT_WITH_CODE(
5635 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5636 PPSMC_MSG_SCLKDPM_UnfreezeLevel
),
5637 "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
5641 data
->need_update_smu7_dpm_table
= 0;
5646 static int tonga_notify_link_speed_change_after_state_change(struct pp_hwmgr
*hwmgr
, const void *input
)
5648 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5649 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5650 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5651 uint16_t target_link_speed
= tonga_get_maximum_link_speed(hwmgr
, tonga_ps
);
5654 if (data
->pspp_notify_required
||
5655 data
->pcie_performance_request
) {
5656 if (target_link_speed
== PP_PCIEGen3
)
5657 request
= PCIE_PERF_REQ_GEN3
;
5658 else if (target_link_speed
== PP_PCIEGen2
)
5659 request
= PCIE_PERF_REQ_GEN2
;
5661 request
= PCIE_PERF_REQ_GEN1
;
5663 if(request
== PCIE_PERF_REQ_GEN1
&& tonga_get_current_pcie_speed(hwmgr
) > 0) {
5664 data
->pcie_performance_request
= false;
5668 if (0 != acpi_pcie_perf_request(hwmgr
->device
, request
, false)) {
5669 if (PP_PCIEGen2
== target_link_speed
)
5670 printk("PSPP request to switch to Gen2 from Gen3 Failed!");
5672 printk("PSPP request to switch to Gen1 from Gen2 Failed!");
5676 data
->pcie_performance_request
= false;
5680 static int tonga_set_power_state_tasks(struct pp_hwmgr
*hwmgr
, const void *input
)
5682 int tmp_result
, result
= 0;
5684 tmp_result
= tonga_find_dpm_states_clocks_in_dpm_table(hwmgr
, input
);
5685 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to find DPM states clocks in DPM table!", result
= tmp_result
);
5687 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_PCIEPerformanceRequest
)) {
5688 tmp_result
= tonga_request_link_speed_change_before_state_change(hwmgr
, input
);
5689 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to request link speed change before state change!", result
= tmp_result
);
5692 tmp_result
= tonga_freeze_sclk_mclk_dpm(hwmgr
);
5693 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to freeze SCLK MCLK DPM!", result
= tmp_result
);
5695 tmp_result
= tonga_populate_and_upload_sclk_mclk_dpm_levels(hwmgr
, input
);
5696 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to populate and upload SCLK MCLK DPM levels!", result
= tmp_result
);
5698 tmp_result
= tonga_generate_dpm_level_enable_mask(hwmgr
, input
);
5699 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to generate DPM level enabled mask!", result
= tmp_result
);
5701 tmp_result
= tonga_update_vce_dpm(hwmgr
, input
);
5702 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to update VCE DPM!", result
= tmp_result
);
5704 tmp_result
= tonga_update_sclk_threshold(hwmgr
);
5705 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to update SCLK threshold!", result
= tmp_result
);
5707 tmp_result
= tonga_update_and_upload_mc_reg_table(hwmgr
);
5708 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to upload MC reg table!", result
= tmp_result
);
5710 tmp_result
= tonga_program_memory_timing_parameters_conditionally(hwmgr
);
5711 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to program memory timing parameters!", result
= tmp_result
);
5713 tmp_result
= tonga_unfreeze_sclk_mclk_dpm(hwmgr
);
5714 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to unfreeze SCLK MCLK DPM!", result
= tmp_result
);
5716 tmp_result
= tonga_upload_dpm_level_enable_mask(hwmgr
);
5717 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to upload DPM level enabled mask!", result
= tmp_result
);
5719 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_PCIEPerformanceRequest
)) {
5720 tmp_result
= tonga_notify_link_speed_change_after_state_change(hwmgr
, input
);
5721 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to notify link speed change after state change!", result
= tmp_result
);
5728 * Set maximum target operating fan output PWM
5730 * @param pHwMgr: the address of the powerplay hardware manager.
5731 * @param usMaxFanPwm: max operating fan PWM in percents
5732 * @return The response that came from the SMC.
5734 static int tonga_set_max_fan_pwm_output(struct pp_hwmgr
*hwmgr
, uint16_t us_max_fan_pwm
)
5736 hwmgr
->thermal_controller
.advanceFanControlParameters
.usMaxFanPWM
= us_max_fan_pwm
;
5738 if (phm_is_hw_access_blocked(hwmgr
))
5741 return (0 == smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
, PPSMC_MSG_SetFanPwmMax
, us_max_fan_pwm
) ? 0 : -1);
5744 int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr
*hwmgr
)
5746 uint32_t num_active_displays
= 0;
5747 struct cgs_display_info info
= {0};
5748 info
.mode_info
= NULL
;
5750 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5752 num_active_displays
= info
.display_count
;
5754 if (num_active_displays
> 1) /* to do && (pHwMgr->pPECI->displayConfiguration.bMultiMonitorInSync != TRUE)) */
5755 tonga_notify_smc_display_change(hwmgr
, false);
5757 tonga_notify_smc_display_change(hwmgr
, true);
5763 * Programs the display gap
5765 * @param hwmgr the address of the powerplay hardware manager.
5768 int tonga_program_display_gap(struct pp_hwmgr
*hwmgr
)
5770 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5771 uint32_t num_active_displays
= 0;
5772 uint32_t display_gap
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
);
5773 uint32_t display_gap2
;
5774 uint32_t pre_vbi_time_in_us
;
5775 uint32_t frame_time_in_us
;
5777 uint32_t refresh_rate
= 0;
5778 struct cgs_display_info info
= {0};
5779 struct cgs_mode_info mode_info
;
5781 info
.mode_info
= &mode_info
;
5783 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5784 num_active_displays
= info
.display_count
;
5786 display_gap
= PHM_SET_FIELD(display_gap
, CG_DISPLAY_GAP_CNTL
, DISP_GAP
, (num_active_displays
> 0)? DISPLAY_GAP_VBLANK_OR_WM
: DISPLAY_GAP_IGNORE
);
5787 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
, display_gap
);
5789 ref_clock
= mode_info
.ref_clock
;
5790 refresh_rate
= mode_info
.refresh_rate
;
5792 if(0 == refresh_rate
)
5795 frame_time_in_us
= 1000000 / refresh_rate
;
5797 pre_vbi_time_in_us
= frame_time_in_us
- 200 - mode_info
.vblank_time_us
;
5798 display_gap2
= pre_vbi_time_in_us
* (ref_clock
/ 100);
5800 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL2
, display_gap2
);
5802 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, data
->soft_regs_start
+ offsetof(SMU72_SoftRegisters
, PreVBlankGap
), 0x64);
5804 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, data
->soft_regs_start
+ offsetof(SMU72_SoftRegisters
, VBlankTimeout
), (frame_time_in_us
- pre_vbi_time_in_us
));
5806 if (num_active_displays
== 1)
5807 tonga_notify_smc_display_change(hwmgr
, true);
5812 int tonga_display_configuration_changed_task(struct pp_hwmgr
*hwmgr
)
5815 tonga_program_display_gap(hwmgr
);
5817 /* to do PhwTonga_CacUpdateDisplayConfiguration(pHwMgr); */
5822 * Set maximum target operating fan output RPM
5824 * @param pHwMgr: the address of the powerplay hardware manager.
5825 * @param usMaxFanRpm: max operating fan RPM value.
5826 * @return The response that came from the SMC.
5828 static int tonga_set_max_fan_rpm_output(struct pp_hwmgr
*hwmgr
, uint16_t us_max_fan_pwm
)
5830 hwmgr
->thermal_controller
.advanceFanControlParameters
.usMaxFanRPM
= us_max_fan_pwm
;
5832 if (phm_is_hw_access_blocked(hwmgr
))
5835 return (0 == smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
, PPSMC_MSG_SetFanRpmMax
, us_max_fan_pwm
) ? 0 : -1);
5838 uint32_t tonga_get_xclk(struct pp_hwmgr
*hwmgr
)
5840 uint32_t reference_clock
;
5844 ATOM_FIRMWARE_INFO
*fw_info
;
5847 int index
= GetIndexIntoMasterTable(DATA
, FirmwareInfo
);
5849 tc
= PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, CG_CLKPIN_CNTL_2
, MUX_TCLK_TO_XCLK
);
5854 fw_info
= (ATOM_FIRMWARE_INFO
*)cgs_atom_get_data_table(hwmgr
->device
, index
,
5855 &size
, &frev
, &crev
);
5860 reference_clock
= le16_to_cpu(fw_info
->usMinPixelClockPLL_Output
);
5862 divide
= PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, CG_CLKPIN_CNTL
, XTALIN_DIVIDE
);
5865 return reference_clock
/ 4;
5867 return reference_clock
;
5870 int tonga_dpm_set_interrupt_state(void *private_data
,
5871 unsigned src_id
, unsigned type
,
5874 uint32_t cg_thermal_int
;
5875 struct pp_hwmgr
*hwmgr
= ((struct pp_eventmgr
*)private_data
)->hwmgr
;
5881 case AMD_THERMAL_IRQ_LOW_TO_HIGH
:
5883 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5884 cg_thermal_int
|= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK
;
5885 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5887 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5888 cg_thermal_int
&= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK
;
5889 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5893 case AMD_THERMAL_IRQ_HIGH_TO_LOW
:
5895 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5896 cg_thermal_int
|= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK
;
5897 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5899 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5900 cg_thermal_int
&= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK
;
5901 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5910 int tonga_register_internal_thermal_interrupt(struct pp_hwmgr
*hwmgr
,
5911 const void *thermal_interrupt_info
)
5914 const struct pp_interrupt_registration_info
*info
=
5915 (const struct pp_interrupt_registration_info
*)thermal_interrupt_info
;
5920 result
= cgs_add_irq_source(hwmgr
->device
, 230, AMD_THERMAL_IRQ_LAST
,
5921 tonga_dpm_set_interrupt_state
,
5922 info
->call_back
, info
->context
);
5927 result
= cgs_add_irq_source(hwmgr
->device
, 231, AMD_THERMAL_IRQ_LAST
,
5928 tonga_dpm_set_interrupt_state
,
5929 info
->call_back
, info
->context
);
5937 bool tonga_check_smc_update_required_for_display_configuration(struct pp_hwmgr
*hwmgr
)
5939 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5940 bool is_update_required
= false;
5941 struct cgs_display_info info
= {0,0,NULL
};
5943 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5945 if (data
->display_timing
.num_existing_displays
!= info
.display_count
)
5946 is_update_required
= true;
5947 /* TO DO NEED TO GET DEEP SLEEP CLOCK FROM DAL
5948 if (phm_cap_enabled(hwmgr->hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
5949 cgs_get_min_clock_settings(hwmgr->device, &min_clocks);
5950 if(min_clocks.engineClockInSR != data->display_timing.minClockInSR)
5951 is_update_required = true;
5953 return is_update_required
;
5956 static inline bool tonga_are_power_levels_equal(const struct tonga_performance_level
*pl1
,
5957 const struct tonga_performance_level
*pl2
)
5959 return ((pl1
->memory_clock
== pl2
->memory_clock
) &&
5960 (pl1
->engine_clock
== pl2
->engine_clock
) &&
5961 (pl1
->pcie_gen
== pl2
->pcie_gen
) &&
5962 (pl1
->pcie_lane
== pl2
->pcie_lane
));
5965 int tonga_check_states_equal(struct pp_hwmgr
*hwmgr
, const struct pp_hw_power_state
*pstate1
, const struct pp_hw_power_state
*pstate2
, bool *equal
)
5967 const struct tonga_power_state
*psa
= cast_const_phw_tonga_power_state(pstate1
);
5968 const struct tonga_power_state
*psb
= cast_const_phw_tonga_power_state(pstate2
);
5971 if (equal
== NULL
|| psa
== NULL
|| psb
== NULL
)
5974 /* If the two states don't even have the same number of performance levels they cannot be the same state. */
5975 if (psa
->performance_level_count
!= psb
->performance_level_count
) {
5980 for (i
= 0; i
< psa
->performance_level_count
; i
++) {
5981 if (!tonga_are_power_levels_equal(&(psa
->performance_levels
[i
]), &(psb
->performance_levels
[i
]))) {
5982 /* If we have found even one performance level pair that is different the states are different. */
5988 /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
5989 *equal
= ((psa
->uvd_clocks
.VCLK
== psb
->uvd_clocks
.VCLK
) && (psa
->uvd_clocks
.DCLK
== psb
->uvd_clocks
.DCLK
));
5990 *equal
&= ((psa
->vce_clocks
.EVCLK
== psb
->vce_clocks
.EVCLK
) && (psa
->vce_clocks
.ECCLK
== psb
->vce_clocks
.ECCLK
));
5991 *equal
&= (psa
->sclk_threshold
== psb
->sclk_threshold
);
5992 *equal
&= (psa
->acp_clk
== psb
->acp_clk
);
5997 static int tonga_set_fan_control_mode(struct pp_hwmgr
*hwmgr
, uint32_t mode
)
6000 /* stop auto-manage */
6001 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
6002 PHM_PlatformCaps_MicrocodeFanControl
))
6003 tonga_fan_ctrl_stop_smc_fan_control(hwmgr
);
6004 tonga_fan_ctrl_set_static_mode(hwmgr
, mode
);
6006 /* restart auto-manage */
6007 tonga_fan_ctrl_reset_fan_speed_to_default(hwmgr
);
6012 static int tonga_get_fan_control_mode(struct pp_hwmgr
*hwmgr
)
6014 if (hwmgr
->fan_ctrl_is_in_default_mode
)
6015 return hwmgr
->fan_ctrl_default_mode
;
6017 return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
6018 CG_FDO_CTRL2
, FDO_PWM_MODE
);
6021 static const struct pp_hwmgr_func tonga_hwmgr_funcs
= {
6022 .backend_init
= &tonga_hwmgr_backend_init
,
6023 .backend_fini
= &tonga_hwmgr_backend_fini
,
6024 .asic_setup
= &tonga_setup_asic_task
,
6025 .dynamic_state_management_enable
= &tonga_enable_dpm_tasks
,
6026 .apply_state_adjust_rules
= tonga_apply_state_adjust_rules
,
6027 .force_dpm_level
= &tonga_force_dpm_level
,
6028 .power_state_set
= tonga_set_power_state_tasks
,
6029 .get_power_state_size
= tonga_get_power_state_size
,
6030 .get_mclk
= tonga_dpm_get_mclk
,
6031 .get_sclk
= tonga_dpm_get_sclk
,
6032 .patch_boot_state
= tonga_dpm_patch_boot_state
,
6033 .get_pp_table_entry
= tonga_get_pp_table_entry
,
6034 .get_num_of_pp_table_entries
= tonga_get_number_of_powerplay_table_entries
,
6035 .print_current_perforce_level
= tonga_print_current_perforce_level
,
6036 .powerdown_uvd
= tonga_phm_powerdown_uvd
,
6037 .powergate_uvd
= tonga_phm_powergate_uvd
,
6038 .powergate_vce
= tonga_phm_powergate_vce
,
6039 .disable_clock_power_gating
= tonga_phm_disable_clock_power_gating
,
6040 .notify_smc_display_config_after_ps_adjustment
= tonga_notify_smc_display_config_after_ps_adjustment
,
6041 .display_config_changed
= tonga_display_configuration_changed_task
,
6042 .set_max_fan_pwm_output
= tonga_set_max_fan_pwm_output
,
6043 .set_max_fan_rpm_output
= tonga_set_max_fan_rpm_output
,
6044 .get_temperature
= tonga_thermal_get_temperature
,
6045 .stop_thermal_controller
= tonga_thermal_stop_thermal_controller
,
6046 .get_fan_speed_info
= tonga_fan_ctrl_get_fan_speed_info
,
6047 .get_fan_speed_percent
= tonga_fan_ctrl_get_fan_speed_percent
,
6048 .set_fan_speed_percent
= tonga_fan_ctrl_set_fan_speed_percent
,
6049 .reset_fan_speed_to_default
= tonga_fan_ctrl_reset_fan_speed_to_default
,
6050 .get_fan_speed_rpm
= tonga_fan_ctrl_get_fan_speed_rpm
,
6051 .set_fan_speed_rpm
= tonga_fan_ctrl_set_fan_speed_rpm
,
6052 .uninitialize_thermal_controller
= tonga_thermal_ctrl_uninitialize_thermal_controller
,
6053 .register_internal_thermal_interrupt
= tonga_register_internal_thermal_interrupt
,
6054 .check_smc_update_required_for_display_configuration
= tonga_check_smc_update_required_for_display_configuration
,
6055 .check_states_equal
= tonga_check_states_equal
,
6056 .set_fan_control_mode
= tonga_set_fan_control_mode
,
6057 .get_fan_control_mode
= tonga_get_fan_control_mode
,
6060 int tonga_hwmgr_init(struct pp_hwmgr
*hwmgr
)
6064 data
= kzalloc (sizeof(tonga_hwmgr
), GFP_KERNEL
);
6067 memset(data
, 0x00, sizeof(tonga_hwmgr
));
6069 hwmgr
->backend
= data
;
6070 hwmgr
->hwmgr_func
= &tonga_hwmgr_funcs
;
6071 hwmgr
->pptable_func
= &tonga_pptable_funcs
;
6072 pp_tonga_thermal_initialize(hwmgr
);