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 "dce/dce_10_0_d.h"
55 #include "dce/dce_10_0_sh_mask.h"
57 #include "cgs_linux.h"
59 #include "amd_pcie_helpers.h"
61 #define MC_CG_ARB_FREQ_F0 0x0a
62 #define MC_CG_ARB_FREQ_F1 0x0b
63 #define MC_CG_ARB_FREQ_F2 0x0c
64 #define MC_CG_ARB_FREQ_F3 0x0d
66 #define MC_CG_SEQ_DRAMCONF_S0 0x05
67 #define MC_CG_SEQ_DRAMCONF_S1 0x06
68 #define MC_CG_SEQ_YCLK_SUSPEND 0x04
69 #define MC_CG_SEQ_YCLK_RESUME 0x0a
71 #define PCIE_BUS_CLK 10000
72 #define TCLK (PCIE_BUS_CLK / 10)
74 #define SMC_RAM_END 0x40000
75 #define SMC_CG_IND_START 0xc0030000
76 #define SMC_CG_IND_END 0xc0040000 /* First byte after SMC_CG_IND*/
78 #define VOLTAGE_SCALE 4
79 #define VOLTAGE_VID_OFFSET_SCALE1 625
80 #define VOLTAGE_VID_OFFSET_SCALE2 100
82 #define VDDC_VDDCI_DELTA 200
83 #define VDDC_VDDGFX_DELTA 300
85 #define MC_SEQ_MISC0_GDDR5_SHIFT 28
86 #define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000
87 #define MC_SEQ_MISC0_GDDR5_VALUE 5
89 typedef uint32_t PECI_RegistryValue
;
91 /* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ] */
92 static const uint16_t PP_ClockStretcherLookupTable
[2][4] = {
96 /* [FF, SS] type, [] 4 voltage ranges, and [Floor Freq, Boundary Freq, VID min , VID max] */
97 static const uint32_t PP_ClockStretcherDDTTable
[2][4][4] = {
98 { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
99 { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
101 /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] (coming from PWR_CKS_CNTL.stretch_amount reg spec) */
102 static const uint8_t PP_ClockStretchAmountConversion
[2][6] = {
104 {0, 2, 4, 5, 6, 5} };
106 /* Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
108 DPM_EVENT_SRC_ANALOG
= 0, /* Internal analog trip point */
109 DPM_EVENT_SRC_EXTERNAL
= 1, /* External (GPIO 17) signal */
110 DPM_EVENT_SRC_DIGITAL
= 2, /* Internal digital trip point (DIG_THERM_DPM) */
111 DPM_EVENT_SRC_ANALOG_OR_EXTERNAL
= 3, /* Internal analog or external */
112 DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL
= 4 /* Internal digital or external */
114 typedef enum DPM_EVENT_SRC DPM_EVENT_SRC
;
116 static const unsigned long PhwTonga_Magic
= (unsigned long)(PHM_VIslands_Magic
);
118 struct tonga_power_state
*cast_phw_tonga_power_state(
119 struct pp_hw_power_state
*hw_ps
)
124 PP_ASSERT_WITH_CODE((PhwTonga_Magic
== hw_ps
->magic
),
125 "Invalid Powerstate Type!",
128 return (struct tonga_power_state
*)hw_ps
;
131 const struct tonga_power_state
*cast_const_phw_tonga_power_state(
132 const struct pp_hw_power_state
*hw_ps
)
137 PP_ASSERT_WITH_CODE((PhwTonga_Magic
== hw_ps
->magic
),
138 "Invalid Powerstate Type!",
141 return (const struct tonga_power_state
*)hw_ps
;
144 int tonga_add_voltage(struct pp_hwmgr
*hwmgr
,
145 phm_ppt_v1_voltage_lookup_table
*look_up_table
,
146 phm_ppt_v1_voltage_lookup_record
*record
)
149 PP_ASSERT_WITH_CODE((NULL
!= look_up_table
),
150 "Lookup Table empty.", return -1;);
151 PP_ASSERT_WITH_CODE((0 != look_up_table
->count
),
152 "Lookup Table empty.", return -1;);
153 PP_ASSERT_WITH_CODE((SMU72_MAX_LEVELS_VDDGFX
>= look_up_table
->count
),
154 "Lookup Table is full.", return -1;);
156 /* This is to avoid entering duplicate calculated records. */
157 for (i
= 0; i
< look_up_table
->count
; i
++) {
158 if (look_up_table
->entries
[i
].us_vdd
== record
->us_vdd
) {
159 if (look_up_table
->entries
[i
].us_calculated
== 1)
166 look_up_table
->entries
[i
].us_calculated
= 1;
167 look_up_table
->entries
[i
].us_vdd
= record
->us_vdd
;
168 look_up_table
->entries
[i
].us_cac_low
= record
->us_cac_low
;
169 look_up_table
->entries
[i
].us_cac_mid
= record
->us_cac_mid
;
170 look_up_table
->entries
[i
].us_cac_high
= record
->us_cac_high
;
171 /* Only increment the count when we're appending, not replacing duplicate entry. */
172 if (i
== look_up_table
->count
)
173 look_up_table
->count
++;
178 int tonga_notify_smc_display_change(struct pp_hwmgr
*hwmgr
, bool has_display
)
180 PPSMC_Msg msg
= has_display
? (PPSMC_Msg
)PPSMC_HasDisplay
: (PPSMC_Msg
)PPSMC_NoDisplay
;
182 return (smum_send_msg_to_smc(hwmgr
->smumgr
, msg
) == 0) ? 0 : -1;
185 uint8_t tonga_get_voltage_id(pp_atomctrl_voltage_table
*voltage_table
,
188 uint8_t count
= (uint8_t) (voltage_table
->count
);
191 PP_ASSERT_WITH_CODE((NULL
!= voltage_table
),
192 "Voltage Table empty.", return 0;);
193 PP_ASSERT_WITH_CODE((0 != count
),
194 "Voltage Table empty.", return 0;);
196 for (i
= 0; i
< count
; i
++) {
197 /* find first voltage bigger than requested */
198 if (voltage_table
->entries
[i
].value
>= voltage
)
202 /* voltage is bigger than max voltage in the table */
207 * @brief PhwTonga_GetVoltageOrder
208 * Returns index of requested voltage record in lookup(table)
209 * @param hwmgr - pointer to hardware manager
210 * @param lookupTable - lookup list to search in
211 * @param voltage - voltage to look for
212 * @return 0 on success
214 uint8_t tonga_get_voltage_index(phm_ppt_v1_voltage_lookup_table
*look_up_table
,
217 uint8_t count
= (uint8_t) (look_up_table
->count
);
220 PP_ASSERT_WITH_CODE((NULL
!= look_up_table
), "Lookup Table empty.", return 0;);
221 PP_ASSERT_WITH_CODE((0 != count
), "Lookup Table empty.", return 0;);
223 for (i
= 0; i
< count
; i
++) {
224 /* find first voltage equal or bigger than requested */
225 if (look_up_table
->entries
[i
].us_vdd
>= voltage
)
229 /* voltage is bigger than max voltage in the table */
233 bool tonga_is_dpm_running(struct pp_hwmgr
*hwmgr
)
236 * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
237 * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
238 * whereas voltage control is a fundemental change that will not be disabled
241 return (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
242 FEATURE_STATUS
, VOLTAGE_CONTROLLER_ON
) ? 1 : 0);
246 * Re-generate the DPM level mask value
247 * @param hwmgr the address of the hardware manager
249 static uint32_t tonga_get_dpm_level_enable_mask_value(
250 struct tonga_single_dpm_table
* dpm_table
)
253 uint32_t mask_value
= 0;
255 for (i
= dpm_table
->count
; i
> 0; i
--) {
256 mask_value
= mask_value
<< 1;
258 if (dpm_table
->dpm_levels
[i
-1].enabled
)
261 mask_value
&= 0xFFFFFFFE;
267 * Retrieve DPM default values from registry (if available)
269 * @param hwmgr the address of the powerplay hardware manager.
271 void tonga_initialize_dpm_defaults(struct pp_hwmgr
*hwmgr
)
273 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
274 phw_tonga_ulv_parm
*ulv
= &(data
->ulv
);
277 ulv
->ch_ulv_parameter
= PPTONGA_CGULVPARAMETER_DFLT
;
278 data
->voting_rights_clients0
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0
;
279 data
->voting_rights_clients1
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1
;
280 data
->voting_rights_clients2
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2
;
281 data
->voting_rights_clients3
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3
;
282 data
->voting_rights_clients4
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4
;
283 data
->voting_rights_clients5
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5
;
284 data
->voting_rights_clients6
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6
;
285 data
->voting_rights_clients7
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7
;
287 data
->static_screen_threshold_unit
= PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT
;
288 data
->static_screen_threshold
= PPTONGA_STATICSCREENTHRESHOLD_DFLT
;
290 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
291 PHM_PlatformCaps_ABM
);
292 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
293 PHM_PlatformCaps_NonABMSupportInPPLib
);
297 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
298 PHM_PlatformCaps_DynamicACTiming
);
302 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
303 PHM_PlatformCaps_DisableMemoryTransition
);
305 data
->mclk_strobe_mode_threshold
= 40000;
306 data
->mclk_stutter_mode_threshold
= 30000;
307 data
->mclk_edc_enable_threshold
= 40000;
308 data
->mclk_edc_wr_enable_threshold
= 40000;
312 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
313 PHM_PlatformCaps_DisableMCLS
);
315 data
->pcie_gen_performance
.max
= PP_PCIEGen1
;
316 data
->pcie_gen_performance
.min
= PP_PCIEGen3
;
317 data
->pcie_gen_power_saving
.max
= PP_PCIEGen1
;
318 data
->pcie_gen_power_saving
.min
= PP_PCIEGen3
;
320 data
->pcie_lane_performance
.max
= 0;
321 data
->pcie_lane_performance
.min
= 16;
322 data
->pcie_lane_power_saving
.max
= 0;
323 data
->pcie_lane_power_saving
.min
= 16;
328 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
329 PHM_PlatformCaps_SclkThrottleLowNotification
);
331 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
332 PHM_PlatformCaps_DynamicUVDState
);
336 int tonga_update_sclk_threshold(struct pp_hwmgr
*hwmgr
)
338 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
341 uint32_t low_sclk_interrupt_threshold
= 0;
343 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
344 PHM_PlatformCaps_SclkThrottleLowNotification
)
345 && (hwmgr
->gfx_arbiter
.sclk_threshold
!= data
->low_sclk_interrupt_threshold
)) {
346 data
->low_sclk_interrupt_threshold
= hwmgr
->gfx_arbiter
.sclk_threshold
;
347 low_sclk_interrupt_threshold
= data
->low_sclk_interrupt_threshold
;
349 CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold
);
351 result
= tonga_copy_bytes_to_smc(
353 data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
,
354 LowSclkInterruptThreshold
),
355 (uint8_t *)&low_sclk_interrupt_threshold
,
365 * Find SCLK value that is associated with specified virtual_voltage_Id.
367 * @param hwmgr the address of the powerplay hardware manager.
368 * @param virtual_voltage_Id voltageId to look for.
369 * @param sclk output value .
370 * @return always 0 if success and 2 if association not found
372 static int tonga_get_sclk_for_voltage_evv(struct pp_hwmgr
*hwmgr
,
373 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
374 uint16_t virtual_voltage_id
, uint32_t *sclk
)
378 struct phm_ppt_v1_information
*pptable_info
=
379 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
381 PP_ASSERT_WITH_CODE(lookup_table
->count
!= 0, "Lookup table is empty", return -1);
383 /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
384 for (entryId
= 0; entryId
< pptable_info
->vdd_dep_on_sclk
->count
; entryId
++) {
385 voltageId
= pptable_info
->vdd_dep_on_sclk
->entries
[entryId
].vddInd
;
386 if (lookup_table
->entries
[voltageId
].us_vdd
== virtual_voltage_id
)
390 PP_ASSERT_WITH_CODE(entryId
< pptable_info
->vdd_dep_on_sclk
->count
,
391 "Can't find requested voltage id in vdd_dep_on_sclk table!",
395 *sclk
= pptable_info
->vdd_dep_on_sclk
->entries
[entryId
].clk
;
401 * Get Leakage VDDC based on leakage ID.
403 * @param hwmgr the address of the powerplay hardware manager.
404 * @return 2 if vddgfx returned is greater than 2V or if BIOS
406 int tonga_get_evv_voltage(struct pp_hwmgr
*hwmgr
)
408 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
409 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
410 phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
= pptable_info
->vdd_dep_on_sclk
;
411 uint16_t virtual_voltage_id
;
417 /* retrieve voltage for leakage ID (0xff01 + i) */
418 for (i
= 0; i
< TONGA_MAX_LEAKAGE_COUNT
; i
++) {
419 virtual_voltage_id
= ATOM_VIRTUAL_VOLTAGE_ID0
+ i
;
421 /* in split mode we should have only vddgfx EVV leakages */
422 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
423 if (0 == tonga_get_sclk_for_voltage_evv(hwmgr
,
424 pptable_info
->vddgfx_lookup_table
, virtual_voltage_id
, &sclk
)) {
425 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
426 PHM_PlatformCaps_ClockStretcher
)) {
427 for (j
= 1; j
< sclk_table
->count
; j
++) {
428 if (sclk_table
->entries
[j
].clk
== sclk
&&
429 sclk_table
->entries
[j
].cks_enable
== 0) {
435 if (0 == atomctrl_get_voltage_evv_on_sclk
436 (hwmgr
, VOLTAGE_TYPE_VDDGFX
, sclk
,
437 virtual_voltage_id
, &vddgfx
)) {
438 /* need to make sure vddgfx is less than 2v or else, it could burn the ASIC. */
439 PP_ASSERT_WITH_CODE((vddgfx
< 2000 && vddgfx
!= 0), "Invalid VDDGFX value!", return -1);
441 /* the voltage should not be zero nor equal to leakage ID */
442 if (vddgfx
!= 0 && vddgfx
!= virtual_voltage_id
) {
443 data
->vddcgfx_leakage
.actual_voltage
[data
->vddcgfx_leakage
.count
] = vddgfx
;
444 data
->vddcgfx_leakage
.leakage_id
[data
->vddcgfx_leakage
.count
] = virtual_voltage_id
;
445 data
->vddcgfx_leakage
.count
++;
448 printk("Error retrieving EVV voltage value!\n");
452 /* in merged mode we have only vddc EVV leakages */
453 if (0 == tonga_get_sclk_for_voltage_evv(hwmgr
,
454 pptable_info
->vddc_lookup_table
,
455 virtual_voltage_id
, &sclk
)) {
456 if (0 == atomctrl_get_voltage_evv_on_sclk
457 (hwmgr
, VOLTAGE_TYPE_VDDC
, sclk
,
458 virtual_voltage_id
, &vddc
)) {
459 /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
460 PP_ASSERT_WITH_CODE(vddc
< 2000, "Invalid VDDC value!", return -1);
462 /* the voltage should not be zero nor equal to leakage ID */
463 if (vddc
!= 0 && vddc
!= virtual_voltage_id
) {
464 data
->vddc_leakage
.actual_voltage
[data
->vddc_leakage
.count
] = vddc
;
465 data
->vddc_leakage
.leakage_id
[data
->vddc_leakage
.count
] = virtual_voltage_id
;
466 data
->vddc_leakage
.count
++;
469 printk("Error retrieving EVV voltage value!\n");
478 int tonga_enable_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
480 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
482 /* enable SCLK dpm */
483 if (0 == data
->sclk_dpm_key_disabled
) {
485 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
486 PPSMC_MSG_DPM_Enable
)),
487 "Failed to enable SCLK DPM during DPM Start Function!",
491 /* enable MCLK dpm */
492 if (0 == data
->mclk_dpm_key_disabled
) {
494 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
495 PPSMC_MSG_MCLKDPM_Enable
)),
496 "Failed to enable MCLK DPM during DPM Start Function!",
499 PHM_WRITE_FIELD(hwmgr
->device
, MC_SEQ_CNTL_3
, CAC_EN
, 0x1);
501 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
502 ixLCAC_MC0_CNTL
, 0x05);/* CH0,1 read */
503 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
504 ixLCAC_MC1_CNTL
, 0x05);/* CH2,3 read */
505 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
506 ixLCAC_CPL_CNTL
, 0x100005);/*Read */
510 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
511 ixLCAC_MC0_CNTL
, 0x400005);/* CH0,1 write */
512 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
513 ixLCAC_MC1_CNTL
, 0x400005);/* CH2,3 write */
514 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
515 ixLCAC_CPL_CNTL
, 0x500005);/* write */
522 int tonga_start_dpm(struct pp_hwmgr
*hwmgr
)
524 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
526 /* enable general power management */
527 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, GLOBAL_PWRMGT_EN
, 1);
528 /* enable sclk deep sleep */
529 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
, DYNAMIC_PM_EN
, 1);
531 /* prepare for PCIE DPM */
532 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, data
->soft_regs_start
+
533 offsetof(SMU72_SoftRegisters
, VoltageChangeTimeout
), 0x1000);
535 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__PCIE
, SWRST_COMMAND_1
, RESETLC
, 0x0);
538 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
539 PPSMC_MSG_Voltage_Cntl_Enable
)),
540 "Failed to enable voltage DPM during DPM Start Function!",
543 if (0 != tonga_enable_sclk_mclk_dpm(hwmgr
)) {
544 PP_ASSERT_WITH_CODE(0, "Failed to enable Sclk DPM and Mclk DPM!", return -1);
547 /* enable PCIE dpm */
548 if (0 == data
->pcie_dpm_key_disabled
) {
550 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
551 PPSMC_MSG_PCIeDPM_Enable
)),
552 "Failed to enable pcie DPM during DPM Start Function!",
557 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
558 PHM_PlatformCaps_Falcon_QuickTransition
)) {
559 smum_send_msg_to_smc(hwmgr
->smumgr
,
560 PPSMC_MSG_EnableACDCGPIOInterrupt
);
566 int tonga_disable_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
568 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
570 /* disable SCLK dpm */
571 if (0 == data
->sclk_dpm_key_disabled
) {
572 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
574 !tonga_is_dpm_running(hwmgr
),
575 "Trying to Disable SCLK DPM when DPM is disabled",
580 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
581 PPSMC_MSG_DPM_Disable
)),
582 "Failed to disable SCLK DPM during DPM stop Function!",
586 /* disable MCLK dpm */
587 if (0 == data
->mclk_dpm_key_disabled
) {
588 /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
590 !tonga_is_dpm_running(hwmgr
),
591 "Trying to Disable MCLK DPM when DPM is disabled",
596 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
597 PPSMC_MSG_MCLKDPM_Disable
)),
598 "Failed to Disable MCLK DPM during DPM stop Function!",
605 int tonga_stop_dpm(struct pp_hwmgr
*hwmgr
)
607 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
609 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, GLOBAL_PWRMGT_EN
, 0);
610 /* disable sclk deep sleep*/
611 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
, DYNAMIC_PM_EN
, 0);
613 /* disable PCIE dpm */
614 if (0 == data
->pcie_dpm_key_disabled
) {
615 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
617 !tonga_is_dpm_running(hwmgr
),
618 "Trying to Disable PCIE DPM when DPM is disabled",
622 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
623 PPSMC_MSG_PCIeDPM_Disable
)),
624 "Failed to disable pcie DPM during DPM stop Function!",
628 if (0 != tonga_disable_sclk_mclk_dpm(hwmgr
))
629 PP_ASSERT_WITH_CODE(0, "Failed to disable Sclk DPM and Mclk DPM!", return -1);
631 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
633 !tonga_is_dpm_running(hwmgr
),
634 "Trying to Disable Voltage CNTL when DPM is disabled",
639 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
640 PPSMC_MSG_Voltage_Cntl_Disable
)),
641 "Failed to disable voltage DPM during DPM stop Function!",
647 int tonga_enable_sclk_control(struct pp_hwmgr
*hwmgr
)
649 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
, SCLK_PWRMGT_OFF
, 0);
655 * Send a message to the SMC and return a parameter
657 * @param hwmgr: the address of the powerplay hardware manager.
658 * @param msg: the message to send.
659 * @param parameter: pointer to the received parameter
660 * @return The response that came from the SMC.
662 PPSMC_Result
tonga_send_msg_to_smc_return_parameter(
663 struct pp_hwmgr
*hwmgr
,
669 result
= smum_send_msg_to_smc(hwmgr
->smumgr
, msg
);
671 if ((0 == result
) && parameter
) {
672 *parameter
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
679 * force DPM power State
681 * @param hwmgr: the address of the powerplay hardware manager.
682 * @param n : DPM level
683 * @return The response that came from the SMC.
685 int tonga_dpm_force_state(struct pp_hwmgr
*hwmgr
, uint32_t n
)
687 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
688 uint32_t level_mask
= 1 << n
;
690 /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
691 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
692 "Trying to force SCLK when DPM is disabled",
694 if (0 == data
->sclk_dpm_key_disabled
)
695 return (0 == smum_send_msg_to_smc_with_parameter(
697 (PPSMC_Msg
)(PPSMC_MSG_SCLKDPM_SetEnabledMask
),
698 level_mask
) ? 0 : 1);
704 * force DPM power State
706 * @param hwmgr: the address of the powerplay hardware manager.
707 * @param n : DPM level
708 * @return The response that came from the SMC.
710 int tonga_dpm_force_state_mclk(struct pp_hwmgr
*hwmgr
, uint32_t n
)
712 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
713 uint32_t level_mask
= 1 << n
;
715 /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
716 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
717 "Trying to Force MCLK when DPM is disabled",
719 if (0 == data
->mclk_dpm_key_disabled
)
720 return (0 == smum_send_msg_to_smc_with_parameter(
722 (PPSMC_Msg
)(PPSMC_MSG_MCLKDPM_SetEnabledMask
),
723 level_mask
) ? 0 : 1);
729 * force DPM power State
731 * @param hwmgr: the address of the powerplay hardware manager.
732 * @param n : DPM level
733 * @return The response that came from the SMC.
735 int tonga_dpm_force_state_pcie(struct pp_hwmgr
*hwmgr
, uint32_t n
)
737 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
739 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
740 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
741 "Trying to Force PCIE level when DPM is disabled",
743 if (0 == data
->pcie_dpm_key_disabled
)
744 return (0 == smum_send_msg_to_smc_with_parameter(
746 (PPSMC_Msg
)(PPSMC_MSG_PCIeDPM_ForceLevel
),
753 * Set the initial state by calling SMC to switch to this state directly
755 * @param hwmgr the address of the powerplay hardware manager.
758 int tonga_set_boot_state(struct pp_hwmgr
*hwmgr
)
761 * SMC only stores one state that SW will ask to switch too,
762 * so we switch the the just uploaded one
764 return (0 == tonga_disable_sclk_mclk_dpm(hwmgr
)) ? 0 : 1;
768 * Get the location of various tables inside the FW image.
770 * @param hwmgr the address of the powerplay hardware manager.
773 int tonga_process_firmware_header(struct pp_hwmgr
*hwmgr
)
775 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
776 struct tonga_smumgr
*tonga_smu
= (struct tonga_smumgr
*)(hwmgr
->smumgr
->backend
);
782 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
783 SMU72_FIRMWARE_HEADER_LOCATION
+
784 offsetof(SMU72_Firmware_Header
, DpmTable
),
785 &tmp
, data
->sram_end
);
788 data
->dpm_table_start
= tmp
;
791 error
|= (0 != result
);
793 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
794 SMU72_FIRMWARE_HEADER_LOCATION
+
795 offsetof(SMU72_Firmware_Header
, SoftRegisters
),
796 &tmp
, data
->sram_end
);
799 data
->soft_regs_start
= tmp
;
800 tonga_smu
->ulSoftRegsStart
= tmp
;
803 error
|= (0 != result
);
806 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
807 SMU72_FIRMWARE_HEADER_LOCATION
+
808 offsetof(SMU72_Firmware_Header
, mcRegisterTable
),
809 &tmp
, data
->sram_end
);
812 data
->mc_reg_table_start
= tmp
;
815 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
816 SMU72_FIRMWARE_HEADER_LOCATION
+
817 offsetof(SMU72_Firmware_Header
, FanTable
),
818 &tmp
, data
->sram_end
);
821 data
->fan_table_start
= tmp
;
824 error
|= (0 != result
);
826 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
827 SMU72_FIRMWARE_HEADER_LOCATION
+
828 offsetof(SMU72_Firmware_Header
, mcArbDramTimingTable
),
829 &tmp
, data
->sram_end
);
832 data
->arb_table_start
= tmp
;
835 error
|= (0 != result
);
838 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
839 SMU72_FIRMWARE_HEADER_LOCATION
+
840 offsetof(SMU72_Firmware_Header
, Version
),
841 &tmp
, data
->sram_end
);
844 hwmgr
->microcode_version_info
.SMC
= tmp
;
847 error
|= (0 != result
);
849 return error
? 1 : 0;
853 * Read clock related registers.
855 * @param hwmgr the address of the powerplay hardware manager.
858 int tonga_read_clock_registers(struct pp_hwmgr
*hwmgr
)
860 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
862 data
->clock_registers
.vCG_SPLL_FUNC_CNTL
=
863 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL
);
864 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
=
865 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL_2
);
866 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
=
867 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL_3
);
868 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
=
869 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL_4
);
870 data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
=
871 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_SPREAD_SPECTRUM
);
872 data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
=
873 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_SPREAD_SPECTRUM_2
);
874 data
->clock_registers
.vDLL_CNTL
=
875 cgs_read_register(hwmgr
->device
, mmDLL_CNTL
);
876 data
->clock_registers
.vMCLK_PWRMGT_CNTL
=
877 cgs_read_register(hwmgr
->device
, mmMCLK_PWRMGT_CNTL
);
878 data
->clock_registers
.vMPLL_AD_FUNC_CNTL
=
879 cgs_read_register(hwmgr
->device
, mmMPLL_AD_FUNC_CNTL
);
880 data
->clock_registers
.vMPLL_DQ_FUNC_CNTL
=
881 cgs_read_register(hwmgr
->device
, mmMPLL_DQ_FUNC_CNTL
);
882 data
->clock_registers
.vMPLL_FUNC_CNTL
=
883 cgs_read_register(hwmgr
->device
, mmMPLL_FUNC_CNTL
);
884 data
->clock_registers
.vMPLL_FUNC_CNTL_1
=
885 cgs_read_register(hwmgr
->device
, mmMPLL_FUNC_CNTL_1
);
886 data
->clock_registers
.vMPLL_FUNC_CNTL_2
=
887 cgs_read_register(hwmgr
->device
, mmMPLL_FUNC_CNTL_2
);
888 data
->clock_registers
.vMPLL_SS1
=
889 cgs_read_register(hwmgr
->device
, mmMPLL_SS1
);
890 data
->clock_registers
.vMPLL_SS2
=
891 cgs_read_register(hwmgr
->device
, mmMPLL_SS2
);
897 * Find out if memory is GDDR5.
899 * @param hwmgr the address of the powerplay hardware manager.
902 int tonga_get_memory_type(struct pp_hwmgr
*hwmgr
)
904 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
907 temp
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC0
);
909 data
->is_memory_GDDR5
= (MC_SEQ_MISC0_GDDR5_VALUE
==
910 ((temp
& MC_SEQ_MISC0_GDDR5_MASK
) >>
911 MC_SEQ_MISC0_GDDR5_SHIFT
));
917 * Enables Dynamic Power Management by SMC
919 * @param hwmgr the address of the powerplay hardware manager.
922 int tonga_enable_acpi_power_management(struct pp_hwmgr
*hwmgr
)
924 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, STATIC_PM_EN
, 1);
930 * Initialize PowerGating States for different engines
932 * @param hwmgr the address of the powerplay hardware manager.
935 int tonga_init_power_gate_state(struct pp_hwmgr
*hwmgr
)
937 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
939 data
->uvd_power_gated
= false;
940 data
->vce_power_gated
= false;
941 data
->samu_power_gated
= false;
942 data
->acp_power_gated
= false;
943 data
->pg_acp_init
= true;
949 * Checks if DPM is enabled
951 * @param hwmgr the address of the powerplay hardware manager.
954 int tonga_check_for_dpm_running(struct pp_hwmgr
*hwmgr
)
957 * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
958 * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
959 * whereas voltage control is a fundemental change that will not be disabled
961 return (!tonga_is_dpm_running(hwmgr
) ? 0 : 1);
965 * Checks if DPM is stopped
967 * @param hwmgr the address of the powerplay hardware manager.
970 int tonga_check_for_dpm_stopped(struct pp_hwmgr
*hwmgr
)
972 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
974 if (tonga_is_dpm_running(hwmgr
)) {
975 /* If HW Virtualization is enabled, dpm_table_start will not have a valid value */
976 if (!data
->dpm_table_start
) {
985 * Remove repeated voltage values and create table with unique values.
987 * @param hwmgr the address of the powerplay hardware manager.
988 * @param voltage_table the pointer to changing voltage table
989 * @return 1 in success
992 static int tonga_trim_voltage_table(struct pp_hwmgr
*hwmgr
,
993 pp_atomctrl_voltage_table
*voltage_table
)
995 uint32_t table_size
, i
, j
;
997 bool bVoltageFound
= false;
998 pp_atomctrl_voltage_table
*table
;
1000 PP_ASSERT_WITH_CODE((NULL
!= voltage_table
), "Voltage Table empty.", return -1;);
1001 table_size
= sizeof(pp_atomctrl_voltage_table
);
1002 table
= kzalloc(table_size
, GFP_KERNEL
);
1007 memset(table
, 0x00, table_size
);
1008 table
->mask_low
= voltage_table
->mask_low
;
1009 table
->phase_delay
= voltage_table
->phase_delay
;
1011 for (i
= 0; i
< voltage_table
->count
; i
++) {
1012 vvalue
= voltage_table
->entries
[i
].value
;
1013 bVoltageFound
= false;
1015 for (j
= 0; j
< table
->count
; j
++) {
1016 if (vvalue
== table
->entries
[j
].value
) {
1017 bVoltageFound
= true;
1022 if (!bVoltageFound
) {
1023 table
->entries
[table
->count
].value
= vvalue
;
1024 table
->entries
[table
->count
].smio_low
=
1025 voltage_table
->entries
[i
].smio_low
;
1030 memcpy(table
, voltage_table
, sizeof(pp_atomctrl_voltage_table
));
1037 static int tonga_get_svi2_vdd_ci_voltage_table(
1038 struct pp_hwmgr
*hwmgr
,
1039 phm_ppt_v1_clock_voltage_dependency_table
*voltage_dependency_table
)
1043 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1044 pp_atomctrl_voltage_table
*vddci_voltage_table
= &(data
->vddci_voltage_table
);
1046 PP_ASSERT_WITH_CODE((0 != voltage_dependency_table
->count
),
1047 "Voltage Dependency Table empty.", return -1;);
1049 vddci_voltage_table
->mask_low
= 0;
1050 vddci_voltage_table
->phase_delay
= 0;
1051 vddci_voltage_table
->count
= voltage_dependency_table
->count
;
1053 for (i
= 0; i
< voltage_dependency_table
->count
; i
++) {
1054 vddci_voltage_table
->entries
[i
].value
=
1055 voltage_dependency_table
->entries
[i
].vddci
;
1056 vddci_voltage_table
->entries
[i
].smio_low
= 0;
1059 result
= tonga_trim_voltage_table(hwmgr
, vddci_voltage_table
);
1060 PP_ASSERT_WITH_CODE((0 == result
),
1061 "Failed to trim VDDCI table.", return result
;);
1068 static int tonga_get_svi2_vdd_voltage_table(
1069 struct pp_hwmgr
*hwmgr
,
1070 phm_ppt_v1_voltage_lookup_table
*look_up_table
,
1071 pp_atomctrl_voltage_table
*voltage_table
)
1075 PP_ASSERT_WITH_CODE((0 != look_up_table
->count
),
1076 "Voltage Lookup Table empty.", return -1;);
1078 voltage_table
->mask_low
= 0;
1079 voltage_table
->phase_delay
= 0;
1081 voltage_table
->count
= look_up_table
->count
;
1083 for (i
= 0; i
< voltage_table
->count
; i
++) {
1084 voltage_table
->entries
[i
].value
= look_up_table
->entries
[i
].us_vdd
;
1085 voltage_table
->entries
[i
].smio_low
= 0;
1092 * -------------------------------------------------------- Voltage Tables --------------------------------------------------------------------------
1093 * If the voltage table would be bigger than what will fit into the state table on the SMC keep only the higher entries.
1096 static void tonga_trim_voltage_table_to_fit_state_table(
1097 struct pp_hwmgr
*hwmgr
,
1098 uint32_t max_voltage_steps
,
1099 pp_atomctrl_voltage_table
*voltage_table
)
1101 unsigned int i
, diff
;
1103 if (voltage_table
->count
<= max_voltage_steps
) {
1107 diff
= voltage_table
->count
- max_voltage_steps
;
1109 for (i
= 0; i
< max_voltage_steps
; i
++) {
1110 voltage_table
->entries
[i
] = voltage_table
->entries
[i
+ diff
];
1113 voltage_table
->count
= max_voltage_steps
;
1119 * Create Voltage Tables.
1121 * @param hwmgr the address of the powerplay hardware manager.
1124 int tonga_construct_voltage_tables(struct pp_hwmgr
*hwmgr
)
1126 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1127 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1130 /* MVDD has only GPIO voltage control */
1131 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1132 result
= atomctrl_get_voltage_table_v3(hwmgr
,
1133 VOLTAGE_TYPE_MVDDC
, VOLTAGE_OBJ_GPIO_LUT
, &(data
->mvdd_voltage_table
));
1134 PP_ASSERT_WITH_CODE((0 == result
),
1135 "Failed to retrieve MVDD table.", return result
;);
1138 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->vdd_ci_control
) {
1140 result
= atomctrl_get_voltage_table_v3(hwmgr
,
1141 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_GPIO_LUT
, &(data
->vddci_voltage_table
));
1142 PP_ASSERT_WITH_CODE((0 == result
),
1143 "Failed to retrieve VDDCI table.", return result
;);
1144 } else if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_ci_control
) {
1146 result
= tonga_get_svi2_vdd_ci_voltage_table(hwmgr
,
1147 pptable_info
->vdd_dep_on_mclk
);
1148 PP_ASSERT_WITH_CODE((0 == result
),
1149 "Failed to retrieve SVI2 VDDCI table from dependancy table.", return result
;);
1152 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_gfx_control
) {
1153 /* VDDGFX has only SVI2 voltage control */
1154 result
= tonga_get_svi2_vdd_voltage_table(hwmgr
,
1155 pptable_info
->vddgfx_lookup_table
, &(data
->vddgfx_voltage_table
));
1156 PP_ASSERT_WITH_CODE((0 == result
),
1157 "Failed to retrieve SVI2 VDDGFX table from lookup table.", return result
;);
1160 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1161 /* VDDC has only SVI2 voltage control */
1162 result
= tonga_get_svi2_vdd_voltage_table(hwmgr
,
1163 pptable_info
->vddc_lookup_table
, &(data
->vddc_voltage_table
));
1164 PP_ASSERT_WITH_CODE((0 == result
),
1165 "Failed to retrieve SVI2 VDDC table from lookup table.", return result
;);
1168 PP_ASSERT_WITH_CODE(
1169 (data
->vddc_voltage_table
.count
<= (SMU72_MAX_LEVELS_VDDC
)),
1170 "Too many voltage values for VDDC. Trimming to fit state table.",
1171 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1172 SMU72_MAX_LEVELS_VDDC
, &(data
->vddc_voltage_table
));
1175 PP_ASSERT_WITH_CODE(
1176 (data
->vddgfx_voltage_table
.count
<= (SMU72_MAX_LEVELS_VDDGFX
)),
1177 "Too many voltage values for VDDGFX. Trimming to fit state table.",
1178 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1179 SMU72_MAX_LEVELS_VDDGFX
, &(data
->vddgfx_voltage_table
));
1182 PP_ASSERT_WITH_CODE(
1183 (data
->vddci_voltage_table
.count
<= (SMU72_MAX_LEVELS_VDDCI
)),
1184 "Too many voltage values for VDDCI. Trimming to fit state table.",
1185 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1186 SMU72_MAX_LEVELS_VDDCI
, &(data
->vddci_voltage_table
));
1189 PP_ASSERT_WITH_CODE(
1190 (data
->mvdd_voltage_table
.count
<= (SMU72_MAX_LEVELS_MVDD
)),
1191 "Too many voltage values for MVDD. Trimming to fit state table.",
1192 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1193 SMU72_MAX_LEVELS_MVDD
, &(data
->mvdd_voltage_table
));
1200 * Vddc table preparation for SMC.
1202 * @param hwmgr the address of the hardware manager
1203 * @param table the SMC DPM table structure to be populated
1206 static int tonga_populate_smc_vddc_table(struct pp_hwmgr
*hwmgr
,
1207 SMU72_Discrete_DpmTable
*table
)
1210 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1212 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1213 table
->VddcLevelCount
= data
->vddc_voltage_table
.count
;
1214 for (count
= 0; count
< table
->VddcLevelCount
; count
++) {
1215 table
->VddcTable
[count
] =
1216 PP_HOST_TO_SMC_US(data
->vddc_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1218 CONVERT_FROM_HOST_TO_SMC_UL(table
->VddcLevelCount
);
1224 * VddGfx table preparation for SMC.
1226 * @param hwmgr the address of the hardware manager
1227 * @param table the SMC DPM table structure to be populated
1230 static int tonga_populate_smc_vdd_gfx_table(struct pp_hwmgr
*hwmgr
,
1231 SMU72_Discrete_DpmTable
*table
)
1234 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1236 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_gfx_control
) {
1237 table
->VddGfxLevelCount
= data
->vddgfx_voltage_table
.count
;
1238 for (count
= 0; count
< data
->vddgfx_voltage_table
.count
; count
++) {
1239 table
->VddGfxTable
[count
] =
1240 PP_HOST_TO_SMC_US(data
->vddgfx_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1242 CONVERT_FROM_HOST_TO_SMC_UL(table
->VddGfxLevelCount
);
1248 * Vddci table preparation for SMC.
1250 * @param *hwmgr The address of the hardware manager.
1251 * @param *table The SMC DPM table structure to be populated.
1254 static int tonga_populate_smc_vdd_ci_table(struct pp_hwmgr
*hwmgr
,
1255 SMU72_Discrete_DpmTable
*table
)
1257 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1260 table
->VddciLevelCount
= data
->vddci_voltage_table
.count
;
1261 for (count
= 0; count
< table
->VddciLevelCount
; count
++) {
1262 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_ci_control
) {
1263 table
->VddciTable
[count
] =
1264 PP_HOST_TO_SMC_US(data
->vddci_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1265 } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->vdd_ci_control
) {
1266 table
->SmioTable1
.Pattern
[count
].Voltage
=
1267 PP_HOST_TO_SMC_US(data
->vddci_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1268 /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level. */
1269 table
->SmioTable1
.Pattern
[count
].Smio
=
1271 table
->Smio
[count
] |=
1272 data
->vddci_voltage_table
.entries
[count
].smio_low
;
1273 table
->VddciTable
[count
] =
1274 PP_HOST_TO_SMC_US(data
->vddci_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1278 table
->SmioMask1
= data
->vddci_voltage_table
.mask_low
;
1279 CONVERT_FROM_HOST_TO_SMC_UL(table
->VddciLevelCount
);
1285 * Mvdd table preparation for SMC.
1287 * @param *hwmgr The address of the hardware manager.
1288 * @param *table The SMC DPM table structure to be populated.
1291 static int tonga_populate_smc_mvdd_table(struct pp_hwmgr
*hwmgr
,
1292 SMU72_Discrete_DpmTable
*table
)
1294 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1297 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1298 table
->MvddLevelCount
= data
->mvdd_voltage_table
.count
;
1299 for (count
= 0; count
< table
->MvddLevelCount
; count
++) {
1300 table
->SmioTable2
.Pattern
[count
].Voltage
=
1301 PP_HOST_TO_SMC_US(data
->mvdd_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1302 /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/
1303 table
->SmioTable2
.Pattern
[count
].Smio
=
1305 table
->Smio
[count
] |=
1306 data
->mvdd_voltage_table
.entries
[count
].smio_low
;
1308 table
->SmioMask2
= data
->mvdd_voltage_table
.mask_low
;
1310 CONVERT_FROM_HOST_TO_SMC_UL(table
->MvddLevelCount
);
1317 * Convert a voltage value in mv unit to VID number required by SMU firmware
1319 static uint8_t convert_to_vid(uint16_t vddc
)
1321 return (uint8_t) ((6200 - (vddc
* VOLTAGE_SCALE
)) / 25);
1326 * Preparation of vddc and vddgfx CAC tables for SMC.
1328 * @param hwmgr the address of the hardware manager
1329 * @param table the SMC DPM table structure to be populated
1332 static int tonga_populate_cac_tables(struct pp_hwmgr
*hwmgr
,
1333 SMU72_Discrete_DpmTable
*table
)
1337 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1338 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1339 struct phm_ppt_v1_voltage_lookup_table
*vddgfx_lookup_table
= pptable_info
->vddgfx_lookup_table
;
1340 struct phm_ppt_v1_voltage_lookup_table
*vddc_lookup_table
= pptable_info
->vddc_lookup_table
;
1342 /* pTables is already swapped, so in order to use the value from it, we need to swap it back. */
1343 uint32_t vddcLevelCount
= PP_SMC_TO_HOST_UL(table
->VddcLevelCount
);
1344 uint32_t vddgfxLevelCount
= PP_SMC_TO_HOST_UL(table
->VddGfxLevelCount
);
1346 for (count
= 0; count
< vddcLevelCount
; count
++) {
1347 /* We are populating vddc CAC data to BapmVddc table in split and merged mode */
1348 index
= tonga_get_voltage_index(vddc_lookup_table
,
1349 data
->vddc_voltage_table
.entries
[count
].value
);
1350 table
->BapmVddcVidLoSidd
[count
] =
1351 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_low
);
1352 table
->BapmVddcVidHiSidd
[count
] =
1353 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_mid
);
1354 table
->BapmVddcVidHiSidd2
[count
] =
1355 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_high
);
1358 if ((data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
)) {
1359 /* We are populating vddgfx CAC data to BapmVddgfx table in split mode */
1360 for (count
= 0; count
< vddgfxLevelCount
; count
++) {
1361 index
= tonga_get_voltage_index(vddgfx_lookup_table
,
1362 data
->vddgfx_voltage_table
.entries
[count
].value
);
1363 table
->BapmVddGfxVidLoSidd
[count
] =
1364 convert_to_vid(vddgfx_lookup_table
->entries
[index
].us_cac_low
);
1365 table
->BapmVddGfxVidHiSidd
[count
] =
1366 convert_to_vid(vddgfx_lookup_table
->entries
[index
].us_cac_mid
);
1367 table
->BapmVddGfxVidHiSidd2
[count
] =
1368 convert_to_vid(vddgfx_lookup_table
->entries
[index
].us_cac_high
);
1371 for (count
= 0; count
< vddcLevelCount
; count
++) {
1372 index
= tonga_get_voltage_index(vddc_lookup_table
,
1373 data
->vddc_voltage_table
.entries
[count
].value
);
1374 table
->BapmVddGfxVidLoSidd
[count
] =
1375 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_low
);
1376 table
->BapmVddGfxVidHiSidd
[count
] =
1377 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_mid
);
1378 table
->BapmVddGfxVidHiSidd2
[count
] =
1379 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_high
);
1388 * Preparation of voltage tables for SMC.
1390 * @param hwmgr the address of the hardware manager
1391 * @param table the SMC DPM table structure to be populated
1395 int tonga_populate_smc_voltage_tables(struct pp_hwmgr
*hwmgr
,
1396 SMU72_Discrete_DpmTable
*table
)
1400 result
= tonga_populate_smc_vddc_table(hwmgr
, table
);
1401 PP_ASSERT_WITH_CODE(0 == result
,
1402 "can not populate VDDC voltage table to SMC", return -1);
1404 result
= tonga_populate_smc_vdd_ci_table(hwmgr
, table
);
1405 PP_ASSERT_WITH_CODE(0 == result
,
1406 "can not populate VDDCI voltage table to SMC", return -1);
1408 result
= tonga_populate_smc_vdd_gfx_table(hwmgr
, table
);
1409 PP_ASSERT_WITH_CODE(0 == result
,
1410 "can not populate VDDGFX voltage table to SMC", return -1);
1412 result
= tonga_populate_smc_mvdd_table(hwmgr
, table
);
1413 PP_ASSERT_WITH_CODE(0 == result
,
1414 "can not populate MVDD voltage table to SMC", return -1);
1416 result
= tonga_populate_cac_tables(hwmgr
, table
);
1417 PP_ASSERT_WITH_CODE(0 == result
,
1418 "can not populate CAC voltage tables to SMC", return -1);
1424 * Populates the SMC VRConfig field in DPM table.
1426 * @param hwmgr the address of the hardware manager
1427 * @param table the SMC DPM table structure to be populated
1430 static int tonga_populate_vr_config(struct pp_hwmgr
*hwmgr
,
1431 SMU72_Discrete_DpmTable
*table
)
1433 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1436 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_gfx_control
) {
1438 config
= VR_SVI2_PLANE_1
;
1439 table
->VRConfig
|= (config
<<VRCONF_VDDGFX_SHIFT
);
1441 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1442 config
= VR_SVI2_PLANE_2
;
1443 table
->VRConfig
|= config
;
1445 printk(KERN_ERR
"[ powerplay ] VDDC and VDDGFX should be both on SVI2 control in splitted mode! \n");
1449 config
= VR_MERGED_WITH_VDDC
;
1450 table
->VRConfig
|= (config
<<VRCONF_VDDGFX_SHIFT
);
1452 /* Set Vddc Voltage Controller */
1453 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1454 config
= VR_SVI2_PLANE_1
;
1455 table
->VRConfig
|= config
;
1457 printk(KERN_ERR
"[ powerplay ] VDDC should be on SVI2 control in merged mode! \n");
1461 /* Set Vddci Voltage Controller */
1462 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_ci_control
) {
1463 config
= VR_SVI2_PLANE_2
; /* only in merged mode */
1464 table
->VRConfig
|= (config
<<VRCONF_VDDCI_SHIFT
);
1465 } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->vdd_ci_control
) {
1466 config
= VR_SMIO_PATTERN_1
;
1467 table
->VRConfig
|= (config
<<VRCONF_VDDCI_SHIFT
);
1470 /* Set Mvdd Voltage Controller */
1471 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1472 config
= VR_SMIO_PATTERN_2
;
1473 table
->VRConfig
|= (config
<<VRCONF_MVDD_SHIFT
);
1479 static int tonga_get_dependecy_volt_by_clk(struct pp_hwmgr
*hwmgr
,
1480 phm_ppt_v1_clock_voltage_dependency_table
*allowed_clock_voltage_table
,
1481 uint32_t clock
, SMU_VoltageLevel
*voltage
, uint32_t *mvdd
)
1484 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1485 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1487 /* clock - voltage dependency table is empty table */
1488 if (allowed_clock_voltage_table
->count
== 0)
1491 for (i
= 0; i
< allowed_clock_voltage_table
->count
; i
++) {
1492 /* find first sclk bigger than request */
1493 if (allowed_clock_voltage_table
->entries
[i
].clk
>= clock
) {
1494 voltage
->VddGfx
= tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1495 allowed_clock_voltage_table
->entries
[i
].vddgfx
);
1497 voltage
->Vddc
= tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1498 allowed_clock_voltage_table
->entries
[i
].vddc
);
1500 if (allowed_clock_voltage_table
->entries
[i
].vddci
) {
1501 voltage
->Vddci
= tonga_get_voltage_id(&data
->vddci_voltage_table
,
1502 allowed_clock_voltage_table
->entries
[i
].vddci
);
1504 voltage
->Vddci
= tonga_get_voltage_id(&data
->vddci_voltage_table
,
1505 allowed_clock_voltage_table
->entries
[i
].vddc
- data
->vddc_vddci_delta
);
1508 if (allowed_clock_voltage_table
->entries
[i
].mvdd
) {
1509 *mvdd
= (uint32_t) allowed_clock_voltage_table
->entries
[i
].mvdd
;
1512 voltage
->Phases
= 1;
1517 /* sclk is bigger than max sclk in the dependence table */
1518 voltage
->VddGfx
= tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1519 allowed_clock_voltage_table
->entries
[i
-1].vddgfx
);
1520 voltage
->Vddc
= tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1521 allowed_clock_voltage_table
->entries
[i
-1].vddc
);
1523 if (allowed_clock_voltage_table
->entries
[i
-1].vddci
) {
1524 voltage
->Vddci
= tonga_get_voltage_id(&data
->vddci_voltage_table
,
1525 allowed_clock_voltage_table
->entries
[i
-1].vddci
);
1527 if (allowed_clock_voltage_table
->entries
[i
-1].mvdd
) {
1528 *mvdd
= (uint32_t) allowed_clock_voltage_table
->entries
[i
-1].mvdd
;
1535 * Call SMC to reset S0/S1 to S1 and Reset SMIO to initial value
1537 * @param hwmgr the address of the powerplay hardware manager.
1540 int tonga_reset_to_default(struct pp_hwmgr
*hwmgr
)
1542 return (smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_ResetToDefaults
) == 0) ? 0 : 1;
1545 int tonga_populate_memory_timing_parameters(
1546 struct pp_hwmgr
*hwmgr
,
1547 uint32_t engine_clock
,
1548 uint32_t memory_clock
,
1549 struct SMU72_Discrete_MCArbDramTimingTableEntry
*arb_regs
1552 uint32_t dramTiming
;
1553 uint32_t dramTiming2
;
1557 result
= atomctrl_set_engine_dram_timings_rv770(hwmgr
,
1558 engine_clock
, memory_clock
);
1560 PP_ASSERT_WITH_CODE(result
== 0,
1561 "Error calling VBIOS to set DRAM_TIMING.", return result
);
1563 dramTiming
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
1564 dramTiming2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
1565 burstTime
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
);
1567 arb_regs
->McArbDramTiming
= PP_HOST_TO_SMC_UL(dramTiming
);
1568 arb_regs
->McArbDramTiming2
= PP_HOST_TO_SMC_UL(dramTiming2
);
1569 arb_regs
->McArbBurstTime
= (uint8_t)burstTime
;
1575 * Setup parameters for the MC ARB.
1577 * @param hwmgr the address of the powerplay hardware manager.
1579 * This function is to be called from the SetPowerState table.
1581 int tonga_program_memory_timing_parameters(struct pp_hwmgr
*hwmgr
)
1583 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1585 SMU72_Discrete_MCArbDramTimingTable arb_regs
;
1588 memset(&arb_regs
, 0x00, sizeof(SMU72_Discrete_MCArbDramTimingTable
));
1590 for (i
= 0; i
< data
->dpm_table
.sclk_table
.count
; i
++) {
1591 for (j
= 0; j
< data
->dpm_table
.mclk_table
.count
; j
++) {
1592 result
= tonga_populate_memory_timing_parameters
1593 (hwmgr
, data
->dpm_table
.sclk_table
.dpm_levels
[i
].value
,
1594 data
->dpm_table
.mclk_table
.dpm_levels
[j
].value
,
1595 &arb_regs
.entries
[i
][j
]);
1604 result
= tonga_copy_bytes_to_smc(
1606 data
->arb_table_start
,
1607 (uint8_t *)&arb_regs
,
1608 sizeof(SMU72_Discrete_MCArbDramTimingTable
),
1616 static int tonga_populate_smc_link_level(struct pp_hwmgr
*hwmgr
, SMU72_Discrete_DpmTable
*table
)
1618 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1619 struct tonga_dpm_table
*dpm_table
= &data
->dpm_table
;
1622 /* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */
1623 for (i
= 0; i
<= dpm_table
->pcie_speed_table
.count
; i
++) {
1624 table
->LinkLevel
[i
].PcieGenSpeed
=
1625 (uint8_t)dpm_table
->pcie_speed_table
.dpm_levels
[i
].value
;
1626 table
->LinkLevel
[i
].PcieLaneCount
=
1627 (uint8_t)encode_pcie_lane_width(dpm_table
->pcie_speed_table
.dpm_levels
[i
].param1
);
1628 table
->LinkLevel
[i
].EnabledForActivity
=
1630 table
->LinkLevel
[i
].SPC
=
1631 (uint8_t)(data
->pcie_spc_cap
& 0xff);
1632 table
->LinkLevel
[i
].DownThreshold
=
1633 PP_HOST_TO_SMC_UL(5);
1634 table
->LinkLevel
[i
].UpThreshold
=
1635 PP_HOST_TO_SMC_UL(30);
1638 data
->smc_state_table
.LinkLevelCount
=
1639 (uint8_t)dpm_table
->pcie_speed_table
.count
;
1640 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
=
1641 tonga_get_dpm_level_enable_mask_value(&dpm_table
->pcie_speed_table
);
1646 static int tonga_populate_smc_uvd_level(struct pp_hwmgr
*hwmgr
,
1647 SMU72_Discrete_DpmTable
*table
)
1652 pp_atomctrl_clock_dividers_vi dividers
;
1653 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1654 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1655 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1657 table
->UvdLevelCount
= (uint8_t) (mm_table
->count
);
1658 table
->UvdBootLevel
= 0;
1660 for (count
= 0; count
< table
->UvdLevelCount
; count
++) {
1661 table
->UvdLevel
[count
].VclkFrequency
= mm_table
->entries
[count
].vclk
;
1662 table
->UvdLevel
[count
].DclkFrequency
= mm_table
->entries
[count
].dclk
;
1663 table
->UvdLevel
[count
].MinVoltage
.Vddc
=
1664 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1665 mm_table
->entries
[count
].vddc
);
1666 table
->UvdLevel
[count
].MinVoltage
.VddGfx
=
1667 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1668 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1669 mm_table
->entries
[count
].vddgfx
) : 0;
1670 table
->UvdLevel
[count
].MinVoltage
.Vddci
=
1671 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1672 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1673 table
->UvdLevel
[count
].MinVoltage
.Phases
= 1;
1675 /* retrieve divider value for VBIOS */
1676 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1677 table
->UvdLevel
[count
].VclkFrequency
, ÷rs
);
1678 PP_ASSERT_WITH_CODE((0 == result
),
1679 "can not find divide id for Vclk clock", return result
);
1681 table
->UvdLevel
[count
].VclkDivider
= (uint8_t)dividers
.pll_post_divider
;
1683 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1684 table
->UvdLevel
[count
].DclkFrequency
, ÷rs
);
1685 PP_ASSERT_WITH_CODE((0 == result
),
1686 "can not find divide id for Dclk clock", return result
);
1688 table
->UvdLevel
[count
].DclkDivider
= (uint8_t)dividers
.pll_post_divider
;
1690 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].VclkFrequency
);
1691 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].DclkFrequency
);
1692 //CONVERT_FROM_HOST_TO_SMC_UL((uint32_t)table->UvdLevel[count].MinVoltage);
1699 static int tonga_populate_smc_vce_level(struct pp_hwmgr
*hwmgr
,
1700 SMU72_Discrete_DpmTable
*table
)
1705 pp_atomctrl_clock_dividers_vi dividers
;
1706 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1707 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1708 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1710 table
->VceLevelCount
= (uint8_t) (mm_table
->count
);
1711 table
->VceBootLevel
= 0;
1713 for (count
= 0; count
< table
->VceLevelCount
; count
++) {
1714 table
->VceLevel
[count
].Frequency
=
1715 mm_table
->entries
[count
].eclk
;
1716 table
->VceLevel
[count
].MinVoltage
.Vddc
=
1717 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1718 mm_table
->entries
[count
].vddc
);
1719 table
->VceLevel
[count
].MinVoltage
.VddGfx
=
1720 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1721 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1722 mm_table
->entries
[count
].vddgfx
) : 0;
1723 table
->VceLevel
[count
].MinVoltage
.Vddci
=
1724 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1725 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1726 table
->VceLevel
[count
].MinVoltage
.Phases
= 1;
1728 /* retrieve divider value for VBIOS */
1729 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1730 table
->VceLevel
[count
].Frequency
, ÷rs
);
1731 PP_ASSERT_WITH_CODE((0 == result
),
1732 "can not find divide id for VCE engine clock", return result
);
1734 table
->VceLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1736 CONVERT_FROM_HOST_TO_SMC_UL(table
->VceLevel
[count
].Frequency
);
1742 static int tonga_populate_smc_acp_level(struct pp_hwmgr
*hwmgr
,
1743 SMU72_Discrete_DpmTable
*table
)
1747 pp_atomctrl_clock_dividers_vi dividers
;
1748 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1749 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1750 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1752 table
->AcpLevelCount
= (uint8_t) (mm_table
->count
);
1753 table
->AcpBootLevel
= 0;
1755 for (count
= 0; count
< table
->AcpLevelCount
; count
++) {
1756 table
->AcpLevel
[count
].Frequency
=
1757 pptable_info
->mm_dep_table
->entries
[count
].aclk
;
1758 table
->AcpLevel
[count
].MinVoltage
.Vddc
=
1759 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1760 mm_table
->entries
[count
].vddc
);
1761 table
->AcpLevel
[count
].MinVoltage
.VddGfx
=
1762 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1763 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1764 mm_table
->entries
[count
].vddgfx
) : 0;
1765 table
->AcpLevel
[count
].MinVoltage
.Vddci
=
1766 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1767 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1768 table
->AcpLevel
[count
].MinVoltage
.Phases
= 1;
1770 /* retrieve divider value for VBIOS */
1771 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1772 table
->AcpLevel
[count
].Frequency
, ÷rs
);
1773 PP_ASSERT_WITH_CODE((0 == result
),
1774 "can not find divide id for engine clock", return result
);
1776 table
->AcpLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1778 CONVERT_FROM_HOST_TO_SMC_UL(table
->AcpLevel
[count
].Frequency
);
1784 static int tonga_populate_smc_samu_level(struct pp_hwmgr
*hwmgr
,
1785 SMU72_Discrete_DpmTable
*table
)
1789 pp_atomctrl_clock_dividers_vi dividers
;
1790 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1791 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1792 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1794 table
->SamuBootLevel
= 0;
1795 table
->SamuLevelCount
= (uint8_t) (mm_table
->count
);
1797 for (count
= 0; count
< table
->SamuLevelCount
; count
++) {
1798 /* not sure whether we need evclk or not */
1799 table
->SamuLevel
[count
].Frequency
=
1800 pptable_info
->mm_dep_table
->entries
[count
].samclock
;
1801 table
->SamuLevel
[count
].MinVoltage
.Vddc
=
1802 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1803 mm_table
->entries
[count
].vddc
);
1804 table
->SamuLevel
[count
].MinVoltage
.VddGfx
=
1805 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1806 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1807 mm_table
->entries
[count
].vddgfx
) : 0;
1808 table
->SamuLevel
[count
].MinVoltage
.Vddci
=
1809 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1810 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1811 table
->SamuLevel
[count
].MinVoltage
.Phases
= 1;
1813 /* retrieve divider value for VBIOS */
1814 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1815 table
->SamuLevel
[count
].Frequency
, ÷rs
);
1816 PP_ASSERT_WITH_CODE((0 == result
),
1817 "can not find divide id for samu clock", return result
);
1819 table
->SamuLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1821 CONVERT_FROM_HOST_TO_SMC_UL(table
->SamuLevel
[count
].Frequency
);
1828 * Populates the SMC MCLK structure using the provided memory clock
1830 * @param hwmgr the address of the hardware manager
1831 * @param memory_clock the memory clock to use to populate the structure
1832 * @param sclk the SMC SCLK structure to be populated
1834 static int tonga_calculate_mclk_params(
1835 struct pp_hwmgr
*hwmgr
,
1836 uint32_t memory_clock
,
1837 SMU72_Discrete_MemoryLevel
*mclk
,
1842 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1843 uint32_t dll_cntl
= data
->clock_registers
.vDLL_CNTL
;
1844 uint32_t mclk_pwrmgt_cntl
= data
->clock_registers
.vMCLK_PWRMGT_CNTL
;
1845 uint32_t mpll_ad_func_cntl
= data
->clock_registers
.vMPLL_AD_FUNC_CNTL
;
1846 uint32_t mpll_dq_func_cntl
= data
->clock_registers
.vMPLL_DQ_FUNC_CNTL
;
1847 uint32_t mpll_func_cntl
= data
->clock_registers
.vMPLL_FUNC_CNTL
;
1848 uint32_t mpll_func_cntl_1
= data
->clock_registers
.vMPLL_FUNC_CNTL_1
;
1849 uint32_t mpll_func_cntl_2
= data
->clock_registers
.vMPLL_FUNC_CNTL_2
;
1850 uint32_t mpll_ss1
= data
->clock_registers
.vMPLL_SS1
;
1851 uint32_t mpll_ss2
= data
->clock_registers
.vMPLL_SS2
;
1853 pp_atomctrl_memory_clock_param mpll_param
;
1856 result
= atomctrl_get_memory_pll_dividers_si(hwmgr
,
1857 memory_clock
, &mpll_param
, strobe_mode
);
1858 PP_ASSERT_WITH_CODE(0 == result
,
1859 "Error retrieving Memory Clock Parameters from VBIOS.", return result
);
1861 /* MPLL_FUNC_CNTL setup*/
1862 mpll_func_cntl
= PHM_SET_FIELD(mpll_func_cntl
, MPLL_FUNC_CNTL
, BWCTRL
, mpll_param
.bw_ctrl
);
1864 /* MPLL_FUNC_CNTL_1 setup*/
1865 mpll_func_cntl_1
= PHM_SET_FIELD(mpll_func_cntl_1
,
1866 MPLL_FUNC_CNTL_1
, CLKF
, mpll_param
.mpll_fb_divider
.cl_kf
);
1867 mpll_func_cntl_1
= PHM_SET_FIELD(mpll_func_cntl_1
,
1868 MPLL_FUNC_CNTL_1
, CLKFRAC
, mpll_param
.mpll_fb_divider
.clk_frac
);
1869 mpll_func_cntl_1
= PHM_SET_FIELD(mpll_func_cntl_1
,
1870 MPLL_FUNC_CNTL_1
, VCO_MODE
, mpll_param
.vco_mode
);
1872 /* MPLL_AD_FUNC_CNTL setup*/
1873 mpll_ad_func_cntl
= PHM_SET_FIELD(mpll_ad_func_cntl
,
1874 MPLL_AD_FUNC_CNTL
, YCLK_POST_DIV
, mpll_param
.mpll_post_divider
);
1876 if (data
->is_memory_GDDR5
) {
1877 /* MPLL_DQ_FUNC_CNTL setup*/
1878 mpll_dq_func_cntl
= PHM_SET_FIELD(mpll_dq_func_cntl
,
1879 MPLL_DQ_FUNC_CNTL
, YCLK_SEL
, mpll_param
.yclk_sel
);
1880 mpll_dq_func_cntl
= PHM_SET_FIELD(mpll_dq_func_cntl
,
1881 MPLL_DQ_FUNC_CNTL
, YCLK_POST_DIV
, mpll_param
.mpll_post_divider
);
1884 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
1885 PHM_PlatformCaps_MemorySpreadSpectrumSupport
)) {
1887 ************************************
1888 Fref = Reference Frequency
1889 NF = Feedback divider ratio
1890 NR = Reference divider ratio
1891 Fnom = Nominal VCO output frequency = Fref * NF / NR
1893 D = Percentage down-spread / 2
1894 Fint = Reference input frequency to PFD = Fref / NR
1895 NS = Spreading rate divider ratio = int(Fint / (2 * Fs))
1896 CLKS = NS - 1 = ISS_STEP_NUM[11:0]
1897 NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2)
1898 CLKV = 65536 * NV = ISS_STEP_SIZE[25:0]
1899 *************************************
1901 pp_atomctrl_internal_ss_info ss_info
;
1904 uint32_t reference_clock
= atomctrl_get_mpll_reference_clock(hwmgr
);
1906 /* for GDDR5 for all modes and DDR3 */
1907 if (1 == mpll_param
.qdr
)
1908 freq_nom
= memory_clock
* 4 * (1 << mpll_param
.mpll_post_divider
);
1910 freq_nom
= memory_clock
* 2 * (1 << mpll_param
.mpll_post_divider
);
1912 /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2 Note: S.I. reference_divider = 1*/
1913 tmp
= (freq_nom
/ reference_clock
);
1916 if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr
, freq_nom
, &ss_info
)) {
1917 /* ss_info.speed_spectrum_percentage -- in unit of 0.01% */
1918 /* ss.Info.speed_spectrum_rate -- in unit of khz */
1919 /* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */
1920 /* = reference_clock * 5 / speed_spectrum_rate */
1921 uint32_t clks
= reference_clock
* 5 / ss_info
.speed_spectrum_rate
;
1923 /* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */
1924 /* = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */
1926 (uint32_t)((((131 * ss_info
.speed_spectrum_percentage
*
1927 ss_info
.speed_spectrum_rate
) / 100) * tmp
) / freq_nom
);
1929 mpll_ss1
= PHM_SET_FIELD(mpll_ss1
, MPLL_SS1
, CLKV
, clkv
);
1930 mpll_ss2
= PHM_SET_FIELD(mpll_ss2
, MPLL_SS2
, CLKS
, clks
);
1934 /* MCLK_PWRMGT_CNTL setup */
1935 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
1936 MCLK_PWRMGT_CNTL
, DLL_SPEED
, mpll_param
.dll_speed
);
1937 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
1938 MCLK_PWRMGT_CNTL
, MRDCK0_PDNB
, dllStateOn
);
1939 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
1940 MCLK_PWRMGT_CNTL
, MRDCK1_PDNB
, dllStateOn
);
1943 /* Save the result data to outpupt memory level structure */
1944 mclk
->MclkFrequency
= memory_clock
;
1945 mclk
->MpllFuncCntl
= mpll_func_cntl
;
1946 mclk
->MpllFuncCntl_1
= mpll_func_cntl_1
;
1947 mclk
->MpllFuncCntl_2
= mpll_func_cntl_2
;
1948 mclk
->MpllAdFuncCntl
= mpll_ad_func_cntl
;
1949 mclk
->MpllDqFuncCntl
= mpll_dq_func_cntl
;
1950 mclk
->MclkPwrmgtCntl
= mclk_pwrmgt_cntl
;
1951 mclk
->DllCntl
= dll_cntl
;
1952 mclk
->MpllSs1
= mpll_ss1
;
1953 mclk
->MpllSs2
= mpll_ss2
;
1958 static uint8_t tonga_get_mclk_frequency_ratio(uint32_t memory_clock
,
1961 uint8_t mc_para_index
;
1964 if (memory_clock
< 12500) {
1965 mc_para_index
= 0x00;
1966 } else if (memory_clock
> 47500) {
1967 mc_para_index
= 0x0f;
1969 mc_para_index
= (uint8_t)((memory_clock
- 10000) / 2500);
1972 if (memory_clock
< 65000) {
1973 mc_para_index
= 0x00;
1974 } else if (memory_clock
> 135000) {
1975 mc_para_index
= 0x0f;
1977 mc_para_index
= (uint8_t)((memory_clock
- 60000) / 5000);
1981 return mc_para_index
;
1984 static uint8_t tonga_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock
)
1986 uint8_t mc_para_index
;
1988 if (memory_clock
< 10000) {
1990 } else if (memory_clock
>= 80000) {
1991 mc_para_index
= 0x0f;
1993 mc_para_index
= (uint8_t)((memory_clock
- 10000) / 5000 + 1);
1996 return mc_para_index
;
1999 static int tonga_populate_single_memory_level(
2000 struct pp_hwmgr
*hwmgr
,
2001 uint32_t memory_clock
,
2002 SMU72_Discrete_MemoryLevel
*memory_level
2005 uint32_t minMvdd
= 0;
2006 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2007 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2010 struct cgs_display_info info
= {0};
2013 if (NULL
!= pptable_info
->vdd_dep_on_mclk
) {
2014 result
= tonga_get_dependecy_volt_by_clk(hwmgr
,
2015 pptable_info
->vdd_dep_on_mclk
, memory_clock
, &memory_level
->MinVoltage
, &minMvdd
);
2016 PP_ASSERT_WITH_CODE((0 == result
),
2017 "can not find MinVddc voltage value from memory VDDC voltage dependency table", return result
);
2020 if (data
->mvdd_control
== TONGA_VOLTAGE_CONTROL_NONE
) {
2021 memory_level
->MinMvdd
= data
->vbios_boot_state
.mvdd_bootup_value
;
2023 memory_level
->MinMvdd
= minMvdd
;
2025 memory_level
->EnabledForThrottle
= 1;
2026 memory_level
->EnabledForActivity
= 0;
2027 memory_level
->UpHyst
= 0;
2028 memory_level
->DownHyst
= 100;
2029 memory_level
->VoltageDownHyst
= 0;
2031 /* Indicates maximum activity level for this performance level.*/
2032 memory_level
->ActivityLevel
= (uint16_t)data
->mclk_activity_target
;
2033 memory_level
->StutterEnable
= 0;
2034 memory_level
->StrobeEnable
= 0;
2035 memory_level
->EdcReadEnable
= 0;
2036 memory_level
->EdcWriteEnable
= 0;
2037 memory_level
->RttEnable
= 0;
2039 /* default set to low watermark. Highest level will be set to high later.*/
2040 memory_level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2042 cgs_get_active_displays_info(hwmgr
->device
, &info
);
2043 data
->display_timing
.num_existing_displays
= info
.display_count
;
2045 if ((data
->mclk_stutter_mode_threshold
!= 0) &&
2046 (memory_clock
<= data
->mclk_stutter_mode_threshold
) &&
2047 (!data
->is_uvd_enabled
)
2048 && (PHM_READ_FIELD(hwmgr
->device
, DPG_PIPE_STUTTER_CONTROL
, STUTTER_ENABLE
) & 0x1)
2049 && (data
->display_timing
.num_existing_displays
<= 2)
2050 && (data
->display_timing
.num_existing_displays
!= 0))
2051 memory_level
->StutterEnable
= 1;
2053 /* decide strobe mode*/
2054 memory_level
->StrobeEnable
= (data
->mclk_strobe_mode_threshold
!= 0) &&
2055 (memory_clock
<= data
->mclk_strobe_mode_threshold
);
2057 /* decide EDC mode and memory clock ratio*/
2058 if (data
->is_memory_GDDR5
) {
2059 memory_level
->StrobeRatio
= tonga_get_mclk_frequency_ratio(memory_clock
,
2060 memory_level
->StrobeEnable
);
2062 if ((data
->mclk_edc_enable_threshold
!= 0) &&
2063 (memory_clock
> data
->mclk_edc_enable_threshold
)) {
2064 memory_level
->EdcReadEnable
= 1;
2067 if ((data
->mclk_edc_wr_enable_threshold
!= 0) &&
2068 (memory_clock
> data
->mclk_edc_wr_enable_threshold
)) {
2069 memory_level
->EdcWriteEnable
= 1;
2072 if (memory_level
->StrobeEnable
) {
2073 if (tonga_get_mclk_frequency_ratio(memory_clock
, 1) >=
2074 ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC7
) >> 16) & 0xf)) {
2075 dllStateOn
= ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC5
) >> 1) & 0x1) ? 1 : 0;
2077 dllStateOn
= ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC6
) >> 1) & 0x1) ? 1 : 0;
2081 dllStateOn
= data
->dll_defaule_on
;
2084 memory_level
->StrobeRatio
=
2085 tonga_get_ddr3_mclk_frequency_ratio(memory_clock
);
2086 dllStateOn
= ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC5
) >> 1) & 0x1) ? 1 : 0;
2089 result
= tonga_calculate_mclk_params(hwmgr
,
2090 memory_clock
, memory_level
, memory_level
->StrobeEnable
, dllStateOn
);
2093 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MinMvdd
);
2094 /* MCLK frequency in units of 10KHz*/
2095 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MclkFrequency
);
2096 /* Indicates maximum activity level for this performance level.*/
2097 CONVERT_FROM_HOST_TO_SMC_US(memory_level
->ActivityLevel
);
2098 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllFuncCntl
);
2099 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllFuncCntl_1
);
2100 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllFuncCntl_2
);
2101 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllAdFuncCntl
);
2102 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllDqFuncCntl
);
2103 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MclkPwrmgtCntl
);
2104 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->DllCntl
);
2105 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllSs1
);
2106 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllSs2
);
2113 * Populates the SMC MVDD structure using the provided memory clock.
2115 * @param hwmgr the address of the hardware manager
2116 * @param mclk the MCLK value to be used in the decision if MVDD should be high or low.
2117 * @param voltage the SMC VOLTAGE structure to be populated
2119 int tonga_populate_mvdd_value(struct pp_hwmgr
*hwmgr
, uint32_t mclk
, SMIO_Pattern
*smio_pattern
)
2121 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2122 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2125 if (TONGA_VOLTAGE_CONTROL_NONE
!= data
->mvdd_control
) {
2126 /* find mvdd value which clock is more than request */
2127 for (i
= 0; i
< pptable_info
->vdd_dep_on_mclk
->count
; i
++) {
2128 if (mclk
<= pptable_info
->vdd_dep_on_mclk
->entries
[i
].clk
) {
2129 /* Always round to higher voltage. */
2130 smio_pattern
->Voltage
= data
->mvdd_voltage_table
.entries
[i
].value
;
2135 PP_ASSERT_WITH_CODE(i
< pptable_info
->vdd_dep_on_mclk
->count
,
2136 "MVDD Voltage is outside the supported range.", return -1);
2146 static int tonga_populate_smv_acpi_level(struct pp_hwmgr
*hwmgr
,
2147 SMU72_Discrete_DpmTable
*table
)
2150 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2151 pp_atomctrl_clock_dividers_vi dividers
;
2152 SMIO_Pattern voltage_level
;
2153 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
2154 uint32_t spll_func_cntl_2
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
;
2155 uint32_t dll_cntl
= data
->clock_registers
.vDLL_CNTL
;
2156 uint32_t mclk_pwrmgt_cntl
= data
->clock_registers
.vMCLK_PWRMGT_CNTL
;
2158 /* The ACPI state should not do DPM on DC (or ever).*/
2159 table
->ACPILevel
.Flags
&= ~PPSMC_SWSTATE_FLAG_DC
;
2161 table
->ACPILevel
.MinVoltage
= data
->smc_state_table
.GraphicsLevel
[0].MinVoltage
;
2163 /* assign zero for now*/
2164 table
->ACPILevel
.SclkFrequency
= atomctrl_get_reference_clock(hwmgr
);
2166 /* get the engine clock dividers for this clock value*/
2167 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
,
2168 table
->ACPILevel
.SclkFrequency
, ÷rs
);
2170 PP_ASSERT_WITH_CODE(result
== 0,
2171 "Error retrieving Engine Clock dividers from VBIOS.", return result
);
2173 /* divider ID for required SCLK*/
2174 table
->ACPILevel
.SclkDid
= (uint8_t)dividers
.pll_post_divider
;
2175 table
->ACPILevel
.DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2176 table
->ACPILevel
.DeepSleepDivId
= 0;
2178 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2179 CG_SPLL_FUNC_CNTL
, SPLL_PWRON
, 0);
2180 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2181 CG_SPLL_FUNC_CNTL
, SPLL_RESET
, 1);
2182 spll_func_cntl_2
= PHM_SET_FIELD(spll_func_cntl_2
,
2183 CG_SPLL_FUNC_CNTL_2
, SCLK_MUX_SEL
, 4);
2185 table
->ACPILevel
.CgSpllFuncCntl
= spll_func_cntl
;
2186 table
->ACPILevel
.CgSpllFuncCntl2
= spll_func_cntl_2
;
2187 table
->ACPILevel
.CgSpllFuncCntl3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
2188 table
->ACPILevel
.CgSpllFuncCntl4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
2189 table
->ACPILevel
.SpllSpreadSpectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
2190 table
->ACPILevel
.SpllSpreadSpectrum2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
2191 table
->ACPILevel
.CcPwrDynRm
= 0;
2192 table
->ACPILevel
.CcPwrDynRm1
= 0;
2195 /* For various features to be enabled/disabled while this level is active.*/
2196 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.Flags
);
2197 /* SCLK frequency in units of 10KHz*/
2198 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SclkFrequency
);
2199 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl
);
2200 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl2
);
2201 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl3
);
2202 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl4
);
2203 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum
);
2204 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum2
);
2205 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm
);
2206 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm1
);
2208 /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
2209 table
->MemoryACPILevel
.MinVoltage
= data
->smc_state_table
.MemoryLevel
[0].MinVoltage
;
2211 /* CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);*/
2213 if (0 == tonga_populate_mvdd_value(hwmgr
, 0, &voltage_level
))
2214 table
->MemoryACPILevel
.MinMvdd
=
2215 PP_HOST_TO_SMC_UL(voltage_level
.Voltage
* VOLTAGE_SCALE
);
2217 table
->MemoryACPILevel
.MinMvdd
= 0;
2219 /* Force reset on DLL*/
2220 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2221 MCLK_PWRMGT_CNTL
, MRDCK0_RESET
, 0x1);
2222 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2223 MCLK_PWRMGT_CNTL
, MRDCK1_RESET
, 0x1);
2225 /* Disable DLL in ACPIState*/
2226 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2227 MCLK_PWRMGT_CNTL
, MRDCK0_PDNB
, 0);
2228 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2229 MCLK_PWRMGT_CNTL
, MRDCK1_PDNB
, 0);
2231 /* Enable DLL bypass signal*/
2232 dll_cntl
= PHM_SET_FIELD(dll_cntl
,
2233 DLL_CNTL
, MRDCK0_BYPASS
, 0);
2234 dll_cntl
= PHM_SET_FIELD(dll_cntl
,
2235 DLL_CNTL
, MRDCK1_BYPASS
, 0);
2237 table
->MemoryACPILevel
.DllCntl
=
2238 PP_HOST_TO_SMC_UL(dll_cntl
);
2239 table
->MemoryACPILevel
.MclkPwrmgtCntl
=
2240 PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl
);
2241 table
->MemoryACPILevel
.MpllAdFuncCntl
=
2242 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_AD_FUNC_CNTL
);
2243 table
->MemoryACPILevel
.MpllDqFuncCntl
=
2244 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_DQ_FUNC_CNTL
);
2245 table
->MemoryACPILevel
.MpllFuncCntl
=
2246 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_FUNC_CNTL
);
2247 table
->MemoryACPILevel
.MpllFuncCntl_1
=
2248 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_FUNC_CNTL_1
);
2249 table
->MemoryACPILevel
.MpllFuncCntl_2
=
2250 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_FUNC_CNTL_2
);
2251 table
->MemoryACPILevel
.MpllSs1
=
2252 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_SS1
);
2253 table
->MemoryACPILevel
.MpllSs2
=
2254 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_SS2
);
2256 table
->MemoryACPILevel
.EnabledForThrottle
= 0;
2257 table
->MemoryACPILevel
.EnabledForActivity
= 0;
2258 table
->MemoryACPILevel
.UpHyst
= 0;
2259 table
->MemoryACPILevel
.DownHyst
= 100;
2260 table
->MemoryACPILevel
.VoltageDownHyst
= 0;
2261 /* Indicates maximum activity level for this performance level.*/
2262 table
->MemoryACPILevel
.ActivityLevel
= PP_HOST_TO_SMC_US((uint16_t)data
->mclk_activity_target
);
2264 table
->MemoryACPILevel
.StutterEnable
= 0;
2265 table
->MemoryACPILevel
.StrobeEnable
= 0;
2266 table
->MemoryACPILevel
.EdcReadEnable
= 0;
2267 table
->MemoryACPILevel
.EdcWriteEnable
= 0;
2268 table
->MemoryACPILevel
.RttEnable
= 0;
2273 static int tonga_find_boot_level(struct tonga_single_dpm_table
*table
, uint32_t value
, uint32_t *boot_level
)
2278 for (i
= 0; i
< table
->count
; i
++) {
2279 if (value
== table
->dpm_levels
[i
].value
) {
2287 static int tonga_populate_smc_boot_level(struct pp_hwmgr
*hwmgr
,
2288 SMU72_Discrete_DpmTable
*table
)
2291 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2293 table
->GraphicsBootLevel
= 0; /* 0 == DPM[0] (low), etc. */
2294 table
->MemoryBootLevel
= 0; /* 0 == DPM[0] (low), etc. */
2296 /* find boot level from dpm table*/
2297 result
= tonga_find_boot_level(&(data
->dpm_table
.sclk_table
),
2298 data
->vbios_boot_state
.sclk_bootup_value
,
2299 (uint32_t *)&(data
->smc_state_table
.GraphicsBootLevel
));
2302 data
->smc_state_table
.GraphicsBootLevel
= 0;
2303 printk(KERN_ERR
"[ powerplay ] VBIOS did not find boot engine clock value \
2304 in dependency table. Using Graphics DPM level 0!");
2308 result
= tonga_find_boot_level(&(data
->dpm_table
.mclk_table
),
2309 data
->vbios_boot_state
.mclk_bootup_value
,
2310 (uint32_t *)&(data
->smc_state_table
.MemoryBootLevel
));
2313 data
->smc_state_table
.MemoryBootLevel
= 0;
2314 printk(KERN_ERR
"[ powerplay ] VBIOS did not find boot engine clock value \
2315 in dependency table. Using Memory DPM level 0!");
2319 table
->BootVoltage
.Vddc
=
2320 tonga_get_voltage_id(&(data
->vddc_voltage_table
),
2321 data
->vbios_boot_state
.vddc_bootup_value
);
2322 table
->BootVoltage
.VddGfx
=
2323 tonga_get_voltage_id(&(data
->vddgfx_voltage_table
),
2324 data
->vbios_boot_state
.vddgfx_bootup_value
);
2325 table
->BootVoltage
.Vddci
=
2326 tonga_get_voltage_id(&(data
->vddci_voltage_table
),
2327 data
->vbios_boot_state
.vddci_bootup_value
);
2328 table
->BootMVdd
= data
->vbios_boot_state
.mvdd_bootup_value
;
2330 CONVERT_FROM_HOST_TO_SMC_US(table
->BootMVdd
);
2337 * Calculates the SCLK dividers using the provided engine clock
2339 * @param hwmgr the address of the hardware manager
2340 * @param engine_clock the engine clock to use to populate the structure
2341 * @param sclk the SMC SCLK structure to be populated
2343 int tonga_calculate_sclk_params(struct pp_hwmgr
*hwmgr
,
2344 uint32_t engine_clock
, SMU72_Discrete_GraphicsLevel
*sclk
)
2346 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2347 pp_atomctrl_clock_dividers_vi dividers
;
2348 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
2349 uint32_t spll_func_cntl_3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
2350 uint32_t spll_func_cntl_4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
2351 uint32_t cg_spll_spread_spectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
2352 uint32_t cg_spll_spread_spectrum_2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
2353 uint32_t reference_clock
;
2354 uint32_t reference_divider
;
2358 /* get the engine clock dividers for this clock value*/
2359 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
, engine_clock
, ÷rs
);
2361 PP_ASSERT_WITH_CODE(result
== 0,
2362 "Error retrieving Engine Clock dividers from VBIOS.", return result
);
2364 /* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/
2365 reference_clock
= atomctrl_get_reference_clock(hwmgr
);
2367 reference_divider
= 1 + dividers
.uc_pll_ref_div
;
2369 /* low 14 bits is fraction and high 12 bits is divider*/
2370 fbdiv
= dividers
.ul_fb_div
.ul_fb_divider
& 0x3FFFFFF;
2372 /* SPLL_FUNC_CNTL setup*/
2373 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2374 CG_SPLL_FUNC_CNTL
, SPLL_REF_DIV
, dividers
.uc_pll_ref_div
);
2375 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2376 CG_SPLL_FUNC_CNTL
, SPLL_PDIV_A
, dividers
.uc_pll_post_div
);
2378 /* SPLL_FUNC_CNTL_3 setup*/
2379 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
,
2380 CG_SPLL_FUNC_CNTL_3
, SPLL_FB_DIV
, fbdiv
);
2382 /* set to use fractional accumulation*/
2383 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
,
2384 CG_SPLL_FUNC_CNTL_3
, SPLL_DITHEN
, 1);
2386 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2387 PHM_PlatformCaps_EngineSpreadSpectrumSupport
)) {
2388 pp_atomctrl_internal_ss_info ss_info
;
2390 uint32_t vcoFreq
= engine_clock
* dividers
.uc_pll_post_div
;
2391 if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr
, vcoFreq
, &ss_info
)) {
2393 * ss_info.speed_spectrum_percentage -- in unit of 0.01%
2394 * ss_info.speed_spectrum_rate -- in unit of khz
2396 /* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */
2397 uint32_t clkS
= reference_clock
* 5 / (reference_divider
* ss_info
.speed_spectrum_rate
);
2399 /* clkv = 2 * D * fbdiv / NS */
2400 uint32_t clkV
= 4 * ss_info
.speed_spectrum_percentage
* fbdiv
/ (clkS
* 10000);
2402 cg_spll_spread_spectrum
=
2403 PHM_SET_FIELD(cg_spll_spread_spectrum
, CG_SPLL_SPREAD_SPECTRUM
, CLKS
, clkS
);
2404 cg_spll_spread_spectrum
=
2405 PHM_SET_FIELD(cg_spll_spread_spectrum
, CG_SPLL_SPREAD_SPECTRUM
, SSEN
, 1);
2406 cg_spll_spread_spectrum_2
=
2407 PHM_SET_FIELD(cg_spll_spread_spectrum_2
, CG_SPLL_SPREAD_SPECTRUM_2
, CLKV
, clkV
);
2411 sclk
->SclkFrequency
= engine_clock
;
2412 sclk
->CgSpllFuncCntl3
= spll_func_cntl_3
;
2413 sclk
->CgSpllFuncCntl4
= spll_func_cntl_4
;
2414 sclk
->SpllSpreadSpectrum
= cg_spll_spread_spectrum
;
2415 sclk
->SpllSpreadSpectrum2
= cg_spll_spread_spectrum_2
;
2416 sclk
->SclkDid
= (uint8_t)dividers
.pll_post_divider
;
2421 static uint8_t tonga_get_sleep_divider_id_from_clock(uint32_t engine_clock
,
2422 uint32_t min_engine_clock_in_sr
)
2425 uint32_t min
= max(min_engine_clock_in_sr
, (uint32_t)TONGA_MINIMUM_ENGINE_CLOCK
);
2427 PP_ASSERT_WITH_CODE((engine_clock
>= min
),
2428 "Engine clock can't satisfy stutter requirement!", return 0);
2430 for (i
= TONGA_MAX_DEEPSLEEP_DIVIDER_ID
;; i
--) {
2431 temp
= engine_clock
>> i
;
2433 if(temp
>= min
|| i
== 0)
2440 * Populates single SMC SCLK structure using the provided engine clock
2442 * @param hwmgr the address of the hardware manager
2443 * @param engine_clock the engine clock to use to populate the structure
2444 * @param sclk the SMC SCLK structure to be populated
2446 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
)
2451 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2452 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2454 result
= tonga_calculate_sclk_params(hwmgr
, engine_clock
, graphic_level
);
2457 /* populate graphics levels*/
2458 result
= tonga_get_dependecy_volt_by_clk(hwmgr
,
2459 pptable_info
->vdd_dep_on_sclk
, engine_clock
,
2460 &graphic_level
->MinVoltage
, &mvdd
);
2461 PP_ASSERT_WITH_CODE((0 == result
),
2462 "can not find VDDC voltage value for VDDC \
2463 engine clock dependency table", return result
);
2465 /* SCLK frequency in units of 10KHz*/
2466 graphic_level
->SclkFrequency
= engine_clock
;
2468 /* Indicates maximum activity level for this performance level. 50% for now*/
2469 graphic_level
->ActivityLevel
= sclk_activity_level_threshold
;
2471 graphic_level
->CcPwrDynRm
= 0;
2472 graphic_level
->CcPwrDynRm1
= 0;
2473 /* this level can be used if activity is high enough.*/
2474 graphic_level
->EnabledForActivity
= 0;
2475 /* this level can be used for throttling.*/
2476 graphic_level
->EnabledForThrottle
= 1;
2477 graphic_level
->UpHyst
= 0;
2478 graphic_level
->DownHyst
= 0;
2479 graphic_level
->VoltageDownHyst
= 0;
2480 graphic_level
->PowerThrottle
= 0;
2482 threshold
= engine_clock
* data
->fast_watemark_threshold
/ 100;
2484 *get the DAL clock. do it in funture.
2485 PECI_GetMinClockSettings(hwmgr->peci, &minClocks);
2486 data->display_timing.min_clock_insr = minClocks.engineClockInSR;
2488 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2489 PHM_PlatformCaps_SclkDeepSleep
))
2490 graphic_level
->DeepSleepDivId
=
2491 tonga_get_sleep_divider_id_from_clock(engine_clock
,
2492 data
->display_timing
.min_clock_insr
);
2494 /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
2495 graphic_level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2498 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVoltage);*/
2499 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases);*/
2500 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->SclkFrequency
);
2501 CONVERT_FROM_HOST_TO_SMC_US(graphic_level
->ActivityLevel
);
2502 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CgSpllFuncCntl3
);
2503 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CgSpllFuncCntl4
);
2504 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->SpllSpreadSpectrum
);
2505 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->SpllSpreadSpectrum2
);
2506 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CcPwrDynRm
);
2507 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CcPwrDynRm1
);
2514 * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
2516 * @param hwmgr the address of the hardware manager
2518 static int tonga_populate_all_graphic_levels(struct pp_hwmgr
*hwmgr
)
2520 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2521 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2522 struct tonga_dpm_table
*dpm_table
= &data
->dpm_table
;
2523 phm_ppt_v1_pcie_table
*pcie_table
= pptable_info
->pcie_table
;
2524 uint8_t pcie_entry_count
= (uint8_t) data
->dpm_table
.pcie_speed_table
.count
;
2526 uint32_t level_array_adress
= data
->dpm_table_start
+
2527 offsetof(SMU72_Discrete_DpmTable
, GraphicsLevel
);
2528 uint32_t level_array_size
= sizeof(SMU72_Discrete_GraphicsLevel
) *
2529 SMU72_MAX_LEVELS_GRAPHICS
; /* 64 -> long; 32 -> int*/
2530 SMU72_Discrete_GraphicsLevel
*levels
= data
->smc_state_table
.GraphicsLevel
;
2531 uint32_t i
, maxEntry
;
2532 uint8_t highest_pcie_level_enabled
= 0, lowest_pcie_level_enabled
= 0, mid_pcie_level_enabled
= 0, count
= 0;
2533 PECI_RegistryValue reg_value
;
2534 memset(levels
, 0x00, level_array_size
);
2536 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
2537 result
= tonga_populate_single_graphic_level(hwmgr
,
2538 dpm_table
->sclk_table
.dpm_levels
[i
].value
,
2539 (uint16_t)data
->activity_target
[i
],
2540 &(data
->smc_state_table
.GraphicsLevel
[i
]));
2545 /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
2547 data
->smc_state_table
.GraphicsLevel
[i
].DeepSleepDivId
= 0;
2552 data
->smc_state_table
.GraphicsLevel
[0].UpHyst
= (uint8_t)reg_value
;
2558 data
->smc_state_table
.GraphicsLevel
[1].UpHyst
= (uint8_t)reg_value
;
2562 /* Only enable level 0 for now. */
2563 data
->smc_state_table
.GraphicsLevel
[0].EnabledForActivity
= 1;
2565 /* set highest level watermark to high */
2566 if (dpm_table
->sclk_table
.count
> 1)
2567 data
->smc_state_table
.GraphicsLevel
[dpm_table
->sclk_table
.count
-1].DisplayWatermark
=
2568 PPSMC_DISPLAY_WATERMARK_HIGH
;
2570 data
->smc_state_table
.GraphicsDpmLevelCount
=
2571 (uint8_t)dpm_table
->sclk_table
.count
;
2572 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
=
2573 tonga_get_dpm_level_enable_mask_value(&dpm_table
->sclk_table
);
2575 if (pcie_table
!= NULL
) {
2576 PP_ASSERT_WITH_CODE((pcie_entry_count
>= 1),
2577 "There must be 1 or more PCIE levels defined in PPTable.", return -1);
2578 maxEntry
= pcie_entry_count
- 1; /* for indexing, we need to decrement by 1.*/
2579 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
2580 data
->smc_state_table
.GraphicsLevel
[i
].pcieDpmLevel
=
2581 (uint8_t) ((i
< maxEntry
) ? i
: maxEntry
);
2584 if (0 == data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
)
2585 printk(KERN_ERR
"[ powerplay ] Pcie Dpm Enablemask is 0!");
2587 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
2588 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2589 (1<<(highest_pcie_level_enabled
+1))) != 0)) {
2590 highest_pcie_level_enabled
++;
2593 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
2594 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2595 (1<<lowest_pcie_level_enabled
)) == 0)) {
2596 lowest_pcie_level_enabled
++;
2599 while ((count
< highest_pcie_level_enabled
) &&
2600 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2601 (1<<(lowest_pcie_level_enabled
+1+count
))) == 0)) {
2604 mid_pcie_level_enabled
= (lowest_pcie_level_enabled
+1+count
) < highest_pcie_level_enabled
?
2605 (lowest_pcie_level_enabled
+1+count
) : highest_pcie_level_enabled
;
2608 /* set pcieDpmLevel to highest_pcie_level_enabled*/
2609 for (i
= 2; i
< dpm_table
->sclk_table
.count
; i
++) {
2610 data
->smc_state_table
.GraphicsLevel
[i
].pcieDpmLevel
= highest_pcie_level_enabled
;
2613 /* set pcieDpmLevel to lowest_pcie_level_enabled*/
2614 data
->smc_state_table
.GraphicsLevel
[0].pcieDpmLevel
= lowest_pcie_level_enabled
;
2616 /* set pcieDpmLevel to mid_pcie_level_enabled*/
2617 data
->smc_state_table
.GraphicsLevel
[1].pcieDpmLevel
= mid_pcie_level_enabled
;
2619 /* level count will send to smc once at init smc table and never change*/
2620 result
= tonga_copy_bytes_to_smc(hwmgr
->smumgr
, level_array_adress
, (uint8_t *)levels
, (uint32_t)level_array_size
, data
->sram_end
);
2629 * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
2631 * @param hwmgr the address of the hardware manager
2634 static int tonga_populate_all_memory_levels(struct pp_hwmgr
*hwmgr
)
2636 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2637 struct tonga_dpm_table
*dpm_table
= &data
->dpm_table
;
2639 /* populate MCLK dpm table to SMU7 */
2640 uint32_t level_array_adress
= data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
, MemoryLevel
);
2641 uint32_t level_array_size
= sizeof(SMU72_Discrete_MemoryLevel
) * SMU72_MAX_LEVELS_MEMORY
;
2642 SMU72_Discrete_MemoryLevel
*levels
= data
->smc_state_table
.MemoryLevel
;
2645 memset(levels
, 0x00, level_array_size
);
2647 for (i
= 0; i
< dpm_table
->mclk_table
.count
; i
++) {
2648 PP_ASSERT_WITH_CODE((0 != dpm_table
->mclk_table
.dpm_levels
[i
].value
),
2649 "can not populate memory level as memory clock is zero", return -1);
2650 result
= tonga_populate_single_memory_level(hwmgr
, dpm_table
->mclk_table
.dpm_levels
[i
].value
,
2651 &(data
->smc_state_table
.MemoryLevel
[i
]));
2657 /* Only enable level 0 for now.*/
2658 data
->smc_state_table
.MemoryLevel
[0].EnabledForActivity
= 1;
2661 * in order to prevent MC activity from stutter mode to push DPM up.
2662 * the UVD change complements this by putting the MCLK in a higher state
2663 * by default such that we are not effected by up threshold or and MCLK DPM latency.
2665 data
->smc_state_table
.MemoryLevel
[0].ActivityLevel
= 0x1F;
2666 CONVERT_FROM_HOST_TO_SMC_US(data
->smc_state_table
.MemoryLevel
[0].ActivityLevel
);
2668 data
->smc_state_table
.MemoryDpmLevelCount
= (uint8_t)dpm_table
->mclk_table
.count
;
2669 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&dpm_table
->mclk_table
);
2670 /* set highest level watermark to high*/
2671 data
->smc_state_table
.MemoryLevel
[dpm_table
->mclk_table
.count
-1].DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_HIGH
;
2673 /* level count will send to smc once at init smc table and never change*/
2674 result
= tonga_copy_bytes_to_smc(hwmgr
->smumgr
,
2675 level_array_adress
, (uint8_t *)levels
, (uint32_t)level_array_size
, data
->sram_end
);
2684 struct TONGA_DLL_SPEED_SETTING
{
2685 uint16_t Min
; /* Minimum Data Rate*/
2686 uint16_t Max
; /* Maximum Data Rate*/
2687 uint32_t dll_speed
; /* The desired DLL_SPEED setting*/
2690 static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr
*hwmgr
)
2695 /* ---------------------------------------- ULV related functions ----------------------------------------------------*/
2698 static int tonga_reset_single_dpm_table(
2699 struct pp_hwmgr
*hwmgr
,
2700 struct tonga_single_dpm_table
*dpm_table
,
2704 if (!(count
<= MAX_REGULAR_DPM_NUMBER
))
2705 printk(KERN_ERR
"[ powerplay ] Fatal error, can not set up single DPM \
2706 table entries to exceed max number! \n");
2708 dpm_table
->count
= count
;
2709 for (i
= 0; i
< MAX_REGULAR_DPM_NUMBER
; i
++) {
2710 dpm_table
->dpm_levels
[i
].enabled
= false;
2716 static void tonga_setup_pcie_table_entry(
2717 struct tonga_single_dpm_table
*dpm_table
,
2718 uint32_t index
, uint32_t pcie_gen
,
2719 uint32_t pcie_lanes
)
2721 dpm_table
->dpm_levels
[index
].value
= pcie_gen
;
2722 dpm_table
->dpm_levels
[index
].param1
= pcie_lanes
;
2723 dpm_table
->dpm_levels
[index
].enabled
= true;
2726 static int tonga_setup_default_pcie_tables(struct pp_hwmgr
*hwmgr
)
2728 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2729 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2730 phm_ppt_v1_pcie_table
*pcie_table
= pptable_info
->pcie_table
;
2731 uint32_t i
, maxEntry
;
2733 if (data
->use_pcie_performance_levels
&& !data
->use_pcie_power_saving_levels
) {
2734 data
->pcie_gen_power_saving
= data
->pcie_gen_performance
;
2735 data
->pcie_lane_power_saving
= data
->pcie_lane_performance
;
2736 } else if (!data
->use_pcie_performance_levels
&& data
->use_pcie_power_saving_levels
) {
2737 data
->pcie_gen_performance
= data
->pcie_gen_power_saving
;
2738 data
->pcie_lane_performance
= data
->pcie_lane_power_saving
;
2741 tonga_reset_single_dpm_table(hwmgr
, &data
->dpm_table
.pcie_speed_table
, SMU72_MAX_LEVELS_LINK
);
2743 if (pcie_table
!= NULL
) {
2745 * maxEntry is used to make sure we reserve one PCIE level for boot level (fix for A+A PSPP issue).
2746 * If PCIE table from PPTable have ULV entry + 8 entries, then ignore the last entry.
2748 maxEntry
= (SMU72_MAX_LEVELS_LINK
< pcie_table
->count
) ?
2749 SMU72_MAX_LEVELS_LINK
: pcie_table
->count
;
2750 for (i
= 1; i
< maxEntry
; i
++) {
2751 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, i
-1,
2752 get_pcie_gen_support(data
->pcie_gen_cap
, pcie_table
->entries
[i
].gen_speed
),
2753 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2755 data
->dpm_table
.pcie_speed_table
.count
= maxEntry
- 1;
2757 /* Hardcode Pcie Table */
2758 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 0,
2759 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Min_PCIEGen
),
2760 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2761 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 1,
2762 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Min_PCIEGen
),
2763 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2764 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 2,
2765 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2766 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2767 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 3,
2768 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2769 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2770 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 4,
2771 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2772 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2773 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 5,
2774 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2775 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2776 data
->dpm_table
.pcie_speed_table
.count
= 6;
2778 /* Populate last level for boot PCIE level, but do not increment count. */
2779 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
,
2780 data
->dpm_table
.pcie_speed_table
.count
,
2781 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Min_PCIEGen
),
2782 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2789 * This function is to initalize all DPM state tables for SMU7 based on the dependency table.
2790 * Dynamic state patching function will then trim these state tables to the allowed range based
2791 * on the power policy or external client requests, such as UVD request, etc.
2793 static int tonga_setup_default_dpm_tables(struct pp_hwmgr
*hwmgr
)
2795 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2796 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2799 phm_ppt_v1_clock_voltage_dependency_table
*allowed_vdd_sclk_table
=
2800 pptable_info
->vdd_dep_on_sclk
;
2801 phm_ppt_v1_clock_voltage_dependency_table
*allowed_vdd_mclk_table
=
2802 pptable_info
->vdd_dep_on_mclk
;
2804 PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table
!= NULL
,
2805 "SCLK dependency table is missing. This table is mandatory", return -1);
2806 PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table
->count
>= 1,
2807 "SCLK dependency table has to have is missing. This table is mandatory", return -1);
2809 PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table
!= NULL
,
2810 "MCLK dependency table is missing. This table is mandatory", return -1);
2811 PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table
->count
>= 1,
2812 "VMCLK dependency table has to have is missing. This table is mandatory", return -1);
2814 /* clear the state table to reset everything to default */
2815 memset(&(data
->dpm_table
), 0x00, sizeof(data
->dpm_table
));
2816 tonga_reset_single_dpm_table(hwmgr
, &data
->dpm_table
.sclk_table
, SMU72_MAX_LEVELS_GRAPHICS
);
2817 tonga_reset_single_dpm_table(hwmgr
, &data
->dpm_table
.mclk_table
, SMU72_MAX_LEVELS_MEMORY
);
2818 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.VddcTable, SMU72_MAX_LEVELS_VDDC); */
2819 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_gfx_table, SMU72_MAX_LEVELS_VDDGFX);*/
2820 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_ci_table, SMU72_MAX_LEVELS_VDDCI);*/
2821 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.mvdd_table, SMU72_MAX_LEVELS_MVDD);*/
2823 PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table
!= NULL
,
2824 "SCLK dependency table is missing. This table is mandatory", return -1);
2825 /* Initialize Sclk DPM table based on allow Sclk values*/
2826 data
->dpm_table
.sclk_table
.count
= 0;
2828 for (i
= 0; i
< allowed_vdd_sclk_table
->count
; i
++) {
2829 if (i
== 0 || data
->dpm_table
.sclk_table
.dpm_levels
[data
->dpm_table
.sclk_table
.count
-1].value
!=
2830 allowed_vdd_sclk_table
->entries
[i
].clk
) {
2831 data
->dpm_table
.sclk_table
.dpm_levels
[data
->dpm_table
.sclk_table
.count
].value
=
2832 allowed_vdd_sclk_table
->entries
[i
].clk
;
2833 data
->dpm_table
.sclk_table
.dpm_levels
[data
->dpm_table
.sclk_table
.count
].enabled
= true; /*(i==0) ? 1 : 0; to do */
2834 data
->dpm_table
.sclk_table
.count
++;
2838 PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table
!= NULL
,
2839 "MCLK dependency table is missing. This table is mandatory", return -1);
2840 /* Initialize Mclk DPM table based on allow Mclk values */
2841 data
->dpm_table
.mclk_table
.count
= 0;
2842 for (i
= 0; i
< allowed_vdd_mclk_table
->count
; i
++) {
2843 if (i
== 0 || data
->dpm_table
.mclk_table
.dpm_levels
[data
->dpm_table
.mclk_table
.count
-1].value
!=
2844 allowed_vdd_mclk_table
->entries
[i
].clk
) {
2845 data
->dpm_table
.mclk_table
.dpm_levels
[data
->dpm_table
.mclk_table
.count
].value
=
2846 allowed_vdd_mclk_table
->entries
[i
].clk
;
2847 data
->dpm_table
.mclk_table
.dpm_levels
[data
->dpm_table
.mclk_table
.count
].enabled
= true; /*(i==0) ? 1 : 0; */
2848 data
->dpm_table
.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 (atomctrl_get_pp_assign_pin(hwmgr
, VDDC_VRHOT_GPIO_PINID
,
3032 &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 (atomctrl_get_pp_assign_pin(hwmgr
, PP_AC_DC_SWITCH_GPIO_PINID
,
3046 &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
) && (atomctrl_get_pp_assign_pin(hwmgr
,
3069 THERMAL_INT_OUTPUT_GPIO_PINID
, &gpio_pin_assignment
))) {
3070 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3071 PHM_PlatformCaps_ThermalOutGPIO
);
3073 table
->ThermOutGpio
= gpio_pin_assignment
.uc_gpio_pin_bit_shift
;
3075 table
->ThermOutPolarity
=
3076 (0 == (cgs_read_register(hwmgr
->device
, mmGPIOPAD_A
) &
3077 (1 << gpio_pin_assignment
.uc_gpio_pin_bit_shift
))) ? 1:0;
3079 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_ONLY
;
3081 /* if required, combine VRHot/PCC with thermal out GPIO*/
3082 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3083 PHM_PlatformCaps_RegulatorHot
) &&
3084 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3085 PHM_PlatformCaps_CombinePCCWithThermalSignal
)){
3086 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_VRHOT
;
3089 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3090 PHM_PlatformCaps_ThermalOutGPIO
);
3092 table
->ThermOutGpio
= 17;
3093 table
->ThermOutPolarity
= 1;
3094 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_DISABLE
;
3097 for (i
= 0; i
< SMU72_MAX_ENTRIES_SMIO
; i
++) {
3098 table
->Smio
[i
] = PP_HOST_TO_SMC_UL(table
->Smio
[i
]);
3100 CONVERT_FROM_HOST_TO_SMC_UL(table
->SystemFlags
);
3101 CONVERT_FROM_HOST_TO_SMC_UL(table
->VRConfig
);
3102 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask1
);
3103 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask2
);
3104 CONVERT_FROM_HOST_TO_SMC_UL(table
->SclkStepSize
);
3105 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitHigh
);
3106 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitLow
);
3107 CONVERT_FROM_HOST_TO_SMC_US(table
->VoltageResponseTime
);
3108 CONVERT_FROM_HOST_TO_SMC_US(table
->PhaseResponseTime
);
3110 /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
3111 result
= tonga_copy_bytes_to_smc(hwmgr
->smumgr
, data
->dpm_table_start
+
3112 offsetof(SMU72_Discrete_DpmTable
, SystemFlags
),
3113 (uint8_t *)&(table
->SystemFlags
),
3114 sizeof(SMU72_Discrete_DpmTable
)-3 * sizeof(SMU72_PIDController
),
3117 PP_ASSERT_WITH_CODE(0 == result
,
3118 "Failed to upload dpm data to SMC memory!", return result
;);
3123 /* Look up the voltaged based on DAL's requested level. and then send the requested VDDC voltage to SMC*/
3124 static void tonga_apply_dal_minimum_voltage_request(struct pp_hwmgr
*hwmgr
)
3129 int tonga_upload_dpm_level_enable_mask(struct pp_hwmgr
*hwmgr
)
3131 PPSMC_Result result
;
3132 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3134 /* Apply minimum voltage based on DAL's request level */
3135 tonga_apply_dal_minimum_voltage_request(hwmgr
);
3137 if (0 == data
->sclk_dpm_key_disabled
) {
3138 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
3139 if (tonga_is_dpm_running(hwmgr
))
3140 printk(KERN_ERR
"[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
3142 if (0 != data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
3143 result
= smum_send_msg_to_smc_with_parameter(
3145 (PPSMC_Msg
)PPSMC_MSG_SCLKDPM_SetEnabledMask
,
3146 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
3147 PP_ASSERT_WITH_CODE((0 == result
),
3148 "Set Sclk Dpm enable Mask failed", return -1);
3152 if (0 == data
->mclk_dpm_key_disabled
) {
3153 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
3154 if (tonga_is_dpm_running(hwmgr
))
3155 printk(KERN_ERR
"[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
3157 if (0 != data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
) {
3158 result
= smum_send_msg_to_smc_with_parameter(
3160 (PPSMC_Msg
)PPSMC_MSG_MCLKDPM_SetEnabledMask
,
3161 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
);
3162 PP_ASSERT_WITH_CODE((0 == result
),
3163 "Set Mclk Dpm enable Mask failed", return -1);
3171 int tonga_force_dpm_highest(struct pp_hwmgr
*hwmgr
)
3173 uint32_t level
, tmp
;
3174 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3176 if (0 == data
->pcie_dpm_key_disabled
) {
3178 if (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
!= 0) {
3180 tmp
= data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
;
3185 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr
, level
)),
3186 "force highest pcie dpm state failed!", return -1);
3191 if (0 == data
->sclk_dpm_key_disabled
) {
3193 if (data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
!= 0) {
3195 tmp
= data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
;
3200 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr
, level
)),
3201 "force highest sclk dpm state failed!", return -1);
3202 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
,
3203 CGS_IND_REG__SMC
, TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_SCLK_INDEX
) != level
)
3204 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3205 Curr_Sclk_Index does not match the level \n");
3211 if (0 == data
->mclk_dpm_key_disabled
) {
3213 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
!= 0) {
3215 tmp
= data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
;
3220 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr
, level
)),
3221 "force highest mclk dpm state failed!", return -1);
3222 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3223 TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_MCLK_INDEX
) != level
)
3224 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3225 Curr_Mclk_Index does not match the level \n");
3234 * Find the MC microcode version and store it in the HwMgr struct
3236 * @param hwmgr the address of the powerplay hardware manager.
3239 int tonga_get_mc_microcode_version (struct pp_hwmgr
*hwmgr
)
3241 cgs_write_register(hwmgr
->device
, mmMC_SEQ_IO_DEBUG_INDEX
, 0x9F);
3243 hwmgr
->microcode_version_info
.MC
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_IO_DEBUG_DATA
);
3249 * Initialize Dynamic State Adjustment Rule Settings
3251 * @param hwmgr the address of the powerplay hardware manager.
3253 int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr
*hwmgr
)
3255 uint32_t table_size
;
3256 struct phm_clock_voltage_dependency_table
*table_clk_vlt
;
3257 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3259 hwmgr
->dyn_state
.mclk_sclk_ratio
= 4;
3260 hwmgr
->dyn_state
.sclk_mclk_delta
= 15000; /* 150 MHz */
3261 hwmgr
->dyn_state
.vddc_vddci_delta
= 200; /* 200mV */
3263 /* initialize vddc_dep_on_dal_pwrl table */
3264 table_size
= sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record
);
3265 table_clk_vlt
= kzalloc(table_size
, GFP_KERNEL
);
3267 if (NULL
== table_clk_vlt
) {
3268 printk(KERN_ERR
"[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
3271 table_clk_vlt
->count
= 4;
3272 table_clk_vlt
->entries
[0].clk
= PP_DAL_POWERLEVEL_ULTRALOW
;
3273 table_clk_vlt
->entries
[0].v
= 0;
3274 table_clk_vlt
->entries
[1].clk
= PP_DAL_POWERLEVEL_LOW
;
3275 table_clk_vlt
->entries
[1].v
= 720;
3276 table_clk_vlt
->entries
[2].clk
= PP_DAL_POWERLEVEL_NOMINAL
;
3277 table_clk_vlt
->entries
[2].v
= 810;
3278 table_clk_vlt
->entries
[3].clk
= PP_DAL_POWERLEVEL_PERFORMANCE
;
3279 table_clk_vlt
->entries
[3].v
= 900;
3280 pptable_info
->vddc_dep_on_dal_pwrl
= table_clk_vlt
;
3281 hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
= table_clk_vlt
;
3287 static int tonga_set_private_var_based_on_pptale(struct pp_hwmgr
*hwmgr
)
3289 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3290 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3292 phm_ppt_v1_clock_voltage_dependency_table
*allowed_sclk_vdd_table
=
3293 pptable_info
->vdd_dep_on_sclk
;
3294 phm_ppt_v1_clock_voltage_dependency_table
*allowed_mclk_vdd_table
=
3295 pptable_info
->vdd_dep_on_mclk
;
3297 PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table
!= NULL
,
3298 "VDD dependency on SCLK table is missing. \
3299 This table is mandatory", return -1);
3300 PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table
->count
>= 1,
3301 "VDD dependency on SCLK table has to have is missing. \
3302 This table is mandatory", return -1);
3304 PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table
!= NULL
,
3305 "VDD dependency on MCLK table is missing. \
3306 This table is mandatory", return -1);
3307 PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table
->count
>= 1,
3308 "VDD dependency on MCLK table has to have is missing. \
3309 This table is mandatory", return -1);
3311 data
->min_vddc_in_pp_table
= (uint16_t)allowed_sclk_vdd_table
->entries
[0].vddc
;
3312 data
->max_vddc_in_pp_table
= (uint16_t)allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].vddc
;
3314 pptable_info
->max_clock_voltage_on_ac
.sclk
=
3315 allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].clk
;
3316 pptable_info
->max_clock_voltage_on_ac
.mclk
=
3317 allowed_mclk_vdd_table
->entries
[allowed_mclk_vdd_table
->count
- 1].clk
;
3318 pptable_info
->max_clock_voltage_on_ac
.vddc
=
3319 allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].vddc
;
3320 pptable_info
->max_clock_voltage_on_ac
.vddci
=
3321 allowed_mclk_vdd_table
->entries
[allowed_mclk_vdd_table
->count
- 1].vddci
;
3323 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.sclk
=
3324 pptable_info
->max_clock_voltage_on_ac
.sclk
;
3325 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.mclk
=
3326 pptable_info
->max_clock_voltage_on_ac
.mclk
;
3327 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.vddc
=
3328 pptable_info
->max_clock_voltage_on_ac
.vddc
;
3329 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.vddci
=
3330 pptable_info
->max_clock_voltage_on_ac
.vddci
;
3335 int tonga_unforce_dpm_levels(struct pp_hwmgr
*hwmgr
)
3337 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3340 PP_ASSERT_WITH_CODE (!tonga_is_dpm_running(hwmgr
),
3341 "Trying to Unforce DPM when DPM is disabled. Returning without sending SMC message.",
3344 if (0 == data
->pcie_dpm_key_disabled
) {
3345 PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(
3347 PPSMC_MSG_PCIeDPM_UnForceLevel
)),
3348 "unforce pcie level failed!",
3352 result
= tonga_upload_dpm_level_enable_mask(hwmgr
);
3357 static uint32_t tonga_get_lowest_enable_level(
3358 struct pp_hwmgr
*hwmgr
, uint32_t level_mask
)
3362 while (0 == (level_mask
& (1 << level
)))
3368 static int tonga_force_dpm_lowest(struct pp_hwmgr
*hwmgr
)
3371 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3373 if (0 == data
->pcie_dpm_key_disabled
) {
3375 if (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
!= 0) {
3376 level
= tonga_get_lowest_enable_level(hwmgr
,
3377 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
);
3378 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr
, level
)),
3379 "force lowest pcie dpm state failed!", return -1);
3383 if (0 == data
->sclk_dpm_key_disabled
) {
3385 if (0 != data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
3386 level
= tonga_get_lowest_enable_level(hwmgr
,
3387 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
3389 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr
, level
)),
3390 "force sclk dpm state failed!", return -1);
3392 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
,
3393 CGS_IND_REG__SMC
, TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_SCLK_INDEX
) != level
)
3394 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3395 Curr_Sclk_Index does not match the level \n");
3399 if (0 == data
->mclk_dpm_key_disabled
) {
3401 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
!= 0) {
3402 level
= tonga_get_lowest_enable_level(hwmgr
,
3403 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
);
3404 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr
, level
)),
3405 "force lowest mclk dpm state failed!", return -1);
3406 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3407 TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_MCLK_INDEX
) != level
)
3408 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3409 Curr_Mclk_Index does not match the level \n");
3416 static int tonga_patch_voltage_dependency_tables_with_lookup_table(struct pp_hwmgr
*hwmgr
)
3420 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3421 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3423 phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
= pptable_info
->vdd_dep_on_sclk
;
3424 phm_ppt_v1_clock_voltage_dependency_table
*mclk_table
= pptable_info
->vdd_dep_on_mclk
;
3425 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
3427 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3428 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
3429 voltageId
= sclk_table
->entries
[entryId
].vddInd
;
3430 sclk_table
->entries
[entryId
].vddgfx
=
3431 pptable_info
->vddgfx_lookup_table
->entries
[voltageId
].us_vdd
;
3434 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
3435 voltageId
= sclk_table
->entries
[entryId
].vddInd
;
3436 sclk_table
->entries
[entryId
].vddc
=
3437 pptable_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
3441 for (entryId
= 0; entryId
< mclk_table
->count
; ++entryId
) {
3442 voltageId
= mclk_table
->entries
[entryId
].vddInd
;
3443 mclk_table
->entries
[entryId
].vddc
=
3444 pptable_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
3447 for (entryId
= 0; entryId
< mm_table
->count
; ++entryId
) {
3448 voltageId
= mm_table
->entries
[entryId
].vddcInd
;
3449 mm_table
->entries
[entryId
].vddc
=
3450 pptable_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
3457 static int tonga_calc_voltage_dependency_tables(struct pp_hwmgr
*hwmgr
)
3460 phm_ppt_v1_voltage_lookup_record v_record
;
3461 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3462 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3464 phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
= pptable_info
->vdd_dep_on_sclk
;
3465 phm_ppt_v1_clock_voltage_dependency_table
*mclk_table
= pptable_info
->vdd_dep_on_mclk
;
3467 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3468 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
3469 if (sclk_table
->entries
[entryId
].vdd_offset
& (1 << 15))
3470 v_record
.us_vdd
= sclk_table
->entries
[entryId
].vddgfx
+
3471 sclk_table
->entries
[entryId
].vdd_offset
- 0xFFFF;
3473 v_record
.us_vdd
= sclk_table
->entries
[entryId
].vddgfx
+
3474 sclk_table
->entries
[entryId
].vdd_offset
;
3476 sclk_table
->entries
[entryId
].vddc
=
3477 v_record
.us_cac_low
= v_record
.us_cac_mid
=
3478 v_record
.us_cac_high
= v_record
.us_vdd
;
3480 tonga_add_voltage(hwmgr
, pptable_info
->vddc_lookup_table
, &v_record
);
3483 for (entryId
= 0; entryId
< mclk_table
->count
; ++entryId
) {
3484 if (mclk_table
->entries
[entryId
].vdd_offset
& (1 << 15))
3485 v_record
.us_vdd
= mclk_table
->entries
[entryId
].vddc
+
3486 mclk_table
->entries
[entryId
].vdd_offset
- 0xFFFF;
3488 v_record
.us_vdd
= mclk_table
->entries
[entryId
].vddc
+
3489 mclk_table
->entries
[entryId
].vdd_offset
;
3491 mclk_table
->entries
[entryId
].vddgfx
= v_record
.us_cac_low
=
3492 v_record
.us_cac_mid
= v_record
.us_cac_high
= v_record
.us_vdd
;
3493 tonga_add_voltage(hwmgr
, pptable_info
->vddgfx_lookup_table
, &v_record
);
3501 static int tonga_calc_mm_voltage_dependency_table(struct pp_hwmgr
*hwmgr
)
3504 phm_ppt_v1_voltage_lookup_record v_record
;
3505 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3506 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3507 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
3509 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3510 for (entryId
= 0; entryId
< mm_table
->count
; entryId
++) {
3511 if (mm_table
->entries
[entryId
].vddgfx_offset
& (1 << 15))
3512 v_record
.us_vdd
= mm_table
->entries
[entryId
].vddc
+
3513 mm_table
->entries
[entryId
].vddgfx_offset
- 0xFFFF;
3515 v_record
.us_vdd
= mm_table
->entries
[entryId
].vddc
+
3516 mm_table
->entries
[entryId
].vddgfx_offset
;
3518 /* Add the calculated VDDGFX to the VDDGFX lookup table */
3519 mm_table
->entries
[entryId
].vddgfx
= v_record
.us_cac_low
=
3520 v_record
.us_cac_mid
= v_record
.us_cac_high
= v_record
.us_vdd
;
3521 tonga_add_voltage(hwmgr
, pptable_info
->vddgfx_lookup_table
, &v_record
);
3529 * Change virtual leakage voltage to actual value.
3531 * @param hwmgr the address of the powerplay hardware manager.
3532 * @param pointer to changing voltage
3533 * @param pointer to leakage table
3535 static void tonga_patch_with_vdd_leakage(struct pp_hwmgr
*hwmgr
,
3536 uint16_t *voltage
, phw_tonga_leakage_voltage
*pLeakageTable
)
3538 uint32_t leakage_index
;
3540 /* search for leakage voltage ID 0xff01 ~ 0xff08 */
3541 for (leakage_index
= 0; leakage_index
< pLeakageTable
->count
; leakage_index
++) {
3542 /* if this voltage matches a leakage voltage ID */
3543 /* patch with actual leakage voltage */
3544 if (pLeakageTable
->leakage_id
[leakage_index
] == *voltage
) {
3545 *voltage
= pLeakageTable
->actual_voltage
[leakage_index
];
3550 if (*voltage
> ATOM_VIRTUAL_VOLTAGE_ID0
)
3551 printk(KERN_ERR
"[ powerplay ] Voltage value looks like a Leakage ID but it's not patched \n");
3555 * Patch voltage lookup table by EVV leakages.
3557 * @param hwmgr the address of the powerplay hardware manager.
3558 * @param pointer to voltage lookup table
3559 * @param pointer to leakage table
3562 static int tonga_patch_lookup_table_with_leakage(struct pp_hwmgr
*hwmgr
,
3563 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
3564 phw_tonga_leakage_voltage
*pLeakageTable
)
3568 for (i
= 0; i
< lookup_table
->count
; i
++) {
3569 tonga_patch_with_vdd_leakage(hwmgr
,
3570 &lookup_table
->entries
[i
].us_vdd
, pLeakageTable
);
3576 static int tonga_patch_clock_voltage_lomits_with_vddc_leakage(struct pp_hwmgr
*hwmgr
,
3577 phw_tonga_leakage_voltage
*pLeakageTable
, uint16_t *Vddc
)
3579 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3581 tonga_patch_with_vdd_leakage(hwmgr
, (uint16_t *)Vddc
, pLeakageTable
);
3582 hwmgr
->dyn_state
.max_clock_voltage_on_dc
.vddc
=
3583 pptable_info
->max_clock_voltage_on_dc
.vddc
;
3588 static int tonga_patch_clock_voltage_limits_with_vddgfx_leakage(
3589 struct pp_hwmgr
*hwmgr
, phw_tonga_leakage_voltage
*pLeakageTable
,
3592 tonga_patch_with_vdd_leakage(hwmgr
, (uint16_t *)Vddgfx
, pLeakageTable
);
3596 int tonga_sort_lookup_table(struct pp_hwmgr
*hwmgr
,
3597 phm_ppt_v1_voltage_lookup_table
*lookup_table
)
3599 uint32_t table_size
, i
, j
;
3600 phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record
;
3601 table_size
= lookup_table
->count
;
3603 PP_ASSERT_WITH_CODE(0 != lookup_table
->count
,
3604 "Lookup table is empty", return -1);
3606 /* Sorting voltages */
3607 for (i
= 0; i
< table_size
- 1; i
++) {
3608 for (j
= i
+ 1; j
> 0; j
--) {
3609 if (lookup_table
->entries
[j
].us_vdd
< lookup_table
->entries
[j
-1].us_vdd
) {
3610 tmp_voltage_lookup_record
= lookup_table
->entries
[j
-1];
3611 lookup_table
->entries
[j
-1] = lookup_table
->entries
[j
];
3612 lookup_table
->entries
[j
] = tmp_voltage_lookup_record
;
3620 static int tonga_complete_dependency_tables(struct pp_hwmgr
*hwmgr
)
3624 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
3625 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3627 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3628 tmp_result
= tonga_patch_lookup_table_with_leakage(hwmgr
,
3629 pptable_info
->vddgfx_lookup_table
, &(data
->vddcgfx_leakage
));
3630 if (tmp_result
!= 0)
3631 result
= tmp_result
;
3633 tmp_result
= tonga_patch_clock_voltage_limits_with_vddgfx_leakage(hwmgr
,
3634 &(data
->vddcgfx_leakage
), &pptable_info
->max_clock_voltage_on_dc
.vddgfx
);
3635 if (tmp_result
!= 0)
3636 result
= tmp_result
;
3638 tmp_result
= tonga_patch_lookup_table_with_leakage(hwmgr
,
3639 pptable_info
->vddc_lookup_table
, &(data
->vddc_leakage
));
3640 if (tmp_result
!= 0)
3641 result
= tmp_result
;
3643 tmp_result
= tonga_patch_clock_voltage_lomits_with_vddc_leakage(hwmgr
,
3644 &(data
->vddc_leakage
), &pptable_info
->max_clock_voltage_on_dc
.vddc
);
3645 if (tmp_result
!= 0)
3646 result
= tmp_result
;
3649 tmp_result
= tonga_patch_voltage_dependency_tables_with_lookup_table(hwmgr
);
3650 if (tmp_result
!= 0)
3651 result
= tmp_result
;
3653 tmp_result
= tonga_calc_voltage_dependency_tables(hwmgr
);
3654 if (tmp_result
!= 0)
3655 result
= tmp_result
;
3657 tmp_result
= tonga_calc_mm_voltage_dependency_table(hwmgr
);
3658 if (tmp_result
!= 0)
3659 result
= tmp_result
;
3661 tmp_result
= tonga_sort_lookup_table(hwmgr
, pptable_info
->vddgfx_lookup_table
);
3662 if (tmp_result
!= 0)
3663 result
= tmp_result
;
3665 tmp_result
= tonga_sort_lookup_table(hwmgr
, pptable_info
->vddc_lookup_table
);
3666 if (tmp_result
!= 0)
3667 result
= tmp_result
;
3672 int tonga_init_sclk_threshold(struct pp_hwmgr
*hwmgr
)
3674 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3675 data
->low_sclk_interrupt_threshold
= 0;
3680 int tonga_setup_asic_task(struct pp_hwmgr
*hwmgr
)
3682 int tmp_result
, result
= 0;
3684 tmp_result
= tonga_read_clock_registers(hwmgr
);
3685 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3686 "Failed to read clock registers!", result
= tmp_result
);
3688 tmp_result
= tonga_get_memory_type(hwmgr
);
3689 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3690 "Failed to get memory type!", result
= tmp_result
);
3692 tmp_result
= tonga_enable_acpi_power_management(hwmgr
);
3693 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3694 "Failed to enable ACPI power management!", result
= tmp_result
);
3696 tmp_result
= tonga_init_power_gate_state(hwmgr
);
3697 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3698 "Failed to init power gate state!", result
= tmp_result
);
3700 tmp_result
= tonga_get_mc_microcode_version(hwmgr
);
3701 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3702 "Failed to get MC microcode version!", result
= tmp_result
);
3704 tmp_result
= tonga_init_sclk_threshold(hwmgr
);
3705 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3706 "Failed to init sclk threshold!", result
= tmp_result
);
3712 * Enable voltage control
3714 * @param hwmgr the address of the powerplay hardware manager.
3717 int tonga_enable_voltage_control(struct pp_hwmgr
*hwmgr
)
3719 /* enable voltage control */
3720 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, VOLT_PWRMGT_EN
, 1);
3726 * Checks if we want to support voltage control
3728 * @param hwmgr the address of the powerplay hardware manager.
3730 bool cf_tonga_voltage_control(const struct pp_hwmgr
*hwmgr
)
3732 const struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
3734 return(TONGA_VOLTAGE_CONTROL_NONE
!= data
->voltage_control
);
3737 /*---------------------------MC----------------------------*/
3739 uint8_t tonga_get_memory_modile_index(struct pp_hwmgr
*hwmgr
)
3741 return (uint8_t) (0xFF & (cgs_read_register(hwmgr
->device
, mmBIOS_SCRATCH_4
) >> 16));
3744 bool tonga_check_s0_mc_reg_index(uint16_t inReg
, uint16_t *outReg
)
3749 case mmMC_SEQ_RAS_TIMING
:
3750 *outReg
= mmMC_SEQ_RAS_TIMING_LP
;
3753 case mmMC_SEQ_DLL_STBY
:
3754 *outReg
= mmMC_SEQ_DLL_STBY_LP
;
3757 case mmMC_SEQ_G5PDX_CMD0
:
3758 *outReg
= mmMC_SEQ_G5PDX_CMD0_LP
;
3761 case mmMC_SEQ_G5PDX_CMD1
:
3762 *outReg
= mmMC_SEQ_G5PDX_CMD1_LP
;
3765 case mmMC_SEQ_G5PDX_CTRL
:
3766 *outReg
= mmMC_SEQ_G5PDX_CTRL_LP
;
3769 case mmMC_SEQ_CAS_TIMING
:
3770 *outReg
= mmMC_SEQ_CAS_TIMING_LP
;
3773 case mmMC_SEQ_MISC_TIMING
:
3774 *outReg
= mmMC_SEQ_MISC_TIMING_LP
;
3777 case mmMC_SEQ_MISC_TIMING2
:
3778 *outReg
= mmMC_SEQ_MISC_TIMING2_LP
;
3781 case mmMC_SEQ_PMG_DVS_CMD
:
3782 *outReg
= mmMC_SEQ_PMG_DVS_CMD_LP
;
3785 case mmMC_SEQ_PMG_DVS_CTL
:
3786 *outReg
= mmMC_SEQ_PMG_DVS_CTL_LP
;
3789 case mmMC_SEQ_RD_CTL_D0
:
3790 *outReg
= mmMC_SEQ_RD_CTL_D0_LP
;
3793 case mmMC_SEQ_RD_CTL_D1
:
3794 *outReg
= mmMC_SEQ_RD_CTL_D1_LP
;
3797 case mmMC_SEQ_WR_CTL_D0
:
3798 *outReg
= mmMC_SEQ_WR_CTL_D0_LP
;
3801 case mmMC_SEQ_WR_CTL_D1
:
3802 *outReg
= mmMC_SEQ_WR_CTL_D1_LP
;
3805 case mmMC_PMG_CMD_EMRS
:
3806 *outReg
= mmMC_SEQ_PMG_CMD_EMRS_LP
;
3809 case mmMC_PMG_CMD_MRS
:
3810 *outReg
= mmMC_SEQ_PMG_CMD_MRS_LP
;
3813 case mmMC_PMG_CMD_MRS1
:
3814 *outReg
= mmMC_SEQ_PMG_CMD_MRS1_LP
;
3817 case mmMC_SEQ_PMG_TIMING
:
3818 *outReg
= mmMC_SEQ_PMG_TIMING_LP
;
3821 case mmMC_PMG_CMD_MRS2
:
3822 *outReg
= mmMC_SEQ_PMG_CMD_MRS2_LP
;
3825 case mmMC_SEQ_WR_CTL_2
:
3826 *outReg
= mmMC_SEQ_WR_CTL_2_LP
;
3837 int tonga_set_s0_mc_reg_index(phw_tonga_mc_reg_table
*table
)
3842 for (i
= 0; i
< table
->last
; i
++) {
3843 table
->mc_reg_address
[i
].s0
=
3844 tonga_check_s0_mc_reg_index(table
->mc_reg_address
[i
].s1
, &address
)
3845 ? address
: table
->mc_reg_address
[i
].s1
;
3850 int tonga_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table
*table
, phw_tonga_mc_reg_table
*ni_table
)
3854 PP_ASSERT_WITH_CODE((table
->last
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3855 "Invalid VramInfo table.", return -1);
3856 PP_ASSERT_WITH_CODE((table
->num_entries
<= MAX_AC_TIMING_ENTRIES
),
3857 "Invalid VramInfo table.", return -1);
3859 for (i
= 0; i
< table
->last
; i
++) {
3860 ni_table
->mc_reg_address
[i
].s1
= table
->mc_reg_address
[i
].s1
;
3862 ni_table
->last
= table
->last
;
3864 for (i
= 0; i
< table
->num_entries
; i
++) {
3865 ni_table
->mc_reg_table_entry
[i
].mclk_max
=
3866 table
->mc_reg_table_entry
[i
].mclk_max
;
3867 for (j
= 0; j
< table
->last
; j
++) {
3868 ni_table
->mc_reg_table_entry
[i
].mc_data
[j
] =
3869 table
->mc_reg_table_entry
[i
].mc_data
[j
];
3873 ni_table
->num_entries
= table
->num_entries
;
3879 * VBIOS omits some information to reduce size, we need to recover them here.
3880 * 1. when we see mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to mmMC_PMG_CMD_EMRS /_LP[15:0].
3881 * Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
3882 * 2. when we see mmMC_SEQ_RESERVE_M, bit[15:0] EMRS2, need to be write to mmMC_PMG_CMD_MRS1/_LP[15:0].
3883 * 3. need to set these data for each clock range
3885 * @param hwmgr the address of the powerplay hardware manager.
3886 * @param table the address of MCRegTable
3889 int tonga_set_mc_special_registers(struct pp_hwmgr
*hwmgr
, phw_tonga_mc_reg_table
*table
)
3893 const tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
3895 for (i
= 0, j
= table
->last
; i
< table
->last
; i
++) {
3896 PP_ASSERT_WITH_CODE((j
< SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3897 "Invalid VramInfo table.", return -1);
3898 switch (table
->mc_reg_address
[i
].s1
) {
3900 * mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to mmMC_PMG_CMD_EMRS /_LP[15:0].
3901 * Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
3903 case mmMC_SEQ_MISC1
:
3904 temp_reg
= cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_EMRS
);
3905 table
->mc_reg_address
[j
].s1
= mmMC_PMG_CMD_EMRS
;
3906 table
->mc_reg_address
[j
].s0
= mmMC_SEQ_PMG_CMD_EMRS_LP
;
3907 for (k
= 0; k
< table
->num_entries
; k
++) {
3908 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3909 ((temp_reg
& 0xffff0000)) |
3910 ((table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0xffff0000) >> 16);
3913 PP_ASSERT_WITH_CODE((j
< SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3914 "Invalid VramInfo table.", return -1);
3916 temp_reg
= cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS
);
3917 table
->mc_reg_address
[j
].s1
= mmMC_PMG_CMD_MRS
;
3918 table
->mc_reg_address
[j
].s0
= mmMC_SEQ_PMG_CMD_MRS_LP
;
3919 for (k
= 0; k
< table
->num_entries
; k
++) {
3920 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3921 (temp_reg
& 0xffff0000) |
3922 (table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0x0000ffff);
3924 if (!data
->is_memory_GDDR5
) {
3925 table
->mc_reg_table_entry
[k
].mc_data
[j
] |= 0x100;
3929 PP_ASSERT_WITH_CODE((j
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3930 "Invalid VramInfo table.", return -1);
3932 if (!data
->is_memory_GDDR5
) {
3933 table
->mc_reg_address
[j
].s1
= mmMC_PMG_AUTO_CMD
;
3934 table
->mc_reg_address
[j
].s0
= mmMC_PMG_AUTO_CMD
;
3935 for (k
= 0; k
< table
->num_entries
; k
++) {
3936 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3937 (table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0xffff0000) >> 16;
3940 PP_ASSERT_WITH_CODE((j
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3941 "Invalid VramInfo table.", return -1);
3946 case mmMC_SEQ_RESERVE_M
:
3947 temp_reg
= cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS1
);
3948 table
->mc_reg_address
[j
].s1
= mmMC_PMG_CMD_MRS1
;
3949 table
->mc_reg_address
[j
].s0
= mmMC_SEQ_PMG_CMD_MRS1_LP
;
3950 for (k
= 0; k
< table
->num_entries
; k
++) {
3951 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3952 (temp_reg
& 0xffff0000) |
3953 (table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0x0000ffff);
3956 PP_ASSERT_WITH_CODE((j
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3957 "Invalid VramInfo table.", return -1);
3971 int tonga_set_valid_flag(phw_tonga_mc_reg_table
*table
)
3974 for (i
= 0; i
< table
->last
; i
++) {
3975 for (j
= 1; j
< table
->num_entries
; j
++) {
3976 if (table
->mc_reg_table_entry
[j
-1].mc_data
[i
] !=
3977 table
->mc_reg_table_entry
[j
].mc_data
[i
]) {
3978 table
->validflag
|= (1<<i
);
3987 int tonga_initialize_mc_reg_table(struct pp_hwmgr
*hwmgr
)
3990 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3991 pp_atomctrl_mc_reg_table
*table
;
3992 phw_tonga_mc_reg_table
*ni_table
= &data
->tonga_mc_reg_table
;
3993 uint8_t module_index
= tonga_get_memory_modile_index(hwmgr
);
3995 table
= kzalloc(sizeof(pp_atomctrl_mc_reg_table
), GFP_KERNEL
);
4000 /* Program additional LP registers that are no longer programmed by VBIOS */
4001 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING
));
4002 cgs_write_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING
));
4003 cgs_write_register(hwmgr
->device
, mmMC_SEQ_DLL_STBY_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_DLL_STBY
));
4004 cgs_write_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD0_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD0
));
4005 cgs_write_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD1_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD1
));
4006 cgs_write_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CTRL_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CTRL
));
4007 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CMD_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CMD
));
4008 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CTL_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CTL
));
4009 cgs_write_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING
));
4010 cgs_write_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2
));
4011 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_EMRS_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_EMRS
));
4012 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_MRS_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS
));
4013 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_MRS1_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS1
));
4014 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D0_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D0
));
4015 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1
));
4016 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0
));
4017 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1
));
4018 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING
));
4019 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_MRS2_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS2
));
4020 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_2_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_2
));
4022 memset(table
, 0x00, sizeof(pp_atomctrl_mc_reg_table
));
4024 result
= atomctrl_initialize_mc_reg_table(hwmgr
, module_index
, table
);
4027 result
= tonga_copy_vbios_smc_reg_table(table
, ni_table
);
4030 tonga_set_s0_mc_reg_index(ni_table
);
4031 result
= tonga_set_mc_special_registers(hwmgr
, ni_table
);
4035 tonga_set_valid_flag(ni_table
);
4042 * Copy one arb setting to another and then switch the active set.
4043 * arbFreqSrc and arbFreqDest is one of the MC_CG_ARB_FREQ_Fx constants.
4045 int tonga_copy_and_switch_arb_sets(struct pp_hwmgr
*hwmgr
,
4046 uint32_t arbFreqSrc
, uint32_t arbFreqDest
)
4048 uint32_t mc_arb_dram_timing
;
4049 uint32_t mc_arb_dram_timing2
;
4050 uint32_t burst_time
;
4051 uint32_t mc_cg_config
;
4053 switch (arbFreqSrc
) {
4054 case MC_CG_ARB_FREQ_F0
:
4055 mc_arb_dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
4056 mc_arb_dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
4057 burst_time
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
);
4060 case MC_CG_ARB_FREQ_F1
:
4061 mc_arb_dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING_1
);
4062 mc_arb_dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2_1
);
4063 burst_time
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE1
);
4070 switch (arbFreqDest
) {
4071 case MC_CG_ARB_FREQ_F0
:
4072 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
, mc_arb_dram_timing
);
4073 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
, mc_arb_dram_timing2
);
4074 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
, burst_time
);
4077 case MC_CG_ARB_FREQ_F1
:
4078 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING_1
, mc_arb_dram_timing
);
4079 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2_1
, mc_arb_dram_timing2
);
4080 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE1
, burst_time
);
4087 mc_cg_config
= cgs_read_register(hwmgr
->device
, mmMC_CG_CONFIG
);
4088 mc_cg_config
|= 0x0000000F;
4089 cgs_write_register(hwmgr
->device
, mmMC_CG_CONFIG
, mc_cg_config
);
4090 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_CG
, CG_ARB_REQ
, arbFreqDest
);
4096 * Initial switch from ARB F0->F1
4098 * @param hwmgr the address of the powerplay hardware manager.
4100 * This function is to be called from the SetPowerState table.
4102 int tonga_initial_switch_from_arb_f0_to_f1(struct pp_hwmgr
*hwmgr
)
4104 return tonga_copy_and_switch_arb_sets(hwmgr
, MC_CG_ARB_FREQ_F0
, MC_CG_ARB_FREQ_F1
);
4108 * Initialize the ARB DRAM timing table's index field.
4110 * @param hwmgr the address of the powerplay hardware manager.
4113 int tonga_init_arb_table_index(struct pp_hwmgr
*hwmgr
)
4115 const tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4120 * This is a read-modify-write on the first byte of the ARB table.
4121 * The first byte in the SMU72_Discrete_MCArbDramTimingTable structure is the field 'current'.
4122 * This solution is ugly, but we never write the whole table only individual fields in it.
4123 * In reality this field should not be in that structure but in a soft register.
4125 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
4126 data
->arb_table_start
, &tmp
, data
->sram_end
);
4132 tmp
|= ((uint32_t)MC_CG_ARB_FREQ_F1
) << 24;
4134 return tonga_write_smc_sram_dword(hwmgr
->smumgr
,
4135 data
->arb_table_start
, tmp
, data
->sram_end
);
4138 int tonga_populate_mc_reg_address(struct pp_hwmgr
*hwmgr
, SMU72_Discrete_MCRegisters
*mc_reg_table
)
4140 const struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4144 for (i
= 0, j
= 0; j
< data
->tonga_mc_reg_table
.last
; j
++) {
4145 if (data
->tonga_mc_reg_table
.validflag
& 1<<j
) {
4146 PP_ASSERT_WITH_CODE(i
< SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
,
4147 "Index of mc_reg_table->address[] array out of boundary", return -1);
4148 mc_reg_table
->address
[i
].s0
=
4149 PP_HOST_TO_SMC_US(data
->tonga_mc_reg_table
.mc_reg_address
[j
].s0
);
4150 mc_reg_table
->address
[i
].s1
=
4151 PP_HOST_TO_SMC_US(data
->tonga_mc_reg_table
.mc_reg_address
[j
].s1
);
4156 mc_reg_table
->last
= (uint8_t)i
;
4161 /*convert register values from driver to SMC format */
4162 void tonga_convert_mc_registers(
4163 const phw_tonga_mc_reg_entry
* pEntry
,
4164 SMU72_Discrete_MCRegisterSet
*pData
,
4165 uint32_t numEntries
, uint32_t validflag
)
4169 for (i
= 0, j
= 0; j
< numEntries
; j
++) {
4170 if (validflag
& 1<<j
) {
4171 pData
->value
[i
] = PP_HOST_TO_SMC_UL(pEntry
->mc_data
[j
]);
4177 /* find the entry in the memory range table, then populate the value to SMC's tonga_mc_reg_table */
4178 int tonga_convert_mc_reg_table_entry_to_smc(
4179 struct pp_hwmgr
*hwmgr
,
4180 const uint32_t memory_clock
,
4181 SMU72_Discrete_MCRegisterSet
*mc_reg_table_data
4184 const tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4187 for (i
= 0; i
< data
->tonga_mc_reg_table
.num_entries
; i
++) {
4189 data
->tonga_mc_reg_table
.mc_reg_table_entry
[i
].mclk_max
) {
4194 if ((i
== data
->tonga_mc_reg_table
.num_entries
) && (i
> 0))
4197 tonga_convert_mc_registers(&data
->tonga_mc_reg_table
.mc_reg_table_entry
[i
],
4198 mc_reg_table_data
, data
->tonga_mc_reg_table
.last
, data
->tonga_mc_reg_table
.validflag
);
4203 int tonga_convert_mc_reg_table_to_smc(struct pp_hwmgr
*hwmgr
,
4204 SMU72_Discrete_MCRegisters
*mc_reg_table
)
4207 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4211 for (i
= 0; i
< data
->dpm_table
.mclk_table
.count
; i
++) {
4212 res
= tonga_convert_mc_reg_table_entry_to_smc(
4214 data
->dpm_table
.mclk_table
.dpm_levels
[i
].value
,
4215 &mc_reg_table
->data
[i
]
4225 int tonga_populate_initial_mc_reg_table(struct pp_hwmgr
*hwmgr
)
4228 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4230 memset(&data
->mc_reg_table
, 0x00, sizeof(SMU72_Discrete_MCRegisters
));
4231 result
= tonga_populate_mc_reg_address(hwmgr
, &(data
->mc_reg_table
));
4232 PP_ASSERT_WITH_CODE(0 == result
,
4233 "Failed to initialize MCRegTable for the MC register addresses!", return result
;);
4235 result
= tonga_convert_mc_reg_table_to_smc(hwmgr
, &data
->mc_reg_table
);
4236 PP_ASSERT_WITH_CODE(0 == result
,
4237 "Failed to initialize MCRegTable for driver state!", return result
;);
4239 return tonga_copy_bytes_to_smc(hwmgr
->smumgr
, data
->mc_reg_table_start
,
4240 (uint8_t *)&data
->mc_reg_table
, sizeof(SMU72_Discrete_MCRegisters
), data
->sram_end
);
4244 * Programs static screed detection parameters
4246 * @param hwmgr the address of the powerplay hardware manager.
4249 int tonga_program_static_screen_threshold_parameters(struct pp_hwmgr
*hwmgr
)
4251 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
4253 /* Set static screen threshold unit*/
4254 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
,
4255 CGS_IND_REG__SMC
, CG_STATIC_SCREEN_PARAMETER
, STATIC_SCREEN_THRESHOLD_UNIT
,
4256 data
->static_screen_threshold_unit
);
4257 /* Set static screen threshold*/
4258 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
,
4259 CGS_IND_REG__SMC
, CG_STATIC_SCREEN_PARAMETER
, STATIC_SCREEN_THRESHOLD
,
4260 data
->static_screen_threshold
);
4266 * Setup display gap for glitch free memory clock switching.
4268 * @param hwmgr the address of the powerplay hardware manager.
4271 int tonga_enable_display_gap(struct pp_hwmgr
*hwmgr
)
4273 uint32_t display_gap
= cgs_read_ind_register(hwmgr
->device
,
4274 CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
);
4276 display_gap
= PHM_SET_FIELD(display_gap
,
4277 CG_DISPLAY_GAP_CNTL
, DISP_GAP
, DISPLAY_GAP_IGNORE
);
4279 display_gap
= PHM_SET_FIELD(display_gap
,
4280 CG_DISPLAY_GAP_CNTL
, DISP_GAP_MCHG
, DISPLAY_GAP_VBLANK
);
4282 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4283 ixCG_DISPLAY_GAP_CNTL
, display_gap
);
4289 * Programs activity state transition voting clients
4291 * @param hwmgr the address of the powerplay hardware manager.
4294 int tonga_program_voting_clients(struct pp_hwmgr
*hwmgr
)
4296 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
4298 /* Clear reset for voting clients before enabling DPM */
4299 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
4300 SCLK_PWRMGT_CNTL
, RESET_SCLK_CNT
, 0);
4301 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
4302 SCLK_PWRMGT_CNTL
, RESET_BUSY_CNT
, 0);
4304 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4305 ixCG_FREQ_TRAN_VOTING_0
, data
->voting_rights_clients0
);
4306 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4307 ixCG_FREQ_TRAN_VOTING_1
, data
->voting_rights_clients1
);
4308 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4309 ixCG_FREQ_TRAN_VOTING_2
, data
->voting_rights_clients2
);
4310 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4311 ixCG_FREQ_TRAN_VOTING_3
, data
->voting_rights_clients3
);
4312 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4313 ixCG_FREQ_TRAN_VOTING_4
, data
->voting_rights_clients4
);
4314 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4315 ixCG_FREQ_TRAN_VOTING_5
, data
->voting_rights_clients5
);
4316 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4317 ixCG_FREQ_TRAN_VOTING_6
, data
->voting_rights_clients6
);
4318 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4319 ixCG_FREQ_TRAN_VOTING_7
, data
->voting_rights_clients7
);
4325 int tonga_enable_dpm_tasks(struct pp_hwmgr
*hwmgr
)
4327 int tmp_result
, result
= 0;
4329 tmp_result
= tonga_check_for_dpm_stopped(hwmgr
);
4331 if (cf_tonga_voltage_control(hwmgr
)) {
4332 tmp_result
= tonga_enable_voltage_control(hwmgr
);
4333 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4334 "Failed to enable voltage control!", result
= tmp_result
);
4336 tmp_result
= tonga_construct_voltage_tables(hwmgr
);
4337 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4338 "Failed to contruct voltage tables!", result
= tmp_result
);
4341 tmp_result
= tonga_initialize_mc_reg_table(hwmgr
);
4342 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4343 "Failed to initialize MC reg table!", result
= tmp_result
);
4345 tmp_result
= tonga_program_static_screen_threshold_parameters(hwmgr
);
4346 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4347 "Failed to program static screen threshold parameters!", result
= tmp_result
);
4349 tmp_result
= tonga_enable_display_gap(hwmgr
);
4350 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4351 "Failed to enable display gap!", result
= tmp_result
);
4353 tmp_result
= tonga_program_voting_clients(hwmgr
);
4354 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4355 "Failed to program voting clients!", result
= tmp_result
);
4357 tmp_result
= tonga_process_firmware_header(hwmgr
);
4358 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4359 "Failed to process firmware header!", result
= tmp_result
);
4361 tmp_result
= tonga_initial_switch_from_arb_f0_to_f1(hwmgr
);
4362 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4363 "Failed to initialize switch from ArbF0 to F1!", result
= tmp_result
);
4365 tmp_result
= tonga_init_smc_table(hwmgr
);
4366 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4367 "Failed to initialize SMC table!", result
= tmp_result
);
4369 tmp_result
= tonga_init_arb_table_index(hwmgr
);
4370 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4371 "Failed to initialize ARB table index!", result
= tmp_result
);
4373 tmp_result
= tonga_populate_initial_mc_reg_table(hwmgr
);
4374 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4375 "Failed to populate initialize MC Reg table!", result
= tmp_result
);
4377 tmp_result
= tonga_notify_smc_display_change(hwmgr
, false);
4378 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4379 "Failed to notify no display!", result
= tmp_result
);
4381 /* enable SCLK control */
4382 tmp_result
= tonga_enable_sclk_control(hwmgr
);
4383 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4384 "Failed to enable SCLK control!", result
= tmp_result
);
4387 tmp_result
= tonga_start_dpm(hwmgr
);
4388 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4389 "Failed to start DPM!", result
= tmp_result
);
4394 int tonga_disable_dpm_tasks(struct pp_hwmgr
*hwmgr
)
4396 int tmp_result
, result
= 0;
4398 tmp_result
= tonga_check_for_dpm_running(hwmgr
);
4399 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4400 "SMC is still running!", return 0);
4402 tmp_result
= tonga_stop_dpm(hwmgr
);
4403 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4404 "Failed to stop DPM!", result
= tmp_result
);
4406 tmp_result
= tonga_reset_to_default(hwmgr
);
4407 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4408 "Failed to reset to default!", result
= tmp_result
);
4413 int tonga_reset_asic_tasks(struct pp_hwmgr
*hwmgr
)
4417 result
= tonga_set_boot_state(hwmgr
);
4419 printk(KERN_ERR
"[ powerplay ] Failed to reset asic via set boot state! \n");
4424 int tonga_hwmgr_backend_fini(struct pp_hwmgr
*hwmgr
)
4426 return phm_hwmgr_backend_fini(hwmgr
);
4430 * Initializes the Volcanic Islands Hardware Manager
4432 * @param hwmgr the address of the powerplay hardware manager.
4433 * @return 1 if success; otherwise appropriate error code.
4435 int tonga_hwmgr_backend_init(struct pp_hwmgr
*hwmgr
)
4438 SMU72_Discrete_DpmTable
*table
= NULL
;
4440 pp_atomctrl_gpio_pin_assignment gpio_pin_assignment
;
4441 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4442 phw_tonga_ulv_parm
*ulv
;
4443 struct cgs_system_info sys_info
= {0};
4445 PP_ASSERT_WITH_CODE((NULL
!= hwmgr
),
4446 "Invalid Parameter!", return -1;);
4448 data
= kzalloc(sizeof(struct tonga_hwmgr
), GFP_KERNEL
);
4452 hwmgr
->backend
= data
;
4454 data
->dll_defaule_on
= false;
4455 data
->sram_end
= SMC_RAM_END
;
4457 data
->activity_target
[0] = PPTONGA_TARGETACTIVITY_DFLT
;
4458 data
->activity_target
[1] = PPTONGA_TARGETACTIVITY_DFLT
;
4459 data
->activity_target
[2] = PPTONGA_TARGETACTIVITY_DFLT
;
4460 data
->activity_target
[3] = PPTONGA_TARGETACTIVITY_DFLT
;
4461 data
->activity_target
[4] = PPTONGA_TARGETACTIVITY_DFLT
;
4462 data
->activity_target
[5] = PPTONGA_TARGETACTIVITY_DFLT
;
4463 data
->activity_target
[6] = PPTONGA_TARGETACTIVITY_DFLT
;
4464 data
->activity_target
[7] = PPTONGA_TARGETACTIVITY_DFLT
;
4466 data
->vddc_vddci_delta
= VDDC_VDDCI_DELTA
;
4467 data
->vddc_vddgfx_delta
= VDDC_VDDGFX_DELTA
;
4468 data
->mclk_activity_target
= PPTONGA_MCLK_TARGETACTIVITY_DFLT
;
4470 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4471 PHM_PlatformCaps_DisableVoltageIsland
);
4473 data
->sclk_dpm_key_disabled
= 0;
4474 data
->mclk_dpm_key_disabled
= 0;
4475 data
->pcie_dpm_key_disabled
= 0;
4476 data
->pcc_monitor_enabled
= 0;
4478 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4479 PHM_PlatformCaps_UnTabledHardwareInterface
);
4481 data
->gpio_debug
= 0;
4482 data
->engine_clock_data
= 0;
4483 data
->memory_clock_data
= 0;
4484 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4485 PHM_PlatformCaps_DynamicPatchPowerState
);
4487 /* need to set voltage control types before EVV patching*/
4488 data
->voltage_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4489 data
->vdd_ci_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4490 data
->vdd_gfx_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4491 data
->mvdd_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4492 data
->force_pcie_gen
= PP_PCIEGenInvalid
;
4494 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4495 VOLTAGE_TYPE_VDDC
, VOLTAGE_OBJ_SVID2
)) {
4496 data
->voltage_control
= TONGA_VOLTAGE_CONTROL_BY_SVID2
;
4499 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4500 PHM_PlatformCaps_ControlVDDGFX
)) {
4501 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4502 VOLTAGE_TYPE_VDDGFX
, VOLTAGE_OBJ_SVID2
)) {
4503 data
->vdd_gfx_control
= TONGA_VOLTAGE_CONTROL_BY_SVID2
;
4507 if (TONGA_VOLTAGE_CONTROL_NONE
== data
->vdd_gfx_control
) {
4508 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4509 PHM_PlatformCaps_ControlVDDGFX
);
4512 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4513 PHM_PlatformCaps_EnableMVDDControl
)) {
4514 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4515 VOLTAGE_TYPE_MVDDC
, VOLTAGE_OBJ_GPIO_LUT
)) {
4516 data
->mvdd_control
= TONGA_VOLTAGE_CONTROL_BY_GPIO
;
4520 if (TONGA_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
) {
4521 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4522 PHM_PlatformCaps_EnableMVDDControl
);
4525 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4526 PHM_PlatformCaps_ControlVDDCI
)) {
4527 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4528 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_GPIO_LUT
))
4529 data
->vdd_ci_control
= TONGA_VOLTAGE_CONTROL_BY_GPIO
;
4530 else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4531 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_SVID2
))
4532 data
->vdd_ci_control
= TONGA_VOLTAGE_CONTROL_BY_SVID2
;
4535 if (TONGA_VOLTAGE_CONTROL_NONE
== data
->vdd_ci_control
)
4536 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4537 PHM_PlatformCaps_ControlVDDCI
);
4539 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4540 PHM_PlatformCaps_TablelessHardwareInterface
);
4542 if (pptable_info
->cac_dtp_table
->usClockStretchAmount
!= 0)
4543 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4544 PHM_PlatformCaps_ClockStretcher
);
4546 /* Initializes DPM default values*/
4547 tonga_initialize_dpm_defaults(hwmgr
);
4549 /* Get leakage voltage based on leakage ID.*/
4550 PP_ASSERT_WITH_CODE((0 == tonga_get_evv_voltage(hwmgr
)),
4551 "Get EVV Voltage Failed. Abort Driver loading!", return -1);
4553 tonga_complete_dependency_tables(hwmgr
);
4555 /* Parse pptable data read from VBIOS*/
4556 tonga_set_private_var_based_on_pptale(hwmgr
);
4560 ulv
->ulv_supported
= false;
4562 /* Initalize Dynamic State Adjustment Rule Settings*/
4563 result
= tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr
);
4565 printk(KERN_ERR
"[ powerplay ] tonga_initializa_dynamic_state_adjustment_rule_settings failed!\n");
4566 data
->uvd_enabled
= false;
4568 table
= &(data
->smc_state_table
);
4571 * if ucGPIO_ID=VDDC_PCC_GPIO_PINID in GPIO_LUTable,
4572 * Peak Current Control feature is enabled and we should program PCC HW register
4574 if (atomctrl_get_pp_assign_pin(hwmgr
, VDDC_PCC_GPIO_PINID
, &gpio_pin_assignment
)) {
4575 uint32_t temp_reg
= cgs_read_ind_register(hwmgr
->device
,
4576 CGS_IND_REG__SMC
, ixCNB_PWRMGT_CNTL
);
4578 switch (gpio_pin_assignment
.uc_gpio_pin_bit_shift
) {
4580 temp_reg
= PHM_SET_FIELD(temp_reg
,
4581 CNB_PWRMGT_CNTL
, GNB_SLOW_MODE
, 0x1);
4584 temp_reg
= PHM_SET_FIELD(temp_reg
,
4585 CNB_PWRMGT_CNTL
, GNB_SLOW_MODE
, 0x2);
4588 temp_reg
= PHM_SET_FIELD(temp_reg
,
4589 CNB_PWRMGT_CNTL
, GNB_SLOW
, 0x1);
4592 temp_reg
= PHM_SET_FIELD(temp_reg
,
4593 CNB_PWRMGT_CNTL
, FORCE_NB_PS1
, 0x1);
4596 temp_reg
= PHM_SET_FIELD(temp_reg
,
4597 CNB_PWRMGT_CNTL
, DPM_ENABLED
, 0x1);
4600 printk(KERN_ERR
"[ powerplay ] Failed to setup PCC HW register! \
4601 Wrong GPIO assigned for VDDC_PCC_GPIO_PINID! \n");
4604 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4605 ixCNB_PWRMGT_CNTL
, temp_reg
);
4608 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4609 PHM_PlatformCaps_EnableSMU7ThermalManagement
);
4610 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4611 PHM_PlatformCaps_SMU7
);
4613 data
->vddc_phase_shed_control
= false;
4615 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4616 PHM_PlatformCaps_UVDPowerGating
);
4617 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4618 PHM_PlatformCaps_VCEPowerGating
);
4619 sys_info
.size
= sizeof(struct cgs_system_info
);
4620 sys_info
.info_id
= CGS_SYSTEM_INFO_PG_FLAGS
;
4621 result
= cgs_query_system_info(hwmgr
->device
, &sys_info
);
4623 if (sys_info
.value
& AMD_PG_SUPPORT_UVD
)
4624 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4625 PHM_PlatformCaps_UVDPowerGating
);
4626 if (sys_info
.value
& AMD_PG_SUPPORT_VCE
)
4627 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4628 PHM_PlatformCaps_VCEPowerGating
);
4632 data
->is_tlu_enabled
= false;
4633 hwmgr
->platform_descriptor
.hardwareActivityPerformanceLevels
=
4634 TONGA_MAX_HARDWARE_POWERLEVELS
;
4635 hwmgr
->platform_descriptor
.hardwarePerformanceLevels
= 2;
4636 hwmgr
->platform_descriptor
.minimumClocksReductionPercentage
= 50;
4638 sys_info
.size
= sizeof(struct cgs_system_info
);
4639 sys_info
.info_id
= CGS_SYSTEM_INFO_PCIE_GEN_INFO
;
4640 result
= cgs_query_system_info(hwmgr
->device
, &sys_info
);
4642 data
->pcie_gen_cap
= AMDGPU_DEFAULT_PCIE_GEN_MASK
;
4644 data
->pcie_gen_cap
= (uint32_t)sys_info
.value
;
4645 if (data
->pcie_gen_cap
& CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3
)
4646 data
->pcie_spc_cap
= 20;
4647 sys_info
.size
= sizeof(struct cgs_system_info
);
4648 sys_info
.info_id
= CGS_SYSTEM_INFO_PCIE_MLW
;
4649 result
= cgs_query_system_info(hwmgr
->device
, &sys_info
);
4651 data
->pcie_lane_cap
= AMDGPU_DEFAULT_PCIE_MLW_MASK
;
4653 data
->pcie_lane_cap
= (uint32_t)sys_info
.value
;
4655 /* Ignore return value in here, we are cleaning up a mess. */
4656 tonga_hwmgr_backend_fini(hwmgr
);
4662 static int tonga_force_dpm_level(struct pp_hwmgr
*hwmgr
,
4663 enum amd_dpm_forced_level level
)
4668 case AMD_DPM_FORCED_LEVEL_HIGH
:
4669 ret
= tonga_force_dpm_highest(hwmgr
);
4673 case AMD_DPM_FORCED_LEVEL_LOW
:
4674 ret
= tonga_force_dpm_lowest(hwmgr
);
4678 case AMD_DPM_FORCED_LEVEL_AUTO
:
4679 ret
= tonga_unforce_dpm_levels(hwmgr
);
4687 hwmgr
->dpm_level
= level
;
4691 static int tonga_apply_state_adjust_rules(struct pp_hwmgr
*hwmgr
,
4692 struct pp_power_state
*prequest_ps
,
4693 const struct pp_power_state
*pcurrent_ps
)
4695 struct tonga_power_state
*tonga_ps
=
4696 cast_phw_tonga_power_state(&prequest_ps
->hardware
);
4700 struct PP_Clocks minimum_clocks
= {0};
4701 bool disable_mclk_switching
;
4702 bool disable_mclk_switching_for_frame_lock
;
4703 struct cgs_display_info info
= {0};
4704 const struct phm_clock_and_voltage_limits
*max_limits
;
4706 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4707 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4710 int32_t stable_pstate_sclk
= 0, stable_pstate_mclk
= 0;
4712 data
->battery_state
= (PP_StateUILabel_Battery
== prequest_ps
->classification
.ui_label
);
4714 PP_ASSERT_WITH_CODE(tonga_ps
->performance_level_count
== 2,
4715 "VI should always have 2 performance levels",
4718 max_limits
= (PP_PowerSource_AC
== hwmgr
->power_source
) ?
4719 &(hwmgr
->dyn_state
.max_clock_voltage_on_ac
) :
4720 &(hwmgr
->dyn_state
.max_clock_voltage_on_dc
);
4722 if (PP_PowerSource_DC
== hwmgr
->power_source
) {
4723 for (i
= 0; i
< tonga_ps
->performance_level_count
; i
++) {
4724 if (tonga_ps
->performance_levels
[i
].memory_clock
> max_limits
->mclk
)
4725 tonga_ps
->performance_levels
[i
].memory_clock
= max_limits
->mclk
;
4726 if (tonga_ps
->performance_levels
[i
].engine_clock
> max_limits
->sclk
)
4727 tonga_ps
->performance_levels
[i
].engine_clock
= max_limits
->sclk
;
4731 tonga_ps
->vce_clocks
.EVCLK
= hwmgr
->vce_arbiter
.evclk
;
4732 tonga_ps
->vce_clocks
.ECCLK
= hwmgr
->vce_arbiter
.ecclk
;
4734 tonga_ps
->acp_clk
= hwmgr
->acp_arbiter
.acpclk
;
4736 cgs_get_active_displays_info(hwmgr
->device
, &info
);
4738 /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
4740 /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
4742 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
)) {
4744 max_limits
= &(hwmgr
->dyn_state
.max_clock_voltage_on_ac
);
4745 stable_pstate_sclk
= (max_limits
->sclk
* 75) / 100;
4747 for (count
= pptable_info
->vdd_dep_on_sclk
->count
-1; count
>= 0; count
--) {
4748 if (stable_pstate_sclk
>= pptable_info
->vdd_dep_on_sclk
->entries
[count
].clk
) {
4749 stable_pstate_sclk
= pptable_info
->vdd_dep_on_sclk
->entries
[count
].clk
;
4755 stable_pstate_sclk
= pptable_info
->vdd_dep_on_sclk
->entries
[0].clk
;
4757 stable_pstate_mclk
= max_limits
->mclk
;
4759 minimum_clocks
.engineClock
= stable_pstate_sclk
;
4760 minimum_clocks
.memoryClock
= stable_pstate_mclk
;
4763 if (minimum_clocks
.engineClock
< hwmgr
->gfx_arbiter
.sclk
)
4764 minimum_clocks
.engineClock
= hwmgr
->gfx_arbiter
.sclk
;
4766 if (minimum_clocks
.memoryClock
< hwmgr
->gfx_arbiter
.mclk
)
4767 minimum_clocks
.memoryClock
= hwmgr
->gfx_arbiter
.mclk
;
4769 tonga_ps
->sclk_threshold
= hwmgr
->gfx_arbiter
.sclk_threshold
;
4771 if (0 != hwmgr
->gfx_arbiter
.sclk_over_drive
) {
4772 PP_ASSERT_WITH_CODE((hwmgr
->gfx_arbiter
.sclk_over_drive
<= hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
),
4773 "Overdrive sclk exceeds limit",
4774 hwmgr
->gfx_arbiter
.sclk_over_drive
= hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
);
4776 if (hwmgr
->gfx_arbiter
.sclk_over_drive
>= hwmgr
->gfx_arbiter
.sclk
)
4777 tonga_ps
->performance_levels
[1].engine_clock
= hwmgr
->gfx_arbiter
.sclk_over_drive
;
4780 if (0 != hwmgr
->gfx_arbiter
.mclk_over_drive
) {
4781 PP_ASSERT_WITH_CODE((hwmgr
->gfx_arbiter
.mclk_over_drive
<= hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
),
4782 "Overdrive mclk exceeds limit",
4783 hwmgr
->gfx_arbiter
.mclk_over_drive
= hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
);
4785 if (hwmgr
->gfx_arbiter
.mclk_over_drive
>= hwmgr
->gfx_arbiter
.mclk
)
4786 tonga_ps
->performance_levels
[1].memory_clock
= hwmgr
->gfx_arbiter
.mclk_over_drive
;
4789 disable_mclk_switching_for_frame_lock
= phm_cap_enabled(
4790 hwmgr
->platform_descriptor
.platformCaps
,
4791 PHM_PlatformCaps_DisableMclkSwitchingForFrameLock
);
4793 disable_mclk_switching
= (1 < info
.display_count
) ||
4794 disable_mclk_switching_for_frame_lock
;
4796 sclk
= tonga_ps
->performance_levels
[0].engine_clock
;
4797 mclk
= tonga_ps
->performance_levels
[0].memory_clock
;
4799 if (disable_mclk_switching
)
4800 mclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
- 1].memory_clock
;
4802 if (sclk
< minimum_clocks
.engineClock
)
4803 sclk
= (minimum_clocks
.engineClock
> max_limits
->sclk
) ? max_limits
->sclk
: minimum_clocks
.engineClock
;
4805 if (mclk
< minimum_clocks
.memoryClock
)
4806 mclk
= (minimum_clocks
.memoryClock
> max_limits
->mclk
) ? max_limits
->mclk
: minimum_clocks
.memoryClock
;
4808 tonga_ps
->performance_levels
[0].engine_clock
= sclk
;
4809 tonga_ps
->performance_levels
[0].memory_clock
= mclk
;
4811 tonga_ps
->performance_levels
[1].engine_clock
=
4812 (tonga_ps
->performance_levels
[1].engine_clock
>= tonga_ps
->performance_levels
[0].engine_clock
) ?
4813 tonga_ps
->performance_levels
[1].engine_clock
:
4814 tonga_ps
->performance_levels
[0].engine_clock
;
4816 if (disable_mclk_switching
) {
4817 if (mclk
< tonga_ps
->performance_levels
[1].memory_clock
)
4818 mclk
= tonga_ps
->performance_levels
[1].memory_clock
;
4820 tonga_ps
->performance_levels
[0].memory_clock
= mclk
;
4821 tonga_ps
->performance_levels
[1].memory_clock
= mclk
;
4823 if (tonga_ps
->performance_levels
[1].memory_clock
< tonga_ps
->performance_levels
[0].memory_clock
)
4824 tonga_ps
->performance_levels
[1].memory_clock
= tonga_ps
->performance_levels
[0].memory_clock
;
4827 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
)) {
4828 for (i
=0; i
< tonga_ps
->performance_level_count
; i
++) {
4829 tonga_ps
->performance_levels
[i
].engine_clock
= stable_pstate_sclk
;
4830 tonga_ps
->performance_levels
[i
].memory_clock
= stable_pstate_mclk
;
4831 tonga_ps
->performance_levels
[i
].pcie_gen
= data
->pcie_gen_performance
.max
;
4832 tonga_ps
->performance_levels
[i
].pcie_lane
= data
->pcie_gen_performance
.max
;
4839 int tonga_get_power_state_size(struct pp_hwmgr
*hwmgr
)
4841 return sizeof(struct tonga_power_state
);
4844 static int tonga_dpm_get_mclk(struct pp_hwmgr
*hwmgr
, bool low
)
4846 struct pp_power_state
*ps
;
4847 struct tonga_power_state
*tonga_ps
;
4852 ps
= hwmgr
->request_ps
;
4857 tonga_ps
= cast_phw_tonga_power_state(&ps
->hardware
);
4860 return tonga_ps
->performance_levels
[0].memory_clock
;
4862 return tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].memory_clock
;
4865 static int tonga_dpm_get_sclk(struct pp_hwmgr
*hwmgr
, bool low
)
4867 struct pp_power_state
*ps
;
4868 struct tonga_power_state
*tonga_ps
;
4873 ps
= hwmgr
->request_ps
;
4878 tonga_ps
= cast_phw_tonga_power_state(&ps
->hardware
);
4881 return tonga_ps
->performance_levels
[0].engine_clock
;
4883 return tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].engine_clock
;
4886 static uint16_t tonga_get_current_pcie_speed(
4887 struct pp_hwmgr
*hwmgr
)
4889 uint32_t speed_cntl
= 0;
4891 speed_cntl
= cgs_read_ind_register(hwmgr
->device
,
4893 ixPCIE_LC_SPEED_CNTL
);
4894 return((uint16_t)PHM_GET_FIELD(speed_cntl
,
4895 PCIE_LC_SPEED_CNTL
, LC_CURRENT_DATA_RATE
));
4898 static int tonga_get_current_pcie_lane_number(
4899 struct pp_hwmgr
*hwmgr
)
4901 uint32_t link_width
;
4903 link_width
= PHM_READ_INDIRECT_FIELD(hwmgr
->device
,
4905 PCIE_LC_LINK_WIDTH_CNTL
,
4908 PP_ASSERT_WITH_CODE((7 >= link_width
),
4909 "Invalid PCIe lane width!", return 0);
4911 return decode_pcie_lane_width(link_width
);
4914 static int tonga_dpm_patch_boot_state(struct pp_hwmgr
*hwmgr
,
4915 struct pp_hw_power_state
*hw_ps
)
4917 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4918 struct tonga_power_state
*ps
= (struct tonga_power_state
*)hw_ps
;
4919 ATOM_FIRMWARE_INFO_V2_2
*fw_info
;
4922 int index
= GetIndexIntoMasterTable(DATA
, FirmwareInfo
);
4924 /* First retrieve the Boot clocks and VDDC from the firmware info table.
4925 * We assume here that fw_info is unchanged if this call fails.
4927 fw_info
= (ATOM_FIRMWARE_INFO_V2_2
*)cgs_atom_get_data_table(
4928 hwmgr
->device
, index
,
4929 &size
, &frev
, &crev
);
4931 /* During a test, there is no firmware info table. */
4934 /* Patch the state. */
4935 data
->vbios_boot_state
.sclk_bootup_value
= le32_to_cpu(fw_info
->ulDefaultEngineClock
);
4936 data
->vbios_boot_state
.mclk_bootup_value
= le32_to_cpu(fw_info
->ulDefaultMemoryClock
);
4937 data
->vbios_boot_state
.mvdd_bootup_value
= le16_to_cpu(fw_info
->usBootUpMVDDCVoltage
);
4938 data
->vbios_boot_state
.vddc_bootup_value
= le16_to_cpu(fw_info
->usBootUpVDDCVoltage
);
4939 data
->vbios_boot_state
.vddci_bootup_value
= le16_to_cpu(fw_info
->usBootUpVDDCIVoltage
);
4940 data
->vbios_boot_state
.pcie_gen_bootup_value
= tonga_get_current_pcie_speed(hwmgr
);
4941 data
->vbios_boot_state
.pcie_lane_bootup_value
=
4942 (uint16_t)tonga_get_current_pcie_lane_number(hwmgr
);
4944 /* set boot power state */
4945 ps
->performance_levels
[0].memory_clock
= data
->vbios_boot_state
.mclk_bootup_value
;
4946 ps
->performance_levels
[0].engine_clock
= data
->vbios_boot_state
.sclk_bootup_value
;
4947 ps
->performance_levels
[0].pcie_gen
= data
->vbios_boot_state
.pcie_gen_bootup_value
;
4948 ps
->performance_levels
[0].pcie_lane
= data
->vbios_boot_state
.pcie_lane_bootup_value
;
4953 static int tonga_get_pp_table_entry_callback_func(struct pp_hwmgr
*hwmgr
,
4954 void *state
, struct pp_power_state
*power_state
,
4955 void *pp_table
, uint32_t classification_flag
)
4957 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4959 struct tonga_power_state
*tonga_ps
=
4960 (struct tonga_power_state
*)(&(power_state
->hardware
));
4962 struct tonga_performance_level
*performance_level
;
4964 ATOM_Tonga_State
*state_entry
= (ATOM_Tonga_State
*)state
;
4966 ATOM_Tonga_POWERPLAYTABLE
*powerplay_table
=
4967 (ATOM_Tonga_POWERPLAYTABLE
*)pp_table
;
4969 ATOM_Tonga_SCLK_Dependency_Table
*sclk_dep_table
=
4970 (ATOM_Tonga_SCLK_Dependency_Table
*)
4971 (((unsigned long)powerplay_table
) +
4972 le16_to_cpu(powerplay_table
->usSclkDependencyTableOffset
));
4974 ATOM_Tonga_MCLK_Dependency_Table
*mclk_dep_table
=
4975 (ATOM_Tonga_MCLK_Dependency_Table
*)
4976 (((unsigned long)powerplay_table
) +
4977 le16_to_cpu(powerplay_table
->usMclkDependencyTableOffset
));
4979 /* The following fields are not initialized here: id orderedList allStatesList */
4980 power_state
->classification
.ui_label
=
4981 (le16_to_cpu(state_entry
->usClassification
) &
4982 ATOM_PPLIB_CLASSIFICATION_UI_MASK
) >>
4983 ATOM_PPLIB_CLASSIFICATION_UI_SHIFT
;
4984 power_state
->classification
.flags
= classification_flag
;
4985 /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
4987 power_state
->classification
.temporary_state
= false;
4988 power_state
->classification
.to_be_deleted
= false;
4990 power_state
->validation
.disallowOnDC
=
4991 (0 != (le32_to_cpu(state_entry
->ulCapsAndSettings
) & ATOM_Tonga_DISALLOW_ON_DC
));
4993 power_state
->pcie
.lanes
= 0;
4995 power_state
->display
.disableFrameModulation
= false;
4996 power_state
->display
.limitRefreshrate
= false;
4997 power_state
->display
.enableVariBright
=
4998 (0 != (le32_to_cpu(state_entry
->ulCapsAndSettings
) & ATOM_Tonga_ENABLE_VARIBRIGHT
));
5000 power_state
->validation
.supportedPowerLevels
= 0;
5001 power_state
->uvd_clocks
.VCLK
= 0;
5002 power_state
->uvd_clocks
.DCLK
= 0;
5003 power_state
->temperatures
.min
= 0;
5004 power_state
->temperatures
.max
= 0;
5006 performance_level
= &(tonga_ps
->performance_levels
5007 [tonga_ps
->performance_level_count
++]);
5009 PP_ASSERT_WITH_CODE(
5010 (tonga_ps
->performance_level_count
< SMU72_MAX_LEVELS_GRAPHICS
),
5011 "Performance levels exceeds SMC limit!",
5014 PP_ASSERT_WITH_CODE(
5015 (tonga_ps
->performance_level_count
<=
5016 hwmgr
->platform_descriptor
.hardwareActivityPerformanceLevels
),
5017 "Performance levels exceeds Driver limit!",
5020 /* Performance levels are arranged from low to high. */
5021 performance_level
->memory_clock
=
5022 le32_to_cpu(mclk_dep_table
->entries
[state_entry
->ucMemoryClockIndexLow
].ulMclk
);
5024 performance_level
->engine_clock
=
5025 le32_to_cpu(sclk_dep_table
->entries
[state_entry
->ucEngineClockIndexLow
].ulSclk
);
5027 performance_level
->pcie_gen
= get_pcie_gen_support(
5029 state_entry
->ucPCIEGenLow
);
5031 performance_level
->pcie_lane
= get_pcie_lane_support(
5032 data
->pcie_lane_cap
,
5033 state_entry
->ucPCIELaneHigh
);
5036 &(tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
++]);
5038 performance_level
->memory_clock
=
5039 le32_to_cpu(mclk_dep_table
->entries
[state_entry
->ucMemoryClockIndexHigh
].ulMclk
);
5041 performance_level
->engine_clock
=
5042 le32_to_cpu(sclk_dep_table
->entries
[state_entry
->ucEngineClockIndexHigh
].ulSclk
);
5044 performance_level
->pcie_gen
= get_pcie_gen_support(
5046 state_entry
->ucPCIEGenHigh
);
5048 performance_level
->pcie_lane
= get_pcie_lane_support(
5049 data
->pcie_lane_cap
,
5050 state_entry
->ucPCIELaneHigh
);
5055 static int tonga_get_pp_table_entry(struct pp_hwmgr
*hwmgr
,
5056 unsigned long entry_index
, struct pp_power_state
*ps
)
5059 struct tonga_power_state
*tonga_ps
;
5060 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5062 struct phm_ppt_v1_information
*table_info
=
5063 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
5065 struct phm_ppt_v1_clock_voltage_dependency_table
*dep_mclk_table
=
5066 table_info
->vdd_dep_on_mclk
;
5068 ps
->hardware
.magic
= PhwTonga_Magic
;
5070 tonga_ps
= cast_phw_tonga_power_state(&(ps
->hardware
));
5072 result
= tonga_get_powerplay_table_entry(hwmgr
, entry_index
, ps
,
5073 tonga_get_pp_table_entry_callback_func
);
5075 /* This is the earliest time we have all the dependency table and the VBIOS boot state
5076 * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
5077 * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
5079 if (dep_mclk_table
!= NULL
&& dep_mclk_table
->count
== 1) {
5080 if (dep_mclk_table
->entries
[0].clk
!=
5081 data
->vbios_boot_state
.mclk_bootup_value
)
5082 printk(KERN_ERR
"Single MCLK entry VDDCI/MCLK dependency table "
5083 "does not match VBIOS boot MCLK level");
5084 if (dep_mclk_table
->entries
[0].vddci
!=
5085 data
->vbios_boot_state
.vddci_bootup_value
)
5086 printk(KERN_ERR
"Single VDDCI entry VDDCI/MCLK dependency table "
5087 "does not match VBIOS boot VDDCI level");
5090 /* set DC compatible flag if this state supports DC */
5091 if (!ps
->validation
.disallowOnDC
)
5092 tonga_ps
->dc_compatible
= true;
5094 if (ps
->classification
.flags
& PP_StateClassificationFlag_ACPI
)
5095 data
->acpi_pcie_gen
= tonga_ps
->performance_levels
[0].pcie_gen
;
5096 else if (ps
->classification
.flags
& PP_StateClassificationFlag_Boot
) {
5097 if (data
->bacos
.best_match
== 0xffff) {
5098 /* For V.I. use boot state as base BACO state */
5099 data
->bacos
.best_match
= PP_StateClassificationFlag_Boot
;
5100 data
->bacos
.performance_level
= tonga_ps
->performance_levels
[0];
5104 tonga_ps
->uvd_clocks
.VCLK
= ps
->uvd_clocks
.VCLK
;
5105 tonga_ps
->uvd_clocks
.DCLK
= ps
->uvd_clocks
.DCLK
;
5110 switch (ps
->classification
.ui_label
) {
5111 case PP_StateUILabel_Performance
:
5112 data
->use_pcie_performance_levels
= true;
5114 for (i
= 0; i
< tonga_ps
->performance_level_count
; i
++) {
5115 if (data
->pcie_gen_performance
.max
<
5116 tonga_ps
->performance_levels
[i
].pcie_gen
)
5117 data
->pcie_gen_performance
.max
=
5118 tonga_ps
->performance_levels
[i
].pcie_gen
;
5120 if (data
->pcie_gen_performance
.min
>
5121 tonga_ps
->performance_levels
[i
].pcie_gen
)
5122 data
->pcie_gen_performance
.min
=
5123 tonga_ps
->performance_levels
[i
].pcie_gen
;
5125 if (data
->pcie_lane_performance
.max
<
5126 tonga_ps
->performance_levels
[i
].pcie_lane
)
5127 data
->pcie_lane_performance
.max
=
5128 tonga_ps
->performance_levels
[i
].pcie_lane
;
5130 if (data
->pcie_lane_performance
.min
>
5131 tonga_ps
->performance_levels
[i
].pcie_lane
)
5132 data
->pcie_lane_performance
.min
=
5133 tonga_ps
->performance_levels
[i
].pcie_lane
;
5136 case PP_StateUILabel_Battery
:
5137 data
->use_pcie_power_saving_levels
= true;
5139 for (i
= 0; i
< tonga_ps
->performance_level_count
; i
++) {
5140 if (data
->pcie_gen_power_saving
.max
<
5141 tonga_ps
->performance_levels
[i
].pcie_gen
)
5142 data
->pcie_gen_power_saving
.max
=
5143 tonga_ps
->performance_levels
[i
].pcie_gen
;
5145 if (data
->pcie_gen_power_saving
.min
>
5146 tonga_ps
->performance_levels
[i
].pcie_gen
)
5147 data
->pcie_gen_power_saving
.min
=
5148 tonga_ps
->performance_levels
[i
].pcie_gen
;
5150 if (data
->pcie_lane_power_saving
.max
<
5151 tonga_ps
->performance_levels
[i
].pcie_lane
)
5152 data
->pcie_lane_power_saving
.max
=
5153 tonga_ps
->performance_levels
[i
].pcie_lane
;
5155 if (data
->pcie_lane_power_saving
.min
>
5156 tonga_ps
->performance_levels
[i
].pcie_lane
)
5157 data
->pcie_lane_power_saving
.min
=
5158 tonga_ps
->performance_levels
[i
].pcie_lane
;
5169 tonga_print_current_perforce_level(struct pp_hwmgr
*hwmgr
, struct seq_file
*m
)
5171 uint32_t sclk
, mclk
, activity_percent
;
5173 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5175 smum_send_msg_to_smc(hwmgr
->smumgr
, (PPSMC_Msg
)(PPSMC_MSG_API_GetSclkFrequency
));
5177 sclk
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5179 smum_send_msg_to_smc(hwmgr
->smumgr
, (PPSMC_Msg
)(PPSMC_MSG_API_GetMclkFrequency
));
5181 mclk
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5182 seq_printf(m
, "\n [ mclk ]: %u MHz\n\n [ sclk ]: %u MHz\n", mclk
/100, sclk
/100);
5184 offset
= data
->soft_regs_start
+ offsetof(SMU72_SoftRegisters
, AverageGraphicsActivity
);
5185 activity_percent
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, offset
);
5186 activity_percent
+= 0x80;
5187 activity_percent
>>= 8;
5189 seq_printf(m
, "\n [GPU load]: %u%%\n\n", activity_percent
> 100 ? 100 : activity_percent
);
5191 seq_printf(m
, "uvd %sabled\n", data
->uvd_power_gated
? "dis" : "en");
5193 seq_printf(m
, "vce %sabled\n", data
->vce_power_gated
? "dis" : "en");
5196 static int tonga_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr
*hwmgr
, const void *input
)
5198 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5199 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5200 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5201 struct tonga_single_dpm_table
*psclk_table
= &(data
->dpm_table
.sclk_table
);
5202 uint32_t sclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].engine_clock
;
5203 struct tonga_single_dpm_table
*pmclk_table
= &(data
->dpm_table
.mclk_table
);
5204 uint32_t mclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].memory_clock
;
5205 struct PP_Clocks min_clocks
= {0};
5207 struct cgs_display_info info
= {0};
5209 data
->need_update_smu7_dpm_table
= 0;
5211 for (i
= 0; i
< psclk_table
->count
; i
++) {
5212 if (sclk
== psclk_table
->dpm_levels
[i
].value
)
5216 if (i
>= psclk_table
->count
)
5217 data
->need_update_smu7_dpm_table
|= DPMTABLE_OD_UPDATE_SCLK
;
5219 /* TODO: Check SCLK in DAL's minimum clocks in case DeepSleep divider update is required.*/
5220 if(data
->display_timing
.min_clock_insr
!= min_clocks
.engineClockInSR
)
5221 data
->need_update_smu7_dpm_table
|= DPMTABLE_UPDATE_SCLK
;
5224 for (i
=0; i
< pmclk_table
->count
; i
++) {
5225 if (mclk
== pmclk_table
->dpm_levels
[i
].value
)
5229 if (i
>= pmclk_table
->count
)
5230 data
->need_update_smu7_dpm_table
|= DPMTABLE_OD_UPDATE_MCLK
;
5232 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5234 if (data
->display_timing
.num_existing_displays
!= info
.display_count
)
5235 data
->need_update_smu7_dpm_table
|= DPMTABLE_UPDATE_MCLK
;
5240 static uint16_t tonga_get_maximum_link_speed(struct pp_hwmgr
*hwmgr
, const struct tonga_power_state
*hw_ps
)
5243 uint32_t sclk
, max_sclk
= 0;
5244 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5245 struct tonga_dpm_table
*pdpm_table
= &data
->dpm_table
;
5247 for (i
= 0; i
< hw_ps
->performance_level_count
; i
++) {
5248 sclk
= hw_ps
->performance_levels
[i
].engine_clock
;
5249 if (max_sclk
< sclk
)
5253 for (i
= 0; i
< pdpm_table
->sclk_table
.count
; i
++) {
5254 if (pdpm_table
->sclk_table
.dpm_levels
[i
].value
== max_sclk
)
5255 return (uint16_t) ((i
>= pdpm_table
->pcie_speed_table
.count
) ?
5256 pdpm_table
->pcie_speed_table
.dpm_levels
[pdpm_table
->pcie_speed_table
.count
-1].value
:
5257 pdpm_table
->pcie_speed_table
.dpm_levels
[i
].value
);
5263 static int tonga_request_link_speed_change_before_state_change(struct pp_hwmgr
*hwmgr
, const void *input
)
5265 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5266 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5267 const struct tonga_power_state
*tonga_nps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5268 const struct tonga_power_state
*tonga_cps
= cast_const_phw_tonga_power_state(states
->pcurrent_state
);
5270 uint16_t target_link_speed
= tonga_get_maximum_link_speed(hwmgr
, tonga_nps
);
5271 uint16_t current_link_speed
;
5273 if (data
->force_pcie_gen
== PP_PCIEGenInvalid
)
5274 current_link_speed
= tonga_get_maximum_link_speed(hwmgr
, tonga_cps
);
5276 current_link_speed
= data
->force_pcie_gen
;
5278 data
->force_pcie_gen
= PP_PCIEGenInvalid
;
5279 data
->pspp_notify_required
= false;
5280 if (target_link_speed
> current_link_speed
) {
5281 switch(target_link_speed
) {
5283 if (0 == acpi_pcie_perf_request(hwmgr
->device
, PCIE_PERF_REQ_GEN3
, false))
5285 data
->force_pcie_gen
= PP_PCIEGen2
;
5286 if (current_link_speed
== PP_PCIEGen2
)
5289 if (0 == acpi_pcie_perf_request(hwmgr
->device
, PCIE_PERF_REQ_GEN2
, false))
5292 data
->force_pcie_gen
= tonga_get_current_pcie_speed(hwmgr
);
5296 if (target_link_speed
< current_link_speed
)
5297 data
->pspp_notify_required
= true;
5303 static int tonga_freeze_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
5305 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5307 if (0 == data
->need_update_smu7_dpm_table
)
5310 if ((0 == data
->sclk_dpm_key_disabled
) &&
5311 (data
->need_update_smu7_dpm_table
&
5312 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
))) {
5313 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
5314 "Trying to freeze SCLK DPM when DPM is disabled",
5316 PP_ASSERT_WITH_CODE(
5317 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5318 PPSMC_MSG_SCLKDPM_FreezeLevel
),
5319 "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
5323 if ((0 == data
->mclk_dpm_key_disabled
) &&
5324 (data
->need_update_smu7_dpm_table
&
5325 DPMTABLE_OD_UPDATE_MCLK
)) {
5326 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
5327 "Trying to freeze MCLK DPM when DPM is disabled",
5329 PP_ASSERT_WITH_CODE(
5330 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5331 PPSMC_MSG_MCLKDPM_FreezeLevel
),
5332 "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
5339 static int tonga_populate_and_upload_sclk_mclk_dpm_levels(struct pp_hwmgr
*hwmgr
, const void *input
)
5343 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5344 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5345 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5346 uint32_t sclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].engine_clock
;
5347 uint32_t mclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].memory_clock
;
5348 struct tonga_dpm_table
*pdpm_table
= &data
->dpm_table
;
5350 struct tonga_dpm_table
*pgolden_dpm_table
= &data
->golden_dpm_table
;
5351 uint32_t dpm_count
, clock_percent
;
5354 if (0 == data
->need_update_smu7_dpm_table
)
5357 if (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_SCLK
) {
5358 pdpm_table
->sclk_table
.dpm_levels
[pdpm_table
->sclk_table
.count
-1].value
= sclk
;
5360 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinACSupport
) ||
5361 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinDCSupport
)) {
5362 /* Need to do calculation based on the golden DPM table
5363 * as the Heatmap GPU Clock axis is also based on the default values
5365 PP_ASSERT_WITH_CODE(
5366 (pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
!= 0),
5369 dpm_count
= pdpm_table
->sclk_table
.count
< 2 ? 0 : pdpm_table
->sclk_table
.count
-2;
5370 for (i
= dpm_count
; i
> 1; i
--) {
5371 if (sclk
> pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
) {
5372 clock_percent
= ((sclk
- pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
)*100) /
5373 pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
;
5375 pdpm_table
->sclk_table
.dpm_levels
[i
].value
=
5376 pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
+
5377 (pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5379 } else if (pgolden_dpm_table
->sclk_table
.dpm_levels
[pdpm_table
->sclk_table
.count
-1].value
> sclk
) {
5380 clock_percent
= ((pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
- sclk
)*100) /
5381 pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
;
5383 pdpm_table
->sclk_table
.dpm_levels
[i
].value
=
5384 pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
-
5385 (pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5387 pdpm_table
->sclk_table
.dpm_levels
[i
].value
=
5388 pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
;
5393 if (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
) {
5394 pdpm_table
->mclk_table
.dpm_levels
[pdpm_table
->mclk_table
.count
-1].value
= mclk
;
5396 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinACSupport
) ||
5397 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinDCSupport
)) {
5399 PP_ASSERT_WITH_CODE(
5400 (pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
!= 0),
5403 dpm_count
= pdpm_table
->mclk_table
.count
< 2? 0 : pdpm_table
->mclk_table
.count
-2;
5404 for (i
= dpm_count
; i
> 1; i
--) {
5405 if (mclk
> pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
) {
5406 clock_percent
= ((mclk
- pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
)*100) /
5407 pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
;
5409 pdpm_table
->mclk_table
.dpm_levels
[i
].value
=
5410 pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
+
5411 (pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5413 } else if (pgolden_dpm_table
->mclk_table
.dpm_levels
[pdpm_table
->mclk_table
.count
-1].value
> mclk
) {
5414 clock_percent
= ((pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
- mclk
)*100) /
5415 pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
;
5417 pdpm_table
->mclk_table
.dpm_levels
[i
].value
=
5418 pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
-
5419 (pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5421 pdpm_table
->mclk_table
.dpm_levels
[i
].value
= pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
;
5426 if (data
->need_update_smu7_dpm_table
& (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
)) {
5427 result
= tonga_populate_all_graphic_levels(hwmgr
);
5428 PP_ASSERT_WITH_CODE((0 == result
),
5429 "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
5433 if (data
->need_update_smu7_dpm_table
& (DPMTABLE_OD_UPDATE_MCLK
+ DPMTABLE_UPDATE_MCLK
)) {
5434 /*populate MCLK dpm table to SMU7 */
5435 result
= tonga_populate_all_memory_levels(hwmgr
);
5436 PP_ASSERT_WITH_CODE((0 == result
),
5437 "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
5444 static int tonga_trim_single_dpm_states(struct pp_hwmgr
*hwmgr
,
5445 struct tonga_single_dpm_table
* pdpm_table
,
5446 uint32_t low_limit
, uint32_t high_limit
)
5450 for (i
= 0; i
< pdpm_table
->count
; i
++) {
5451 if ((pdpm_table
->dpm_levels
[i
].value
< low_limit
) ||
5452 (pdpm_table
->dpm_levels
[i
].value
> high_limit
))
5453 pdpm_table
->dpm_levels
[i
].enabled
= false;
5455 pdpm_table
->dpm_levels
[i
].enabled
= true;
5460 static int tonga_trim_dpm_states(struct pp_hwmgr
*hwmgr
, const struct tonga_power_state
*hw_state
)
5462 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5463 uint32_t high_limit_count
;
5465 PP_ASSERT_WITH_CODE((hw_state
->performance_level_count
>= 1),
5466 "power state did not have any performance level",
5469 high_limit_count
= (1 == hw_state
->performance_level_count
) ? 0: 1;
5471 tonga_trim_single_dpm_states(hwmgr
,
5472 &(data
->dpm_table
.sclk_table
),
5473 hw_state
->performance_levels
[0].engine_clock
,
5474 hw_state
->performance_levels
[high_limit_count
].engine_clock
);
5476 tonga_trim_single_dpm_states(hwmgr
,
5477 &(data
->dpm_table
.mclk_table
),
5478 hw_state
->performance_levels
[0].memory_clock
,
5479 hw_state
->performance_levels
[high_limit_count
].memory_clock
);
5484 static int tonga_generate_dpm_level_enable_mask(struct pp_hwmgr
*hwmgr
, const void *input
)
5487 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5488 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5489 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5491 result
= tonga_trim_dpm_states(hwmgr
, tonga_ps
);
5495 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&data
->dpm_table
.sclk_table
);
5496 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&data
->dpm_table
.mclk_table
);
5497 data
->last_mclk_dpm_enable_mask
= data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
;
5498 if (data
->uvd_enabled
)
5499 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
&= 0xFFFFFFFE;
5501 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&data
->dpm_table
.pcie_speed_table
);
5506 int tonga_enable_disable_vce_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
5508 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
5509 (PPSMC_Msg
)PPSMC_MSG_VCEDPM_Enable
:
5510 (PPSMC_Msg
)PPSMC_MSG_VCEDPM_Disable
);
5513 int tonga_enable_disable_uvd_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
5515 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
5516 (PPSMC_Msg
)PPSMC_MSG_UVDDPM_Enable
:
5517 (PPSMC_Msg
)PPSMC_MSG_UVDDPM_Disable
);
5520 int tonga_update_uvd_dpm(struct pp_hwmgr
*hwmgr
, bool bgate
)
5522 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5523 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
5524 struct phm_ppt_v1_information
*ptable_information
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
5527 data
->smc_state_table
.UvdBootLevel
= (uint8_t) (ptable_information
->mm_dep_table
->count
- 1);
5528 mm_boot_level_offset
= data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
, UvdBootLevel
);
5529 mm_boot_level_offset
/= 4;
5530 mm_boot_level_offset
*= 4;
5531 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
);
5532 mm_boot_level_value
&= 0x00FFFFFF;
5533 mm_boot_level_value
|= data
->smc_state_table
.UvdBootLevel
<< 24;
5534 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
5536 if (!phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_UVDDPM
) ||
5537 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
))
5538 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5539 PPSMC_MSG_UVDDPM_SetEnabledMask
,
5540 (uint32_t)(1 << data
->smc_state_table
.UvdBootLevel
));
5543 return tonga_enable_disable_uvd_dpm(hwmgr
, !bgate
);
5546 int tonga_update_vce_dpm(struct pp_hwmgr
*hwmgr
, const void *input
)
5548 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5549 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5550 const struct tonga_power_state
*tonga_nps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5551 const struct tonga_power_state
*tonga_cps
= cast_const_phw_tonga_power_state(states
->pcurrent_state
);
5553 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
5554 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
5556 if (tonga_nps
->vce_clocks
.EVCLK
> 0 && (tonga_cps
== NULL
|| tonga_cps
->vce_clocks
.EVCLK
== 0)) {
5557 data
->smc_state_table
.VceBootLevel
= (uint8_t) (pptable_info
->mm_dep_table
->count
- 1);
5559 mm_boot_level_offset
= data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
, VceBootLevel
);
5560 mm_boot_level_offset
/= 4;
5561 mm_boot_level_offset
*= 4;
5562 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
);
5563 mm_boot_level_value
&= 0xFF00FFFF;
5564 mm_boot_level_value
|= data
->smc_state_table
.VceBootLevel
<< 16;
5565 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
5567 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
))
5568 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5569 PPSMC_MSG_VCEDPM_SetEnabledMask
,
5570 (uint32_t)(1 << data
->smc_state_table
.VceBootLevel
));
5572 tonga_enable_disable_vce_dpm(hwmgr
, true);
5573 } else if (tonga_nps
->vce_clocks
.EVCLK
== 0 && tonga_cps
!= NULL
&& tonga_cps
->vce_clocks
.EVCLK
> 0)
5574 tonga_enable_disable_vce_dpm(hwmgr
, false);
5579 static int tonga_update_and_upload_mc_reg_table(struct pp_hwmgr
*hwmgr
)
5581 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5586 if (0 == (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
))
5590 memset(&data
->mc_reg_table
, 0, sizeof(SMU72_Discrete_MCRegisters
));
5592 result
= tonga_convert_mc_reg_table_to_smc(hwmgr
, &(data
->mc_reg_table
));
5598 address
= data
->mc_reg_table_start
+ (uint32_t)offsetof(SMU72_Discrete_MCRegisters
, data
[0]);
5600 return tonga_copy_bytes_to_smc(hwmgr
->smumgr
, address
,
5601 (uint8_t *)&data
->mc_reg_table
.data
[0],
5602 sizeof(SMU72_Discrete_MCRegisterSet
) * data
->dpm_table
.mclk_table
.count
,
5606 static int tonga_program_memory_timing_parameters_conditionally(struct pp_hwmgr
*hwmgr
)
5608 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5610 if (data
->need_update_smu7_dpm_table
&
5611 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_OD_UPDATE_MCLK
))
5612 return tonga_program_memory_timing_parameters(hwmgr
);
5617 static int tonga_unfreeze_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
5619 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5621 if (0 == data
->need_update_smu7_dpm_table
)
5624 if ((0 == data
->sclk_dpm_key_disabled
) &&
5625 (data
->need_update_smu7_dpm_table
&
5626 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
))) {
5628 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
5629 "Trying to Unfreeze SCLK DPM when DPM is disabled",
5631 PP_ASSERT_WITH_CODE(
5632 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5633 PPSMC_MSG_SCLKDPM_UnfreezeLevel
),
5634 "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
5638 if ((0 == data
->mclk_dpm_key_disabled
) &&
5639 (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
)) {
5641 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
5642 "Trying to Unfreeze MCLK DPM when DPM is disabled",
5644 PP_ASSERT_WITH_CODE(
5645 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5646 PPSMC_MSG_SCLKDPM_UnfreezeLevel
),
5647 "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
5651 data
->need_update_smu7_dpm_table
= 0;
5656 static int tonga_notify_link_speed_change_after_state_change(struct pp_hwmgr
*hwmgr
, const void *input
)
5658 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5659 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5660 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5661 uint16_t target_link_speed
= tonga_get_maximum_link_speed(hwmgr
, tonga_ps
);
5664 if (data
->pspp_notify_required
||
5665 data
->pcie_performance_request
) {
5666 if (target_link_speed
== PP_PCIEGen3
)
5667 request
= PCIE_PERF_REQ_GEN3
;
5668 else if (target_link_speed
== PP_PCIEGen2
)
5669 request
= PCIE_PERF_REQ_GEN2
;
5671 request
= PCIE_PERF_REQ_GEN1
;
5673 if(request
== PCIE_PERF_REQ_GEN1
&& tonga_get_current_pcie_speed(hwmgr
) > 0) {
5674 data
->pcie_performance_request
= false;
5678 if (0 != acpi_pcie_perf_request(hwmgr
->device
, request
, false)) {
5679 if (PP_PCIEGen2
== target_link_speed
)
5680 printk("PSPP request to switch to Gen2 from Gen3 Failed!");
5682 printk("PSPP request to switch to Gen1 from Gen2 Failed!");
5686 data
->pcie_performance_request
= false;
5690 static int tonga_set_power_state_tasks(struct pp_hwmgr
*hwmgr
, const void *input
)
5692 int tmp_result
, result
= 0;
5694 tmp_result
= tonga_find_dpm_states_clocks_in_dpm_table(hwmgr
, input
);
5695 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to find DPM states clocks in DPM table!", result
= tmp_result
);
5697 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_PCIEPerformanceRequest
)) {
5698 tmp_result
= tonga_request_link_speed_change_before_state_change(hwmgr
, input
);
5699 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to request link speed change before state change!", result
= tmp_result
);
5702 tmp_result
= tonga_freeze_sclk_mclk_dpm(hwmgr
);
5703 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to freeze SCLK MCLK DPM!", result
= tmp_result
);
5705 tmp_result
= tonga_populate_and_upload_sclk_mclk_dpm_levels(hwmgr
, input
);
5706 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to populate and upload SCLK MCLK DPM levels!", result
= tmp_result
);
5708 tmp_result
= tonga_generate_dpm_level_enable_mask(hwmgr
, input
);
5709 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to generate DPM level enabled mask!", result
= tmp_result
);
5711 tmp_result
= tonga_update_vce_dpm(hwmgr
, input
);
5712 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to update VCE DPM!", result
= tmp_result
);
5714 tmp_result
= tonga_update_sclk_threshold(hwmgr
);
5715 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to update SCLK threshold!", result
= tmp_result
);
5717 tmp_result
= tonga_update_and_upload_mc_reg_table(hwmgr
);
5718 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to upload MC reg table!", result
= tmp_result
);
5720 tmp_result
= tonga_program_memory_timing_parameters_conditionally(hwmgr
);
5721 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to program memory timing parameters!", result
= tmp_result
);
5723 tmp_result
= tonga_unfreeze_sclk_mclk_dpm(hwmgr
);
5724 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to unfreeze SCLK MCLK DPM!", result
= tmp_result
);
5726 tmp_result
= tonga_upload_dpm_level_enable_mask(hwmgr
);
5727 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to upload DPM level enabled mask!", result
= tmp_result
);
5729 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_PCIEPerformanceRequest
)) {
5730 tmp_result
= tonga_notify_link_speed_change_after_state_change(hwmgr
, input
);
5731 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to notify link speed change after state change!", result
= tmp_result
);
5738 * Set maximum target operating fan output PWM
5740 * @param pHwMgr: the address of the powerplay hardware manager.
5741 * @param usMaxFanPwm: max operating fan PWM in percents
5742 * @return The response that came from the SMC.
5744 static int tonga_set_max_fan_pwm_output(struct pp_hwmgr
*hwmgr
, uint16_t us_max_fan_pwm
)
5746 hwmgr
->thermal_controller
.advanceFanControlParameters
.usMaxFanPWM
= us_max_fan_pwm
;
5748 if (phm_is_hw_access_blocked(hwmgr
))
5751 return (0 == smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
, PPSMC_MSG_SetFanPwmMax
, us_max_fan_pwm
) ? 0 : -1);
5754 int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr
*hwmgr
)
5756 uint32_t num_active_displays
= 0;
5757 struct cgs_display_info info
= {0};
5758 info
.mode_info
= NULL
;
5760 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5762 num_active_displays
= info
.display_count
;
5764 if (num_active_displays
> 1) /* to do && (pHwMgr->pPECI->displayConfiguration.bMultiMonitorInSync != TRUE)) */
5765 tonga_notify_smc_display_change(hwmgr
, false);
5767 tonga_notify_smc_display_change(hwmgr
, true);
5773 * Programs the display gap
5775 * @param hwmgr the address of the powerplay hardware manager.
5778 int tonga_program_display_gap(struct pp_hwmgr
*hwmgr
)
5780 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5781 uint32_t num_active_displays
= 0;
5782 uint32_t display_gap
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
);
5783 uint32_t display_gap2
;
5784 uint32_t pre_vbi_time_in_us
;
5785 uint32_t frame_time_in_us
;
5787 uint32_t refresh_rate
= 0;
5788 struct cgs_display_info info
= {0};
5789 struct cgs_mode_info mode_info
;
5791 info
.mode_info
= &mode_info
;
5793 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5794 num_active_displays
= info
.display_count
;
5796 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
);
5797 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
, display_gap
);
5799 ref_clock
= mode_info
.ref_clock
;
5800 refresh_rate
= mode_info
.refresh_rate
;
5802 if(0 == refresh_rate
)
5805 frame_time_in_us
= 1000000 / refresh_rate
;
5807 pre_vbi_time_in_us
= frame_time_in_us
- 200 - mode_info
.vblank_time_us
;
5808 display_gap2
= pre_vbi_time_in_us
* (ref_clock
/ 100);
5810 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL2
, display_gap2
);
5812 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, data
->soft_regs_start
+ offsetof(SMU72_SoftRegisters
, PreVBlankGap
), 0x64);
5814 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
));
5816 if (num_active_displays
== 1)
5817 tonga_notify_smc_display_change(hwmgr
, true);
5822 int tonga_display_configuration_changed_task(struct pp_hwmgr
*hwmgr
)
5825 tonga_program_display_gap(hwmgr
);
5827 /* to do PhwTonga_CacUpdateDisplayConfiguration(pHwMgr); */
5832 * Set maximum target operating fan output RPM
5834 * @param pHwMgr: the address of the powerplay hardware manager.
5835 * @param usMaxFanRpm: max operating fan RPM value.
5836 * @return The response that came from the SMC.
5838 static int tonga_set_max_fan_rpm_output(struct pp_hwmgr
*hwmgr
, uint16_t us_max_fan_pwm
)
5840 hwmgr
->thermal_controller
.advanceFanControlParameters
.usMaxFanRPM
= us_max_fan_pwm
;
5842 if (phm_is_hw_access_blocked(hwmgr
))
5845 return (0 == smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
, PPSMC_MSG_SetFanRpmMax
, us_max_fan_pwm
) ? 0 : -1);
5848 uint32_t tonga_get_xclk(struct pp_hwmgr
*hwmgr
)
5850 uint32_t reference_clock
;
5854 ATOM_FIRMWARE_INFO
*fw_info
;
5857 int index
= GetIndexIntoMasterTable(DATA
, FirmwareInfo
);
5859 tc
= PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, CG_CLKPIN_CNTL_2
, MUX_TCLK_TO_XCLK
);
5864 fw_info
= (ATOM_FIRMWARE_INFO
*)cgs_atom_get_data_table(hwmgr
->device
, index
,
5865 &size
, &frev
, &crev
);
5870 reference_clock
= le16_to_cpu(fw_info
->usReferenceClock
);
5872 divide
= PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, CG_CLKPIN_CNTL
, XTALIN_DIVIDE
);
5875 return reference_clock
/ 4;
5877 return reference_clock
;
5880 int tonga_dpm_set_interrupt_state(void *private_data
,
5881 unsigned src_id
, unsigned type
,
5884 uint32_t cg_thermal_int
;
5885 struct pp_hwmgr
*hwmgr
= ((struct pp_eventmgr
*)private_data
)->hwmgr
;
5891 case AMD_THERMAL_IRQ_LOW_TO_HIGH
:
5893 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5894 cg_thermal_int
|= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK
;
5895 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5897 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5898 cg_thermal_int
&= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK
;
5899 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5903 case AMD_THERMAL_IRQ_HIGH_TO_LOW
:
5905 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5906 cg_thermal_int
|= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK
;
5907 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5909 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5910 cg_thermal_int
&= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK
;
5911 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5920 int tonga_register_internal_thermal_interrupt(struct pp_hwmgr
*hwmgr
,
5921 const void *thermal_interrupt_info
)
5924 const struct pp_interrupt_registration_info
*info
=
5925 (const struct pp_interrupt_registration_info
*)thermal_interrupt_info
;
5930 result
= cgs_add_irq_source(hwmgr
->device
, 230, AMD_THERMAL_IRQ_LAST
,
5931 tonga_dpm_set_interrupt_state
,
5932 info
->call_back
, info
->context
);
5937 result
= cgs_add_irq_source(hwmgr
->device
, 231, AMD_THERMAL_IRQ_LAST
,
5938 tonga_dpm_set_interrupt_state
,
5939 info
->call_back
, info
->context
);
5947 bool tonga_check_smc_update_required_for_display_configuration(struct pp_hwmgr
*hwmgr
)
5949 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5950 bool is_update_required
= false;
5951 struct cgs_display_info info
= {0,0,NULL
};
5953 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5955 if (data
->display_timing
.num_existing_displays
!= info
.display_count
)
5956 is_update_required
= true;
5957 /* TO DO NEED TO GET DEEP SLEEP CLOCK FROM DAL
5958 if (phm_cap_enabled(hwmgr->hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
5959 cgs_get_min_clock_settings(hwmgr->device, &min_clocks);
5960 if(min_clocks.engineClockInSR != data->display_timing.minClockInSR)
5961 is_update_required = true;
5963 return is_update_required
;
5966 static inline bool tonga_are_power_levels_equal(const struct tonga_performance_level
*pl1
,
5967 const struct tonga_performance_level
*pl2
)
5969 return ((pl1
->memory_clock
== pl2
->memory_clock
) &&
5970 (pl1
->engine_clock
== pl2
->engine_clock
) &&
5971 (pl1
->pcie_gen
== pl2
->pcie_gen
) &&
5972 (pl1
->pcie_lane
== pl2
->pcie_lane
));
5975 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
)
5977 const struct tonga_power_state
*psa
= cast_const_phw_tonga_power_state(pstate1
);
5978 const struct tonga_power_state
*psb
= cast_const_phw_tonga_power_state(pstate2
);
5981 if (equal
== NULL
|| psa
== NULL
|| psb
== NULL
)
5984 /* If the two states don't even have the same number of performance levels they cannot be the same state. */
5985 if (psa
->performance_level_count
!= psb
->performance_level_count
) {
5990 for (i
= 0; i
< psa
->performance_level_count
; i
++) {
5991 if (!tonga_are_power_levels_equal(&(psa
->performance_levels
[i
]), &(psb
->performance_levels
[i
]))) {
5992 /* If we have found even one performance level pair that is different the states are different. */
5998 /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
5999 *equal
= ((psa
->uvd_clocks
.VCLK
== psb
->uvd_clocks
.VCLK
) && (psa
->uvd_clocks
.DCLK
== psb
->uvd_clocks
.DCLK
));
6000 *equal
&= ((psa
->vce_clocks
.EVCLK
== psb
->vce_clocks
.EVCLK
) && (psa
->vce_clocks
.ECCLK
== psb
->vce_clocks
.ECCLK
));
6001 *equal
&= (psa
->sclk_threshold
== psb
->sclk_threshold
);
6002 *equal
&= (psa
->acp_clk
== psb
->acp_clk
);
6007 static int tonga_set_fan_control_mode(struct pp_hwmgr
*hwmgr
, uint32_t mode
)
6010 /* stop auto-manage */
6011 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
6012 PHM_PlatformCaps_MicrocodeFanControl
))
6013 tonga_fan_ctrl_stop_smc_fan_control(hwmgr
);
6014 tonga_fan_ctrl_set_static_mode(hwmgr
, mode
);
6016 /* restart auto-manage */
6017 tonga_fan_ctrl_reset_fan_speed_to_default(hwmgr
);
6022 static int tonga_get_fan_control_mode(struct pp_hwmgr
*hwmgr
)
6024 if (hwmgr
->fan_ctrl_is_in_default_mode
)
6025 return hwmgr
->fan_ctrl_default_mode
;
6027 return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
6028 CG_FDO_CTRL2
, FDO_PWM_MODE
);
6031 static int tonga_force_clock_level(struct pp_hwmgr
*hwmgr
,
6032 enum pp_clock_type type
, uint32_t mask
)
6034 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
6036 if (hwmgr
->dpm_level
!= AMD_DPM_FORCED_LEVEL_MANUAL
)
6041 if (!data
->sclk_dpm_key_disabled
)
6042 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
6043 PPSMC_MSG_SCLKDPM_SetEnabledMask
,
6044 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
& mask
);
6047 if (!data
->mclk_dpm_key_disabled
)
6048 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
6049 PPSMC_MSG_MCLKDPM_SetEnabledMask
,
6050 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
& mask
);
6054 uint32_t tmp
= mask
& data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
;
6060 if (!data
->pcie_dpm_key_disabled
)
6061 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
6062 PPSMC_MSG_PCIeDPM_ForceLevel
,
6073 static int tonga_print_clock_levels(struct pp_hwmgr
*hwmgr
,
6074 enum pp_clock_type type
, char *buf
)
6076 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
6077 struct tonga_single_dpm_table
*sclk_table
= &(data
->dpm_table
.sclk_table
);
6078 struct tonga_single_dpm_table
*mclk_table
= &(data
->dpm_table
.mclk_table
);
6079 struct tonga_single_dpm_table
*pcie_table
= &(data
->dpm_table
.pcie_speed_table
);
6080 int i
, now
, size
= 0;
6081 uint32_t clock
, pcie_speed
;
6085 smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_API_GetSclkFrequency
);
6086 clock
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
6088 for (i
= 0; i
< sclk_table
->count
; i
++) {
6089 if (clock
> sclk_table
->dpm_levels
[i
].value
)
6095 for (i
= 0; i
< sclk_table
->count
; i
++)
6096 size
+= sprintf(buf
+ size
, "%d: %uMhz %s\n",
6097 i
, sclk_table
->dpm_levels
[i
].value
/ 100,
6098 (i
== now
) ? "*" : "");
6101 smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_API_GetMclkFrequency
);
6102 clock
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
6104 for (i
= 0; i
< mclk_table
->count
; i
++) {
6105 if (clock
> mclk_table
->dpm_levels
[i
].value
)
6111 for (i
= 0; i
< mclk_table
->count
; i
++)
6112 size
+= sprintf(buf
+ size
, "%d: %uMhz %s\n",
6113 i
, mclk_table
->dpm_levels
[i
].value
/ 100,
6114 (i
== now
) ? "*" : "");
6117 pcie_speed
= tonga_get_current_pcie_speed(hwmgr
);
6118 for (i
= 0; i
< pcie_table
->count
; i
++) {
6119 if (pcie_speed
!= pcie_table
->dpm_levels
[i
].value
)
6125 for (i
= 0; i
< pcie_table
->count
; i
++)
6126 size
+= sprintf(buf
+ size
, "%d: %s %s\n", i
,
6127 (pcie_table
->dpm_levels
[i
].value
== 0) ? "2.5GB, x8" :
6128 (pcie_table
->dpm_levels
[i
].value
== 1) ? "5.0GB, x16" :
6129 (pcie_table
->dpm_levels
[i
].value
== 2) ? "8.0GB, x16" : "",
6130 (i
== now
) ? "*" : "");
6138 static int tonga_get_sclk_od(struct pp_hwmgr
*hwmgr
)
6140 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
6141 struct tonga_single_dpm_table
*sclk_table
= &(data
->dpm_table
.sclk_table
);
6142 struct tonga_single_dpm_table
*golden_sclk_table
=
6143 &(data
->golden_dpm_table
.sclk_table
);
6146 value
= (sclk_table
->dpm_levels
[sclk_table
->count
- 1].value
-
6147 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
) *
6149 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
;
6154 static int tonga_set_sclk_od(struct pp_hwmgr
*hwmgr
, uint32_t value
)
6156 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
6157 struct tonga_single_dpm_table
*golden_sclk_table
=
6158 &(data
->golden_dpm_table
.sclk_table
);
6159 struct pp_power_state
*ps
;
6160 struct tonga_power_state
*tonga_ps
;
6165 ps
= hwmgr
->request_ps
;
6170 tonga_ps
= cast_phw_tonga_power_state(&ps
->hardware
);
6172 tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
- 1].engine_clock
=
6173 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
*
6175 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
;
6180 static int tonga_get_mclk_od(struct pp_hwmgr
*hwmgr
)
6182 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
6183 struct tonga_single_dpm_table
*mclk_table
= &(data
->dpm_table
.mclk_table
);
6184 struct tonga_single_dpm_table
*golden_mclk_table
=
6185 &(data
->golden_dpm_table
.mclk_table
);
6188 value
= (mclk_table
->dpm_levels
[mclk_table
->count
- 1].value
-
6189 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
) *
6191 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
;
6196 static int tonga_set_mclk_od(struct pp_hwmgr
*hwmgr
, uint32_t value
)
6198 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
6199 struct tonga_single_dpm_table
*golden_mclk_table
=
6200 &(data
->golden_dpm_table
.mclk_table
);
6201 struct pp_power_state
*ps
;
6202 struct tonga_power_state
*tonga_ps
;
6207 ps
= hwmgr
->request_ps
;
6212 tonga_ps
= cast_phw_tonga_power_state(&ps
->hardware
);
6214 tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
- 1].memory_clock
=
6215 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
*
6217 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
;
6222 static const struct pp_hwmgr_func tonga_hwmgr_funcs
= {
6223 .backend_init
= &tonga_hwmgr_backend_init
,
6224 .backend_fini
= &tonga_hwmgr_backend_fini
,
6225 .asic_setup
= &tonga_setup_asic_task
,
6226 .dynamic_state_management_enable
= &tonga_enable_dpm_tasks
,
6227 .dynamic_state_management_disable
= &tonga_disable_dpm_tasks
,
6228 .apply_state_adjust_rules
= tonga_apply_state_adjust_rules
,
6229 .force_dpm_level
= &tonga_force_dpm_level
,
6230 .power_state_set
= tonga_set_power_state_tasks
,
6231 .get_power_state_size
= tonga_get_power_state_size
,
6232 .get_mclk
= tonga_dpm_get_mclk
,
6233 .get_sclk
= tonga_dpm_get_sclk
,
6234 .patch_boot_state
= tonga_dpm_patch_boot_state
,
6235 .get_pp_table_entry
= tonga_get_pp_table_entry
,
6236 .get_num_of_pp_table_entries
= tonga_get_number_of_powerplay_table_entries
,
6237 .print_current_perforce_level
= tonga_print_current_perforce_level
,
6238 .powerdown_uvd
= tonga_phm_powerdown_uvd
,
6239 .powergate_uvd
= tonga_phm_powergate_uvd
,
6240 .powergate_vce
= tonga_phm_powergate_vce
,
6241 .disable_clock_power_gating
= tonga_phm_disable_clock_power_gating
,
6242 .update_clock_gatings
= tonga_phm_update_clock_gatings
,
6243 .notify_smc_display_config_after_ps_adjustment
= tonga_notify_smc_display_config_after_ps_adjustment
,
6244 .display_config_changed
= tonga_display_configuration_changed_task
,
6245 .set_max_fan_pwm_output
= tonga_set_max_fan_pwm_output
,
6246 .set_max_fan_rpm_output
= tonga_set_max_fan_rpm_output
,
6247 .get_temperature
= tonga_thermal_get_temperature
,
6248 .stop_thermal_controller
= tonga_thermal_stop_thermal_controller
,
6249 .get_fan_speed_info
= tonga_fan_ctrl_get_fan_speed_info
,
6250 .get_fan_speed_percent
= tonga_fan_ctrl_get_fan_speed_percent
,
6251 .set_fan_speed_percent
= tonga_fan_ctrl_set_fan_speed_percent
,
6252 .reset_fan_speed_to_default
= tonga_fan_ctrl_reset_fan_speed_to_default
,
6253 .get_fan_speed_rpm
= tonga_fan_ctrl_get_fan_speed_rpm
,
6254 .set_fan_speed_rpm
= tonga_fan_ctrl_set_fan_speed_rpm
,
6255 .uninitialize_thermal_controller
= tonga_thermal_ctrl_uninitialize_thermal_controller
,
6256 .register_internal_thermal_interrupt
= tonga_register_internal_thermal_interrupt
,
6257 .check_smc_update_required_for_display_configuration
= tonga_check_smc_update_required_for_display_configuration
,
6258 .check_states_equal
= tonga_check_states_equal
,
6259 .set_fan_control_mode
= tonga_set_fan_control_mode
,
6260 .get_fan_control_mode
= tonga_get_fan_control_mode
,
6261 .force_clock_level
= tonga_force_clock_level
,
6262 .print_clock_levels
= tonga_print_clock_levels
,
6263 .get_sclk_od
= tonga_get_sclk_od
,
6264 .set_sclk_od
= tonga_set_sclk_od
,
6265 .get_mclk_od
= tonga_get_mclk_od
,
6266 .set_mclk_od
= tonga_set_mclk_od
,
6269 int tonga_hwmgr_init(struct pp_hwmgr
*hwmgr
)
6271 hwmgr
->hwmgr_func
= &tonga_hwmgr_funcs
;
6272 hwmgr
->pptable_func
= &tonga_pptable_funcs
;
6273 pp_tonga_thermal_initialize(hwmgr
);