2 * Copyright 2015 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
23 #include <linux/module.h>
24 #include <linux/slab.h>
25 #include "linux/delay.h"
29 #include "tonga_hwmgr.h"
31 #include "processpptables.h"
32 #include "tonga_processpptables.h"
33 #include "tonga_pptable.h"
35 #include "tonga_ppsmc.h"
36 #include "cgs_common.h"
37 #include "pppcielanes.h"
38 #include "tonga_dyn_defaults.h"
40 #include "tonga_smumgr.h"
41 #include "tonga_clockpowergating.h"
42 #include "tonga_thermal.h"
44 #include "smu/smu_7_1_2_d.h"
45 #include "smu/smu_7_1_2_sh_mask.h"
47 #include "gmc/gmc_8_1_d.h"
48 #include "gmc/gmc_8_1_sh_mask.h"
50 #include "bif/bif_5_0_d.h"
51 #include "bif/bif_5_0_sh_mask.h"
53 #include "dce/dce_10_0_d.h"
54 #include "dce/dce_10_0_sh_mask.h"
56 #include "cgs_linux.h"
58 #include "amd_pcie_helpers.h"
60 #define MC_CG_ARB_FREQ_F0 0x0a
61 #define MC_CG_ARB_FREQ_F1 0x0b
62 #define MC_CG_ARB_FREQ_F2 0x0c
63 #define MC_CG_ARB_FREQ_F3 0x0d
65 #define MC_CG_SEQ_DRAMCONF_S0 0x05
66 #define MC_CG_SEQ_DRAMCONF_S1 0x06
67 #define MC_CG_SEQ_YCLK_SUSPEND 0x04
68 #define MC_CG_SEQ_YCLK_RESUME 0x0a
70 #define PCIE_BUS_CLK 10000
71 #define TCLK (PCIE_BUS_CLK / 10)
73 #define SMC_RAM_END 0x40000
74 #define SMC_CG_IND_START 0xc0030000
75 #define SMC_CG_IND_END 0xc0040000 /* First byte after SMC_CG_IND*/
77 #define VOLTAGE_SCALE 4
78 #define VOLTAGE_VID_OFFSET_SCALE1 625
79 #define VOLTAGE_VID_OFFSET_SCALE2 100
81 #define VDDC_VDDCI_DELTA 200
82 #define VDDC_VDDGFX_DELTA 300
84 #define MC_SEQ_MISC0_GDDR5_SHIFT 28
85 #define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000
86 #define MC_SEQ_MISC0_GDDR5_VALUE 5
88 typedef uint32_t PECI_RegistryValue
;
90 /* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ] */
91 static const uint16_t PP_ClockStretcherLookupTable
[2][4] = {
95 /* [FF, SS] type, [] 4 voltage ranges, and [Floor Freq, Boundary Freq, VID min , VID max] */
96 static const uint32_t PP_ClockStretcherDDTTable
[2][4][4] = {
97 { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
98 { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
100 /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] (coming from PWR_CKS_CNTL.stretch_amount reg spec) */
101 static const uint8_t PP_ClockStretchAmountConversion
[2][6] = {
103 {0, 2, 4, 5, 6, 5} };
105 /* Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
107 DPM_EVENT_SRC_ANALOG
= 0, /* Internal analog trip point */
108 DPM_EVENT_SRC_EXTERNAL
= 1, /* External (GPIO 17) signal */
109 DPM_EVENT_SRC_DIGITAL
= 2, /* Internal digital trip point (DIG_THERM_DPM) */
110 DPM_EVENT_SRC_ANALOG_OR_EXTERNAL
= 3, /* Internal analog or external */
111 DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL
= 4 /* Internal digital or external */
113 typedef enum DPM_EVENT_SRC DPM_EVENT_SRC
;
115 static const unsigned long PhwTonga_Magic
= (unsigned long)(PHM_VIslands_Magic
);
117 struct tonga_power_state
*cast_phw_tonga_power_state(
118 struct pp_hw_power_state
*hw_ps
)
123 PP_ASSERT_WITH_CODE((PhwTonga_Magic
== hw_ps
->magic
),
124 "Invalid Powerstate Type!",
127 return (struct tonga_power_state
*)hw_ps
;
130 const struct tonga_power_state
*cast_const_phw_tonga_power_state(
131 const struct pp_hw_power_state
*hw_ps
)
136 PP_ASSERT_WITH_CODE((PhwTonga_Magic
== hw_ps
->magic
),
137 "Invalid Powerstate Type!",
140 return (const struct tonga_power_state
*)hw_ps
;
143 int tonga_add_voltage(struct pp_hwmgr
*hwmgr
,
144 phm_ppt_v1_voltage_lookup_table
*look_up_table
,
145 phm_ppt_v1_voltage_lookup_record
*record
)
148 PP_ASSERT_WITH_CODE((NULL
!= look_up_table
),
149 "Lookup Table empty.", return -1;);
150 PP_ASSERT_WITH_CODE((0 != look_up_table
->count
),
151 "Lookup Table empty.", return -1;);
152 PP_ASSERT_WITH_CODE((SMU72_MAX_LEVELS_VDDGFX
>= look_up_table
->count
),
153 "Lookup Table is full.", return -1;);
155 /* This is to avoid entering duplicate calculated records. */
156 for (i
= 0; i
< look_up_table
->count
; i
++) {
157 if (look_up_table
->entries
[i
].us_vdd
== record
->us_vdd
) {
158 if (look_up_table
->entries
[i
].us_calculated
== 1)
165 look_up_table
->entries
[i
].us_calculated
= 1;
166 look_up_table
->entries
[i
].us_vdd
= record
->us_vdd
;
167 look_up_table
->entries
[i
].us_cac_low
= record
->us_cac_low
;
168 look_up_table
->entries
[i
].us_cac_mid
= record
->us_cac_mid
;
169 look_up_table
->entries
[i
].us_cac_high
= record
->us_cac_high
;
170 /* Only increment the count when we're appending, not replacing duplicate entry. */
171 if (i
== look_up_table
->count
)
172 look_up_table
->count
++;
177 int tonga_notify_smc_display_change(struct pp_hwmgr
*hwmgr
, bool has_display
)
179 PPSMC_Msg msg
= has_display
? (PPSMC_Msg
)PPSMC_HasDisplay
: (PPSMC_Msg
)PPSMC_NoDisplay
;
181 return (smum_send_msg_to_smc(hwmgr
->smumgr
, msg
) == 0) ? 0 : -1;
184 uint8_t tonga_get_voltage_id(pp_atomctrl_voltage_table
*voltage_table
,
187 uint8_t count
= (uint8_t) (voltage_table
->count
);
190 PP_ASSERT_WITH_CODE((NULL
!= voltage_table
),
191 "Voltage Table empty.", return 0;);
192 PP_ASSERT_WITH_CODE((0 != count
),
193 "Voltage Table empty.", return 0;);
195 for (i
= 0; i
< count
; i
++) {
196 /* find first voltage bigger than requested */
197 if (voltage_table
->entries
[i
].value
>= voltage
)
201 /* voltage is bigger than max voltage in the table */
206 * @brief PhwTonga_GetVoltageOrder
207 * Returns index of requested voltage record in lookup(table)
208 * @param hwmgr - pointer to hardware manager
209 * @param lookupTable - lookup list to search in
210 * @param voltage - voltage to look for
211 * @return 0 on success
213 uint8_t tonga_get_voltage_index(phm_ppt_v1_voltage_lookup_table
*look_up_table
,
216 uint8_t count
= (uint8_t) (look_up_table
->count
);
219 PP_ASSERT_WITH_CODE((NULL
!= look_up_table
), "Lookup Table empty.", return 0;);
220 PP_ASSERT_WITH_CODE((0 != count
), "Lookup Table empty.", return 0;);
222 for (i
= 0; i
< count
; i
++) {
223 /* find first voltage equal or bigger than requested */
224 if (look_up_table
->entries
[i
].us_vdd
>= voltage
)
228 /* voltage is bigger than max voltage in the table */
232 bool tonga_is_dpm_running(struct pp_hwmgr
*hwmgr
)
235 * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
236 * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
237 * whereas voltage control is a fundemental change that will not be disabled
240 return (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
241 FEATURE_STATUS
, VOLTAGE_CONTROLLER_ON
) ? 1 : 0);
245 * Re-generate the DPM level mask value
246 * @param hwmgr the address of the hardware manager
248 static uint32_t tonga_get_dpm_level_enable_mask_value(
249 struct tonga_single_dpm_table
* dpm_table
)
252 uint32_t mask_value
= 0;
254 for (i
= dpm_table
->count
; i
> 0; i
--) {
255 mask_value
= mask_value
<< 1;
257 if (dpm_table
->dpm_levels
[i
-1].enabled
)
260 mask_value
&= 0xFFFFFFFE;
266 * Retrieve DPM default values from registry (if available)
268 * @param hwmgr the address of the powerplay hardware manager.
270 void tonga_initialize_dpm_defaults(struct pp_hwmgr
*hwmgr
)
272 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
273 phw_tonga_ulv_parm
*ulv
= &(data
->ulv
);
276 ulv
->ch_ulv_parameter
= PPTONGA_CGULVPARAMETER_DFLT
;
277 data
->voting_rights_clients0
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0
;
278 data
->voting_rights_clients1
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1
;
279 data
->voting_rights_clients2
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2
;
280 data
->voting_rights_clients3
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3
;
281 data
->voting_rights_clients4
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4
;
282 data
->voting_rights_clients5
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5
;
283 data
->voting_rights_clients6
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6
;
284 data
->voting_rights_clients7
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7
;
286 data
->static_screen_threshold_unit
= PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT
;
287 data
->static_screen_threshold
= PPTONGA_STATICSCREENTHRESHOLD_DFLT
;
289 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
290 PHM_PlatformCaps_ABM
);
291 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
292 PHM_PlatformCaps_NonABMSupportInPPLib
);
296 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
297 PHM_PlatformCaps_DynamicACTiming
);
301 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
302 PHM_PlatformCaps_DisableMemoryTransition
);
304 tonga_initialize_power_tune_defaults(hwmgr
);
306 data
->mclk_strobe_mode_threshold
= 40000;
307 data
->mclk_stutter_mode_threshold
= 30000;
308 data
->mclk_edc_enable_threshold
= 40000;
309 data
->mclk_edc_wr_enable_threshold
= 40000;
313 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
314 PHM_PlatformCaps_DisableMCLS
);
316 data
->pcie_gen_performance
.max
= PP_PCIEGen1
;
317 data
->pcie_gen_performance
.min
= PP_PCIEGen3
;
318 data
->pcie_gen_power_saving
.max
= PP_PCIEGen1
;
319 data
->pcie_gen_power_saving
.min
= PP_PCIEGen3
;
321 data
->pcie_lane_performance
.max
= 0;
322 data
->pcie_lane_performance
.min
= 16;
323 data
->pcie_lane_power_saving
.max
= 0;
324 data
->pcie_lane_power_saving
.min
= 16;
329 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
330 PHM_PlatformCaps_SclkThrottleLowNotification
);
332 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
333 PHM_PlatformCaps_DynamicUVDState
);
337 int tonga_update_sclk_threshold(struct pp_hwmgr
*hwmgr
)
339 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
342 uint32_t low_sclk_interrupt_threshold
= 0;
344 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
345 PHM_PlatformCaps_SclkThrottleLowNotification
)
346 && (hwmgr
->gfx_arbiter
.sclk_threshold
!= data
->low_sclk_interrupt_threshold
)) {
347 data
->low_sclk_interrupt_threshold
= hwmgr
->gfx_arbiter
.sclk_threshold
;
348 low_sclk_interrupt_threshold
= data
->low_sclk_interrupt_threshold
;
350 CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold
);
352 result
= tonga_copy_bytes_to_smc(
354 data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
,
355 LowSclkInterruptThreshold
),
356 (uint8_t *)&low_sclk_interrupt_threshold
,
366 * Find SCLK value that is associated with specified virtual_voltage_Id.
368 * @param hwmgr the address of the powerplay hardware manager.
369 * @param virtual_voltage_Id voltageId to look for.
370 * @param sclk output value .
371 * @return always 0 if success and 2 if association not found
373 static int tonga_get_sclk_for_voltage_evv(struct pp_hwmgr
*hwmgr
,
374 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
375 uint16_t virtual_voltage_id
, uint32_t *sclk
)
379 struct phm_ppt_v1_information
*pptable_info
=
380 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
382 PP_ASSERT_WITH_CODE(lookup_table
->count
!= 0, "Lookup table is empty", return -1);
384 /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
385 for (entryId
= 0; entryId
< pptable_info
->vdd_dep_on_sclk
->count
; entryId
++) {
386 voltageId
= pptable_info
->vdd_dep_on_sclk
->entries
[entryId
].vddInd
;
387 if (lookup_table
->entries
[voltageId
].us_vdd
== virtual_voltage_id
)
391 PP_ASSERT_WITH_CODE(entryId
< pptable_info
->vdd_dep_on_sclk
->count
,
392 "Can't find requested voltage id in vdd_dep_on_sclk table!",
396 *sclk
= pptable_info
->vdd_dep_on_sclk
->entries
[entryId
].clk
;
402 * Get Leakage VDDC based on leakage ID.
404 * @param hwmgr the address of the powerplay hardware manager.
405 * @return 2 if vddgfx returned is greater than 2V or if BIOS
407 int tonga_get_evv_voltage(struct pp_hwmgr
*hwmgr
)
409 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
410 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
411 phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
= pptable_info
->vdd_dep_on_sclk
;
412 uint16_t virtual_voltage_id
;
418 /* retrieve voltage for leakage ID (0xff01 + i) */
419 for (i
= 0; i
< TONGA_MAX_LEAKAGE_COUNT
; i
++) {
420 virtual_voltage_id
= ATOM_VIRTUAL_VOLTAGE_ID0
+ i
;
422 /* in split mode we should have only vddgfx EVV leakages */
423 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
424 if (0 == tonga_get_sclk_for_voltage_evv(hwmgr
,
425 pptable_info
->vddgfx_lookup_table
, virtual_voltage_id
, &sclk
)) {
426 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
427 PHM_PlatformCaps_ClockStretcher
)) {
428 for (j
= 1; j
< sclk_table
->count
; j
++) {
429 if (sclk_table
->entries
[j
].clk
== sclk
&&
430 sclk_table
->entries
[j
].cks_enable
== 0) {
436 if (0 == atomctrl_get_voltage_evv_on_sclk
437 (hwmgr
, VOLTAGE_TYPE_VDDGFX
, sclk
,
438 virtual_voltage_id
, &vddgfx
)) {
439 /* need to make sure vddgfx is less than 2v or else, it could burn the ASIC. */
440 PP_ASSERT_WITH_CODE((vddgfx
< 2000 && vddgfx
!= 0), "Invalid VDDGFX value!", return -1);
442 /* the voltage should not be zero nor equal to leakage ID */
443 if (vddgfx
!= 0 && vddgfx
!= virtual_voltage_id
) {
444 data
->vddcgfx_leakage
.actual_voltage
[data
->vddcgfx_leakage
.count
] = vddgfx
;
445 data
->vddcgfx_leakage
.leakage_id
[data
->vddcgfx_leakage
.count
] = virtual_voltage_id
;
446 data
->vddcgfx_leakage
.count
++;
449 printk("Error retrieving EVV voltage value!\n");
453 /* in merged mode we have only vddc EVV leakages */
454 if (0 == tonga_get_sclk_for_voltage_evv(hwmgr
,
455 pptable_info
->vddc_lookup_table
,
456 virtual_voltage_id
, &sclk
)) {
457 if (0 == atomctrl_get_voltage_evv_on_sclk
458 (hwmgr
, VOLTAGE_TYPE_VDDC
, sclk
,
459 virtual_voltage_id
, &vddc
)) {
460 /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
461 PP_ASSERT_WITH_CODE(vddc
< 2000, "Invalid VDDC value!", return -1);
463 /* the voltage should not be zero nor equal to leakage ID */
464 if (vddc
!= 0 && vddc
!= virtual_voltage_id
) {
465 data
->vddc_leakage
.actual_voltage
[data
->vddc_leakage
.count
] = vddc
;
466 data
->vddc_leakage
.leakage_id
[data
->vddc_leakage
.count
] = virtual_voltage_id
;
467 data
->vddc_leakage
.count
++;
470 printk("Error retrieving EVV voltage value!\n");
479 int tonga_enable_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
481 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
483 /* enable SCLK dpm */
484 if (0 == data
->sclk_dpm_key_disabled
) {
486 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
487 PPSMC_MSG_DPM_Enable
)),
488 "Failed to enable SCLK DPM during DPM Start Function!",
492 /* enable MCLK dpm */
493 if (0 == data
->mclk_dpm_key_disabled
) {
495 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
496 PPSMC_MSG_MCLKDPM_Enable
)),
497 "Failed to enable MCLK DPM during DPM Start Function!",
500 PHM_WRITE_FIELD(hwmgr
->device
, MC_SEQ_CNTL_3
, CAC_EN
, 0x1);
502 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
503 ixLCAC_MC0_CNTL
, 0x05);/* CH0,1 read */
504 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
505 ixLCAC_MC1_CNTL
, 0x05);/* CH2,3 read */
506 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
507 ixLCAC_CPL_CNTL
, 0x100005);/*Read */
511 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
512 ixLCAC_MC0_CNTL
, 0x400005);/* CH0,1 write */
513 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
514 ixLCAC_MC1_CNTL
, 0x400005);/* CH2,3 write */
515 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
516 ixLCAC_CPL_CNTL
, 0x500005);/* write */
523 int tonga_start_dpm(struct pp_hwmgr
*hwmgr
)
525 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
527 /* enable general power management */
528 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, GLOBAL_PWRMGT_EN
, 1);
529 /* enable sclk deep sleep */
530 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
, DYNAMIC_PM_EN
, 1);
532 /* prepare for PCIE DPM */
533 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, data
->soft_regs_start
+
534 offsetof(SMU72_SoftRegisters
, VoltageChangeTimeout
), 0x1000);
536 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__PCIE
, SWRST_COMMAND_1
, RESETLC
, 0x0);
539 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
540 PPSMC_MSG_Voltage_Cntl_Enable
)),
541 "Failed to enable voltage DPM during DPM Start Function!",
544 if (0 != tonga_enable_sclk_mclk_dpm(hwmgr
)) {
545 PP_ASSERT_WITH_CODE(0, "Failed to enable Sclk DPM and Mclk DPM!", return -1);
548 /* enable PCIE dpm */
549 if (0 == data
->pcie_dpm_key_disabled
) {
551 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
552 PPSMC_MSG_PCIeDPM_Enable
)),
553 "Failed to enable pcie DPM during DPM Start Function!",
558 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
559 PHM_PlatformCaps_Falcon_QuickTransition
)) {
560 smum_send_msg_to_smc(hwmgr
->smumgr
,
561 PPSMC_MSG_EnableACDCGPIOInterrupt
);
567 int tonga_disable_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
569 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
571 /* disable SCLK dpm */
572 if (0 == data
->sclk_dpm_key_disabled
) {
573 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
575 !tonga_is_dpm_running(hwmgr
),
576 "Trying to Disable SCLK DPM when DPM is disabled",
581 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
582 PPSMC_MSG_DPM_Disable
)),
583 "Failed to disable SCLK DPM during DPM stop Function!",
587 /* disable MCLK dpm */
588 if (0 == data
->mclk_dpm_key_disabled
) {
589 /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
591 !tonga_is_dpm_running(hwmgr
),
592 "Trying to Disable MCLK DPM when DPM is disabled",
597 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
598 PPSMC_MSG_MCLKDPM_Disable
)),
599 "Failed to Disable MCLK DPM during DPM stop Function!",
606 int tonga_stop_dpm(struct pp_hwmgr
*hwmgr
)
608 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
610 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, GLOBAL_PWRMGT_EN
, 0);
611 /* disable sclk deep sleep*/
612 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
, DYNAMIC_PM_EN
, 0);
614 /* disable PCIE dpm */
615 if (0 == data
->pcie_dpm_key_disabled
) {
616 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
618 !tonga_is_dpm_running(hwmgr
),
619 "Trying to Disable PCIE DPM when DPM is disabled",
623 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
624 PPSMC_MSG_PCIeDPM_Disable
)),
625 "Failed to disable pcie DPM during DPM stop Function!",
629 if (0 != tonga_disable_sclk_mclk_dpm(hwmgr
))
630 PP_ASSERT_WITH_CODE(0, "Failed to disable Sclk DPM and Mclk DPM!", return -1);
632 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
634 !tonga_is_dpm_running(hwmgr
),
635 "Trying to Disable Voltage CNTL when DPM is disabled",
640 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
641 PPSMC_MSG_Voltage_Cntl_Disable
)),
642 "Failed to disable voltage DPM during DPM stop Function!",
648 int tonga_enable_sclk_control(struct pp_hwmgr
*hwmgr
)
650 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
, SCLK_PWRMGT_OFF
, 0);
656 * Send a message to the SMC and return a parameter
658 * @param hwmgr: the address of the powerplay hardware manager.
659 * @param msg: the message to send.
660 * @param parameter: pointer to the received parameter
661 * @return The response that came from the SMC.
663 PPSMC_Result
tonga_send_msg_to_smc_return_parameter(
664 struct pp_hwmgr
*hwmgr
,
670 result
= smum_send_msg_to_smc(hwmgr
->smumgr
, msg
);
672 if ((0 == result
) && parameter
) {
673 *parameter
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
680 * force DPM power State
682 * @param hwmgr: the address of the powerplay hardware manager.
683 * @param n : DPM level
684 * @return The response that came from the SMC.
686 int tonga_dpm_force_state(struct pp_hwmgr
*hwmgr
, uint32_t n
)
688 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
689 uint32_t level_mask
= 1 << n
;
691 /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
692 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
693 "Trying to force SCLK when DPM is disabled",
695 if (0 == data
->sclk_dpm_key_disabled
)
696 return (0 == smum_send_msg_to_smc_with_parameter(
698 (PPSMC_Msg
)(PPSMC_MSG_SCLKDPM_SetEnabledMask
),
699 level_mask
) ? 0 : 1);
705 * force DPM power State
707 * @param hwmgr: the address of the powerplay hardware manager.
708 * @param n : DPM level
709 * @return The response that came from the SMC.
711 int tonga_dpm_force_state_mclk(struct pp_hwmgr
*hwmgr
, uint32_t n
)
713 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
714 uint32_t level_mask
= 1 << n
;
716 /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
717 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
718 "Trying to Force MCLK when DPM is disabled",
720 if (0 == data
->mclk_dpm_key_disabled
)
721 return (0 == smum_send_msg_to_smc_with_parameter(
723 (PPSMC_Msg
)(PPSMC_MSG_MCLKDPM_SetEnabledMask
),
724 level_mask
) ? 0 : 1);
730 * force DPM power State
732 * @param hwmgr: the address of the powerplay hardware manager.
733 * @param n : DPM level
734 * @return The response that came from the SMC.
736 int tonga_dpm_force_state_pcie(struct pp_hwmgr
*hwmgr
, uint32_t n
)
738 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
740 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
741 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
742 "Trying to Force PCIE level when DPM is disabled",
744 if (0 == data
->pcie_dpm_key_disabled
)
745 return (0 == smum_send_msg_to_smc_with_parameter(
747 (PPSMC_Msg
)(PPSMC_MSG_PCIeDPM_ForceLevel
),
754 * Set the initial state by calling SMC to switch to this state directly
756 * @param hwmgr the address of the powerplay hardware manager.
759 int tonga_set_boot_state(struct pp_hwmgr
*hwmgr
)
762 * SMC only stores one state that SW will ask to switch too,
763 * so we switch the the just uploaded one
765 return (0 == tonga_disable_sclk_mclk_dpm(hwmgr
)) ? 0 : 1;
769 * Get the location of various tables inside the FW image.
771 * @param hwmgr the address of the powerplay hardware manager.
774 int tonga_process_firmware_header(struct pp_hwmgr
*hwmgr
)
776 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
777 struct tonga_smumgr
*tonga_smu
= (struct tonga_smumgr
*)(hwmgr
->smumgr
->backend
);
783 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
784 SMU72_FIRMWARE_HEADER_LOCATION
+
785 offsetof(SMU72_Firmware_Header
, DpmTable
),
786 &tmp
, data
->sram_end
);
789 data
->dpm_table_start
= tmp
;
792 error
|= (0 != result
);
794 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
795 SMU72_FIRMWARE_HEADER_LOCATION
+
796 offsetof(SMU72_Firmware_Header
, SoftRegisters
),
797 &tmp
, data
->sram_end
);
800 data
->soft_regs_start
= tmp
;
801 tonga_smu
->ulSoftRegsStart
= tmp
;
804 error
|= (0 != result
);
807 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
808 SMU72_FIRMWARE_HEADER_LOCATION
+
809 offsetof(SMU72_Firmware_Header
, mcRegisterTable
),
810 &tmp
, data
->sram_end
);
813 data
->mc_reg_table_start
= tmp
;
816 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
817 SMU72_FIRMWARE_HEADER_LOCATION
+
818 offsetof(SMU72_Firmware_Header
, FanTable
),
819 &tmp
, data
->sram_end
);
822 data
->fan_table_start
= tmp
;
825 error
|= (0 != result
);
827 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
828 SMU72_FIRMWARE_HEADER_LOCATION
+
829 offsetof(SMU72_Firmware_Header
, mcArbDramTimingTable
),
830 &tmp
, data
->sram_end
);
833 data
->arb_table_start
= tmp
;
836 error
|= (0 != result
);
839 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
840 SMU72_FIRMWARE_HEADER_LOCATION
+
841 offsetof(SMU72_Firmware_Header
, Version
),
842 &tmp
, data
->sram_end
);
845 hwmgr
->microcode_version_info
.SMC
= tmp
;
848 error
|= (0 != result
);
850 return error
? 1 : 0;
854 * Read clock related registers.
856 * @param hwmgr the address of the powerplay hardware manager.
859 int tonga_read_clock_registers(struct pp_hwmgr
*hwmgr
)
861 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
863 data
->clock_registers
.vCG_SPLL_FUNC_CNTL
=
864 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL
);
865 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
=
866 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL_2
);
867 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
=
868 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL_3
);
869 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
=
870 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL_4
);
871 data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
=
872 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_SPREAD_SPECTRUM
);
873 data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
=
874 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_SPREAD_SPECTRUM_2
);
875 data
->clock_registers
.vDLL_CNTL
=
876 cgs_read_register(hwmgr
->device
, mmDLL_CNTL
);
877 data
->clock_registers
.vMCLK_PWRMGT_CNTL
=
878 cgs_read_register(hwmgr
->device
, mmMCLK_PWRMGT_CNTL
);
879 data
->clock_registers
.vMPLL_AD_FUNC_CNTL
=
880 cgs_read_register(hwmgr
->device
, mmMPLL_AD_FUNC_CNTL
);
881 data
->clock_registers
.vMPLL_DQ_FUNC_CNTL
=
882 cgs_read_register(hwmgr
->device
, mmMPLL_DQ_FUNC_CNTL
);
883 data
->clock_registers
.vMPLL_FUNC_CNTL
=
884 cgs_read_register(hwmgr
->device
, mmMPLL_FUNC_CNTL
);
885 data
->clock_registers
.vMPLL_FUNC_CNTL_1
=
886 cgs_read_register(hwmgr
->device
, mmMPLL_FUNC_CNTL_1
);
887 data
->clock_registers
.vMPLL_FUNC_CNTL_2
=
888 cgs_read_register(hwmgr
->device
, mmMPLL_FUNC_CNTL_2
);
889 data
->clock_registers
.vMPLL_SS1
=
890 cgs_read_register(hwmgr
->device
, mmMPLL_SS1
);
891 data
->clock_registers
.vMPLL_SS2
=
892 cgs_read_register(hwmgr
->device
, mmMPLL_SS2
);
898 * Find out if memory is GDDR5.
900 * @param hwmgr the address of the powerplay hardware manager.
903 int tonga_get_memory_type(struct pp_hwmgr
*hwmgr
)
905 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
908 temp
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC0
);
910 data
->is_memory_GDDR5
= (MC_SEQ_MISC0_GDDR5_VALUE
==
911 ((temp
& MC_SEQ_MISC0_GDDR5_MASK
) >>
912 MC_SEQ_MISC0_GDDR5_SHIFT
));
918 * Enables Dynamic Power Management by SMC
920 * @param hwmgr the address of the powerplay hardware manager.
923 int tonga_enable_acpi_power_management(struct pp_hwmgr
*hwmgr
)
925 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, STATIC_PM_EN
, 1);
931 * Initialize PowerGating States for different engines
933 * @param hwmgr the address of the powerplay hardware manager.
936 int tonga_init_power_gate_state(struct pp_hwmgr
*hwmgr
)
938 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
940 data
->uvd_power_gated
= false;
941 data
->vce_power_gated
= false;
942 data
->samu_power_gated
= false;
943 data
->acp_power_gated
= false;
944 data
->pg_acp_init
= true;
950 * Checks if DPM is enabled
952 * @param hwmgr the address of the powerplay hardware manager.
955 int tonga_check_for_dpm_running(struct pp_hwmgr
*hwmgr
)
958 * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
959 * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
960 * whereas voltage control is a fundemental change that will not be disabled
962 return (!tonga_is_dpm_running(hwmgr
) ? 0 : 1);
966 * Checks if DPM is stopped
968 * @param hwmgr the address of the powerplay hardware manager.
971 int tonga_check_for_dpm_stopped(struct pp_hwmgr
*hwmgr
)
973 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
975 if (tonga_is_dpm_running(hwmgr
)) {
976 /* If HW Virtualization is enabled, dpm_table_start will not have a valid value */
977 if (!data
->dpm_table_start
) {
986 * Remove repeated voltage values and create table with unique values.
988 * @param hwmgr the address of the powerplay hardware manager.
989 * @param voltage_table the pointer to changing voltage table
990 * @return 1 in success
993 static int tonga_trim_voltage_table(struct pp_hwmgr
*hwmgr
,
994 pp_atomctrl_voltage_table
*voltage_table
)
996 uint32_t table_size
, i
, j
;
998 bool bVoltageFound
= false;
999 pp_atomctrl_voltage_table
*table
;
1001 PP_ASSERT_WITH_CODE((NULL
!= voltage_table
), "Voltage Table empty.", return -1;);
1002 table_size
= sizeof(pp_atomctrl_voltage_table
);
1003 table
= kzalloc(table_size
, GFP_KERNEL
);
1008 memset(table
, 0x00, table_size
);
1009 table
->mask_low
= voltage_table
->mask_low
;
1010 table
->phase_delay
= voltage_table
->phase_delay
;
1012 for (i
= 0; i
< voltage_table
->count
; i
++) {
1013 vvalue
= voltage_table
->entries
[i
].value
;
1014 bVoltageFound
= false;
1016 for (j
= 0; j
< table
->count
; j
++) {
1017 if (vvalue
== table
->entries
[j
].value
) {
1018 bVoltageFound
= true;
1023 if (!bVoltageFound
) {
1024 table
->entries
[table
->count
].value
= vvalue
;
1025 table
->entries
[table
->count
].smio_low
=
1026 voltage_table
->entries
[i
].smio_low
;
1031 memcpy(table
, voltage_table
, sizeof(pp_atomctrl_voltage_table
));
1038 static int tonga_get_svi2_vdd_ci_voltage_table(
1039 struct pp_hwmgr
*hwmgr
,
1040 phm_ppt_v1_clock_voltage_dependency_table
*voltage_dependency_table
)
1044 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1045 pp_atomctrl_voltage_table
*vddci_voltage_table
= &(data
->vddci_voltage_table
);
1047 PP_ASSERT_WITH_CODE((0 != voltage_dependency_table
->count
),
1048 "Voltage Dependency Table empty.", return -1;);
1050 vddci_voltage_table
->mask_low
= 0;
1051 vddci_voltage_table
->phase_delay
= 0;
1052 vddci_voltage_table
->count
= voltage_dependency_table
->count
;
1054 for (i
= 0; i
< voltage_dependency_table
->count
; i
++) {
1055 vddci_voltage_table
->entries
[i
].value
=
1056 voltage_dependency_table
->entries
[i
].vddci
;
1057 vddci_voltage_table
->entries
[i
].smio_low
= 0;
1060 result
= tonga_trim_voltage_table(hwmgr
, vddci_voltage_table
);
1061 PP_ASSERT_WITH_CODE((0 == result
),
1062 "Failed to trim VDDCI table.", return result
;);
1069 static int tonga_get_svi2_vdd_voltage_table(
1070 struct pp_hwmgr
*hwmgr
,
1071 phm_ppt_v1_voltage_lookup_table
*look_up_table
,
1072 pp_atomctrl_voltage_table
*voltage_table
)
1076 PP_ASSERT_WITH_CODE((0 != look_up_table
->count
),
1077 "Voltage Lookup Table empty.", return -1;);
1079 voltage_table
->mask_low
= 0;
1080 voltage_table
->phase_delay
= 0;
1082 voltage_table
->count
= look_up_table
->count
;
1084 for (i
= 0; i
< voltage_table
->count
; i
++) {
1085 voltage_table
->entries
[i
].value
= look_up_table
->entries
[i
].us_vdd
;
1086 voltage_table
->entries
[i
].smio_low
= 0;
1093 * -------------------------------------------------------- Voltage Tables --------------------------------------------------------------------------
1094 * If the voltage table would be bigger than what will fit into the state table on the SMC keep only the higher entries.
1097 static void tonga_trim_voltage_table_to_fit_state_table(
1098 struct pp_hwmgr
*hwmgr
,
1099 uint32_t max_voltage_steps
,
1100 pp_atomctrl_voltage_table
*voltage_table
)
1102 unsigned int i
, diff
;
1104 if (voltage_table
->count
<= max_voltage_steps
) {
1108 diff
= voltage_table
->count
- max_voltage_steps
;
1110 for (i
= 0; i
< max_voltage_steps
; i
++) {
1111 voltage_table
->entries
[i
] = voltage_table
->entries
[i
+ diff
];
1114 voltage_table
->count
= max_voltage_steps
;
1120 * Create Voltage Tables.
1122 * @param hwmgr the address of the powerplay hardware manager.
1125 int tonga_construct_voltage_tables(struct pp_hwmgr
*hwmgr
)
1127 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1128 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1131 /* MVDD has only GPIO voltage control */
1132 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1133 result
= atomctrl_get_voltage_table_v3(hwmgr
,
1134 VOLTAGE_TYPE_MVDDC
, VOLTAGE_OBJ_GPIO_LUT
, &(data
->mvdd_voltage_table
));
1135 PP_ASSERT_WITH_CODE((0 == result
),
1136 "Failed to retrieve MVDD table.", return result
;);
1139 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->vdd_ci_control
) {
1141 result
= atomctrl_get_voltage_table_v3(hwmgr
,
1142 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_GPIO_LUT
, &(data
->vddci_voltage_table
));
1143 PP_ASSERT_WITH_CODE((0 == result
),
1144 "Failed to retrieve VDDCI table.", return result
;);
1145 } else if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_ci_control
) {
1147 result
= tonga_get_svi2_vdd_ci_voltage_table(hwmgr
,
1148 pptable_info
->vdd_dep_on_mclk
);
1149 PP_ASSERT_WITH_CODE((0 == result
),
1150 "Failed to retrieve SVI2 VDDCI table from dependancy table.", return result
;);
1153 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_gfx_control
) {
1154 /* VDDGFX has only SVI2 voltage control */
1155 result
= tonga_get_svi2_vdd_voltage_table(hwmgr
,
1156 pptable_info
->vddgfx_lookup_table
, &(data
->vddgfx_voltage_table
));
1157 PP_ASSERT_WITH_CODE((0 == result
),
1158 "Failed to retrieve SVI2 VDDGFX table from lookup table.", return result
;);
1161 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1162 /* VDDC has only SVI2 voltage control */
1163 result
= tonga_get_svi2_vdd_voltage_table(hwmgr
,
1164 pptable_info
->vddc_lookup_table
, &(data
->vddc_voltage_table
));
1165 PP_ASSERT_WITH_CODE((0 == result
),
1166 "Failed to retrieve SVI2 VDDC table from lookup table.", return result
;);
1169 PP_ASSERT_WITH_CODE(
1170 (data
->vddc_voltage_table
.count
<= (SMU72_MAX_LEVELS_VDDC
)),
1171 "Too many voltage values for VDDC. Trimming to fit state table.",
1172 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1173 SMU72_MAX_LEVELS_VDDC
, &(data
->vddc_voltage_table
));
1176 PP_ASSERT_WITH_CODE(
1177 (data
->vddgfx_voltage_table
.count
<= (SMU72_MAX_LEVELS_VDDGFX
)),
1178 "Too many voltage values for VDDGFX. Trimming to fit state table.",
1179 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1180 SMU72_MAX_LEVELS_VDDGFX
, &(data
->vddgfx_voltage_table
));
1183 PP_ASSERT_WITH_CODE(
1184 (data
->vddci_voltage_table
.count
<= (SMU72_MAX_LEVELS_VDDCI
)),
1185 "Too many voltage values for VDDCI. Trimming to fit state table.",
1186 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1187 SMU72_MAX_LEVELS_VDDCI
, &(data
->vddci_voltage_table
));
1190 PP_ASSERT_WITH_CODE(
1191 (data
->mvdd_voltage_table
.count
<= (SMU72_MAX_LEVELS_MVDD
)),
1192 "Too many voltage values for MVDD. Trimming to fit state table.",
1193 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1194 SMU72_MAX_LEVELS_MVDD
, &(data
->mvdd_voltage_table
));
1201 * Vddc table preparation for SMC.
1203 * @param hwmgr the address of the hardware manager
1204 * @param table the SMC DPM table structure to be populated
1207 static int tonga_populate_smc_vddc_table(struct pp_hwmgr
*hwmgr
,
1208 SMU72_Discrete_DpmTable
*table
)
1211 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1213 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1214 table
->VddcLevelCount
= data
->vddc_voltage_table
.count
;
1215 for (count
= 0; count
< table
->VddcLevelCount
; count
++) {
1216 table
->VddcTable
[count
] =
1217 PP_HOST_TO_SMC_US(data
->vddc_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1219 CONVERT_FROM_HOST_TO_SMC_UL(table
->VddcLevelCount
);
1225 * VddGfx table preparation for SMC.
1227 * @param hwmgr the address of the hardware manager
1228 * @param table the SMC DPM table structure to be populated
1231 static int tonga_populate_smc_vdd_gfx_table(struct pp_hwmgr
*hwmgr
,
1232 SMU72_Discrete_DpmTable
*table
)
1235 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1237 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_gfx_control
) {
1238 table
->VddGfxLevelCount
= data
->vddgfx_voltage_table
.count
;
1239 for (count
= 0; count
< data
->vddgfx_voltage_table
.count
; count
++) {
1240 table
->VddGfxTable
[count
] =
1241 PP_HOST_TO_SMC_US(data
->vddgfx_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1243 CONVERT_FROM_HOST_TO_SMC_UL(table
->VddGfxLevelCount
);
1249 * Vddci table preparation for SMC.
1251 * @param *hwmgr The address of the hardware manager.
1252 * @param *table The SMC DPM table structure to be populated.
1255 static int tonga_populate_smc_vdd_ci_table(struct pp_hwmgr
*hwmgr
,
1256 SMU72_Discrete_DpmTable
*table
)
1258 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1261 table
->VddciLevelCount
= data
->vddci_voltage_table
.count
;
1262 for (count
= 0; count
< table
->VddciLevelCount
; count
++) {
1263 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_ci_control
) {
1264 table
->VddciTable
[count
] =
1265 PP_HOST_TO_SMC_US(data
->vddci_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1266 } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->vdd_ci_control
) {
1267 table
->SmioTable1
.Pattern
[count
].Voltage
=
1268 PP_HOST_TO_SMC_US(data
->vddci_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1269 /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level. */
1270 table
->SmioTable1
.Pattern
[count
].Smio
=
1272 table
->Smio
[count
] |=
1273 data
->vddci_voltage_table
.entries
[count
].smio_low
;
1274 table
->VddciTable
[count
] =
1275 PP_HOST_TO_SMC_US(data
->vddci_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1279 table
->SmioMask1
= data
->vddci_voltage_table
.mask_low
;
1280 CONVERT_FROM_HOST_TO_SMC_UL(table
->VddciLevelCount
);
1286 * Mvdd table preparation for SMC.
1288 * @param *hwmgr The address of the hardware manager.
1289 * @param *table The SMC DPM table structure to be populated.
1292 static int tonga_populate_smc_mvdd_table(struct pp_hwmgr
*hwmgr
,
1293 SMU72_Discrete_DpmTable
*table
)
1295 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1298 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1299 table
->MvddLevelCount
= data
->mvdd_voltage_table
.count
;
1300 for (count
= 0; count
< table
->MvddLevelCount
; count
++) {
1301 table
->SmioTable2
.Pattern
[count
].Voltage
=
1302 PP_HOST_TO_SMC_US(data
->mvdd_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1303 /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/
1304 table
->SmioTable2
.Pattern
[count
].Smio
=
1306 table
->Smio
[count
] |=
1307 data
->mvdd_voltage_table
.entries
[count
].smio_low
;
1309 table
->SmioMask2
= data
->mvdd_voltage_table
.mask_low
;
1311 CONVERT_FROM_HOST_TO_SMC_UL(table
->MvddLevelCount
);
1318 * Convert a voltage value in mv unit to VID number required by SMU firmware
1320 static uint8_t convert_to_vid(uint16_t vddc
)
1322 return (uint8_t) ((6200 - (vddc
* VOLTAGE_SCALE
)) / 25);
1327 * Preparation of vddc and vddgfx CAC tables for SMC.
1329 * @param hwmgr the address of the hardware manager
1330 * @param table the SMC DPM table structure to be populated
1333 static int tonga_populate_cac_tables(struct pp_hwmgr
*hwmgr
,
1334 SMU72_Discrete_DpmTable
*table
)
1338 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1339 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1340 struct phm_ppt_v1_voltage_lookup_table
*vddgfx_lookup_table
= pptable_info
->vddgfx_lookup_table
;
1341 struct phm_ppt_v1_voltage_lookup_table
*vddc_lookup_table
= pptable_info
->vddc_lookup_table
;
1343 /* pTables is already swapped, so in order to use the value from it, we need to swap it back. */
1344 uint32_t vddcLevelCount
= PP_SMC_TO_HOST_UL(table
->VddcLevelCount
);
1345 uint32_t vddgfxLevelCount
= PP_SMC_TO_HOST_UL(table
->VddGfxLevelCount
);
1347 for (count
= 0; count
< vddcLevelCount
; count
++) {
1348 /* We are populating vddc CAC data to BapmVddc table in split and merged mode */
1349 index
= tonga_get_voltage_index(vddc_lookup_table
,
1350 data
->vddc_voltage_table
.entries
[count
].value
);
1351 table
->BapmVddcVidLoSidd
[count
] =
1352 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_low
);
1353 table
->BapmVddcVidHiSidd
[count
] =
1354 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_mid
);
1355 table
->BapmVddcVidHiSidd2
[count
] =
1356 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_high
);
1359 if ((data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
)) {
1360 /* We are populating vddgfx CAC data to BapmVddgfx table in split mode */
1361 for (count
= 0; count
< vddgfxLevelCount
; count
++) {
1362 index
= tonga_get_voltage_index(vddgfx_lookup_table
,
1363 data
->vddgfx_voltage_table
.entries
[count
].value
);
1364 table
->BapmVddGfxVidLoSidd
[count
] =
1365 convert_to_vid(vddgfx_lookup_table
->entries
[index
].us_cac_low
);
1366 table
->BapmVddGfxVidHiSidd
[count
] =
1367 convert_to_vid(vddgfx_lookup_table
->entries
[index
].us_cac_mid
);
1368 table
->BapmVddGfxVidHiSidd2
[count
] =
1369 convert_to_vid(vddgfx_lookup_table
->entries
[index
].us_cac_high
);
1372 for (count
= 0; count
< vddcLevelCount
; count
++) {
1373 index
= tonga_get_voltage_index(vddc_lookup_table
,
1374 data
->vddc_voltage_table
.entries
[count
].value
);
1375 table
->BapmVddGfxVidLoSidd
[count
] =
1376 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_low
);
1377 table
->BapmVddGfxVidHiSidd
[count
] =
1378 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_mid
);
1379 table
->BapmVddGfxVidHiSidd2
[count
] =
1380 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_high
);
1389 * Preparation of voltage tables for SMC.
1391 * @param hwmgr the address of the hardware manager
1392 * @param table the SMC DPM table structure to be populated
1396 int tonga_populate_smc_voltage_tables(struct pp_hwmgr
*hwmgr
,
1397 SMU72_Discrete_DpmTable
*table
)
1401 result
= tonga_populate_smc_vddc_table(hwmgr
, table
);
1402 PP_ASSERT_WITH_CODE(0 == result
,
1403 "can not populate VDDC voltage table to SMC", return -1);
1405 result
= tonga_populate_smc_vdd_ci_table(hwmgr
, table
);
1406 PP_ASSERT_WITH_CODE(0 == result
,
1407 "can not populate VDDCI voltage table to SMC", return -1);
1409 result
= tonga_populate_smc_vdd_gfx_table(hwmgr
, table
);
1410 PP_ASSERT_WITH_CODE(0 == result
,
1411 "can not populate VDDGFX voltage table to SMC", return -1);
1413 result
= tonga_populate_smc_mvdd_table(hwmgr
, table
);
1414 PP_ASSERT_WITH_CODE(0 == result
,
1415 "can not populate MVDD voltage table to SMC", return -1);
1417 result
= tonga_populate_cac_tables(hwmgr
, table
);
1418 PP_ASSERT_WITH_CODE(0 == result
,
1419 "can not populate CAC voltage tables to SMC", return -1);
1425 * Populates the SMC VRConfig field in DPM table.
1427 * @param hwmgr the address of the hardware manager
1428 * @param table the SMC DPM table structure to be populated
1431 static int tonga_populate_vr_config(struct pp_hwmgr
*hwmgr
,
1432 SMU72_Discrete_DpmTable
*table
)
1434 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1437 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_gfx_control
) {
1439 config
= VR_SVI2_PLANE_1
;
1440 table
->VRConfig
|= (config
<<VRCONF_VDDGFX_SHIFT
);
1442 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1443 config
= VR_SVI2_PLANE_2
;
1444 table
->VRConfig
|= config
;
1446 printk(KERN_ERR
"[ powerplay ] VDDC and VDDGFX should be both on SVI2 control in splitted mode! \n");
1450 config
= VR_MERGED_WITH_VDDC
;
1451 table
->VRConfig
|= (config
<<VRCONF_VDDGFX_SHIFT
);
1453 /* Set Vddc Voltage Controller */
1454 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1455 config
= VR_SVI2_PLANE_1
;
1456 table
->VRConfig
|= config
;
1458 printk(KERN_ERR
"[ powerplay ] VDDC should be on SVI2 control in merged mode! \n");
1462 /* Set Vddci Voltage Controller */
1463 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_ci_control
) {
1464 config
= VR_SVI2_PLANE_2
; /* only in merged mode */
1465 table
->VRConfig
|= (config
<<VRCONF_VDDCI_SHIFT
);
1466 } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->vdd_ci_control
) {
1467 config
= VR_SMIO_PATTERN_1
;
1468 table
->VRConfig
|= (config
<<VRCONF_VDDCI_SHIFT
);
1471 /* Set Mvdd Voltage Controller */
1472 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1473 config
= VR_SMIO_PATTERN_2
;
1474 table
->VRConfig
|= (config
<<VRCONF_MVDD_SHIFT
);
1480 static int tonga_get_dependecy_volt_by_clk(struct pp_hwmgr
*hwmgr
,
1481 phm_ppt_v1_clock_voltage_dependency_table
*allowed_clock_voltage_table
,
1482 uint32_t clock
, SMU_VoltageLevel
*voltage
, uint32_t *mvdd
)
1485 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1486 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1488 /* clock - voltage dependency table is empty table */
1489 if (allowed_clock_voltage_table
->count
== 0)
1492 for (i
= 0; i
< allowed_clock_voltage_table
->count
; i
++) {
1493 /* find first sclk bigger than request */
1494 if (allowed_clock_voltage_table
->entries
[i
].clk
>= clock
) {
1495 voltage
->VddGfx
= tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1496 allowed_clock_voltage_table
->entries
[i
].vddgfx
);
1498 voltage
->Vddc
= tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1499 allowed_clock_voltage_table
->entries
[i
].vddc
);
1501 if (allowed_clock_voltage_table
->entries
[i
].vddci
) {
1502 voltage
->Vddci
= tonga_get_voltage_id(&data
->vddci_voltage_table
,
1503 allowed_clock_voltage_table
->entries
[i
].vddci
);
1505 voltage
->Vddci
= tonga_get_voltage_id(&data
->vddci_voltage_table
,
1506 allowed_clock_voltage_table
->entries
[i
].vddc
- data
->vddc_vddci_delta
);
1509 if (allowed_clock_voltage_table
->entries
[i
].mvdd
) {
1510 *mvdd
= (uint32_t) allowed_clock_voltage_table
->entries
[i
].mvdd
;
1513 voltage
->Phases
= 1;
1518 /* sclk is bigger than max sclk in the dependence table */
1519 voltage
->VddGfx
= tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1520 allowed_clock_voltage_table
->entries
[i
-1].vddgfx
);
1521 voltage
->Vddc
= tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1522 allowed_clock_voltage_table
->entries
[i
-1].vddc
);
1524 if (allowed_clock_voltage_table
->entries
[i
-1].vddci
) {
1525 voltage
->Vddci
= tonga_get_voltage_id(&data
->vddci_voltage_table
,
1526 allowed_clock_voltage_table
->entries
[i
-1].vddci
);
1528 if (allowed_clock_voltage_table
->entries
[i
-1].mvdd
) {
1529 *mvdd
= (uint32_t) allowed_clock_voltage_table
->entries
[i
-1].mvdd
;
1536 * Call SMC to reset S0/S1 to S1 and Reset SMIO to initial value
1538 * @param hwmgr the address of the powerplay hardware manager.
1541 int tonga_reset_to_default(struct pp_hwmgr
*hwmgr
)
1543 return (smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_ResetToDefaults
) == 0) ? 0 : 1;
1546 int tonga_populate_memory_timing_parameters(
1547 struct pp_hwmgr
*hwmgr
,
1548 uint32_t engine_clock
,
1549 uint32_t memory_clock
,
1550 struct SMU72_Discrete_MCArbDramTimingTableEntry
*arb_regs
1553 uint32_t dramTiming
;
1554 uint32_t dramTiming2
;
1558 result
= atomctrl_set_engine_dram_timings_rv770(hwmgr
,
1559 engine_clock
, memory_clock
);
1561 PP_ASSERT_WITH_CODE(result
== 0,
1562 "Error calling VBIOS to set DRAM_TIMING.", return result
);
1564 dramTiming
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
1565 dramTiming2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
1566 burstTime
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
);
1568 arb_regs
->McArbDramTiming
= PP_HOST_TO_SMC_UL(dramTiming
);
1569 arb_regs
->McArbDramTiming2
= PP_HOST_TO_SMC_UL(dramTiming2
);
1570 arb_regs
->McArbBurstTime
= (uint8_t)burstTime
;
1576 * Setup parameters for the MC ARB.
1578 * @param hwmgr the address of the powerplay hardware manager.
1580 * This function is to be called from the SetPowerState table.
1582 int tonga_program_memory_timing_parameters(struct pp_hwmgr
*hwmgr
)
1584 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1586 SMU72_Discrete_MCArbDramTimingTable arb_regs
;
1589 memset(&arb_regs
, 0x00, sizeof(SMU72_Discrete_MCArbDramTimingTable
));
1591 for (i
= 0; i
< data
->dpm_table
.sclk_table
.count
; i
++) {
1592 for (j
= 0; j
< data
->dpm_table
.mclk_table
.count
; j
++) {
1593 result
= tonga_populate_memory_timing_parameters
1594 (hwmgr
, data
->dpm_table
.sclk_table
.dpm_levels
[i
].value
,
1595 data
->dpm_table
.mclk_table
.dpm_levels
[j
].value
,
1596 &arb_regs
.entries
[i
][j
]);
1605 result
= tonga_copy_bytes_to_smc(
1607 data
->arb_table_start
,
1608 (uint8_t *)&arb_regs
,
1609 sizeof(SMU72_Discrete_MCArbDramTimingTable
),
1617 static int tonga_populate_smc_link_level(struct pp_hwmgr
*hwmgr
, SMU72_Discrete_DpmTable
*table
)
1619 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1620 struct tonga_dpm_table
*dpm_table
= &data
->dpm_table
;
1623 /* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */
1624 for (i
= 0; i
<= dpm_table
->pcie_speed_table
.count
; i
++) {
1625 table
->LinkLevel
[i
].PcieGenSpeed
=
1626 (uint8_t)dpm_table
->pcie_speed_table
.dpm_levels
[i
].value
;
1627 table
->LinkLevel
[i
].PcieLaneCount
=
1628 (uint8_t)encode_pcie_lane_width(dpm_table
->pcie_speed_table
.dpm_levels
[i
].param1
);
1629 table
->LinkLevel
[i
].EnabledForActivity
=
1631 table
->LinkLevel
[i
].SPC
=
1632 (uint8_t)(data
->pcie_spc_cap
& 0xff);
1633 table
->LinkLevel
[i
].DownThreshold
=
1634 PP_HOST_TO_SMC_UL(5);
1635 table
->LinkLevel
[i
].UpThreshold
=
1636 PP_HOST_TO_SMC_UL(30);
1639 data
->smc_state_table
.LinkLevelCount
=
1640 (uint8_t)dpm_table
->pcie_speed_table
.count
;
1641 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
=
1642 tonga_get_dpm_level_enable_mask_value(&dpm_table
->pcie_speed_table
);
1647 static int tonga_populate_smc_uvd_level(struct pp_hwmgr
*hwmgr
,
1648 SMU72_Discrete_DpmTable
*table
)
1653 pp_atomctrl_clock_dividers_vi dividers
;
1654 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1655 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1656 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1658 table
->UvdLevelCount
= (uint8_t) (mm_table
->count
);
1659 table
->UvdBootLevel
= 0;
1661 for (count
= 0; count
< table
->UvdLevelCount
; count
++) {
1662 table
->UvdLevel
[count
].VclkFrequency
= mm_table
->entries
[count
].vclk
;
1663 table
->UvdLevel
[count
].DclkFrequency
= mm_table
->entries
[count
].dclk
;
1664 table
->UvdLevel
[count
].MinVoltage
.Vddc
=
1665 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1666 mm_table
->entries
[count
].vddc
);
1667 table
->UvdLevel
[count
].MinVoltage
.VddGfx
=
1668 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1669 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1670 mm_table
->entries
[count
].vddgfx
) : 0;
1671 table
->UvdLevel
[count
].MinVoltage
.Vddci
=
1672 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1673 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1674 table
->UvdLevel
[count
].MinVoltage
.Phases
= 1;
1676 /* retrieve divider value for VBIOS */
1677 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1678 table
->UvdLevel
[count
].VclkFrequency
, ÷rs
);
1679 PP_ASSERT_WITH_CODE((0 == result
),
1680 "can not find divide id for Vclk clock", return result
);
1682 table
->UvdLevel
[count
].VclkDivider
= (uint8_t)dividers
.pll_post_divider
;
1684 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1685 table
->UvdLevel
[count
].DclkFrequency
, ÷rs
);
1686 PP_ASSERT_WITH_CODE((0 == result
),
1687 "can not find divide id for Dclk clock", return result
);
1689 table
->UvdLevel
[count
].DclkDivider
= (uint8_t)dividers
.pll_post_divider
;
1691 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].VclkFrequency
);
1692 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].DclkFrequency
);
1693 //CONVERT_FROM_HOST_TO_SMC_UL((uint32_t)table->UvdLevel[count].MinVoltage);
1700 static int tonga_populate_smc_vce_level(struct pp_hwmgr
*hwmgr
,
1701 SMU72_Discrete_DpmTable
*table
)
1706 pp_atomctrl_clock_dividers_vi dividers
;
1707 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1708 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1709 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1711 table
->VceLevelCount
= (uint8_t) (mm_table
->count
);
1712 table
->VceBootLevel
= 0;
1714 for (count
= 0; count
< table
->VceLevelCount
; count
++) {
1715 table
->VceLevel
[count
].Frequency
=
1716 mm_table
->entries
[count
].eclk
;
1717 table
->VceLevel
[count
].MinVoltage
.Vddc
=
1718 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1719 mm_table
->entries
[count
].vddc
);
1720 table
->VceLevel
[count
].MinVoltage
.VddGfx
=
1721 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1722 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1723 mm_table
->entries
[count
].vddgfx
) : 0;
1724 table
->VceLevel
[count
].MinVoltage
.Vddci
=
1725 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1726 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1727 table
->VceLevel
[count
].MinVoltage
.Phases
= 1;
1729 /* retrieve divider value for VBIOS */
1730 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1731 table
->VceLevel
[count
].Frequency
, ÷rs
);
1732 PP_ASSERT_WITH_CODE((0 == result
),
1733 "can not find divide id for VCE engine clock", return result
);
1735 table
->VceLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1737 CONVERT_FROM_HOST_TO_SMC_UL(table
->VceLevel
[count
].Frequency
);
1743 static int tonga_populate_smc_acp_level(struct pp_hwmgr
*hwmgr
,
1744 SMU72_Discrete_DpmTable
*table
)
1748 pp_atomctrl_clock_dividers_vi dividers
;
1749 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1750 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1751 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1753 table
->AcpLevelCount
= (uint8_t) (mm_table
->count
);
1754 table
->AcpBootLevel
= 0;
1756 for (count
= 0; count
< table
->AcpLevelCount
; count
++) {
1757 table
->AcpLevel
[count
].Frequency
=
1758 pptable_info
->mm_dep_table
->entries
[count
].aclk
;
1759 table
->AcpLevel
[count
].MinVoltage
.Vddc
=
1760 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1761 mm_table
->entries
[count
].vddc
);
1762 table
->AcpLevel
[count
].MinVoltage
.VddGfx
=
1763 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1764 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1765 mm_table
->entries
[count
].vddgfx
) : 0;
1766 table
->AcpLevel
[count
].MinVoltage
.Vddci
=
1767 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1768 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1769 table
->AcpLevel
[count
].MinVoltage
.Phases
= 1;
1771 /* retrieve divider value for VBIOS */
1772 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1773 table
->AcpLevel
[count
].Frequency
, ÷rs
);
1774 PP_ASSERT_WITH_CODE((0 == result
),
1775 "can not find divide id for engine clock", return result
);
1777 table
->AcpLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1779 CONVERT_FROM_HOST_TO_SMC_UL(table
->AcpLevel
[count
].Frequency
);
1785 static int tonga_populate_smc_samu_level(struct pp_hwmgr
*hwmgr
,
1786 SMU72_Discrete_DpmTable
*table
)
1790 pp_atomctrl_clock_dividers_vi dividers
;
1791 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1792 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1793 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1795 table
->SamuBootLevel
= 0;
1796 table
->SamuLevelCount
= (uint8_t) (mm_table
->count
);
1798 for (count
= 0; count
< table
->SamuLevelCount
; count
++) {
1799 /* not sure whether we need evclk or not */
1800 table
->SamuLevel
[count
].Frequency
=
1801 pptable_info
->mm_dep_table
->entries
[count
].samclock
;
1802 table
->SamuLevel
[count
].MinVoltage
.Vddc
=
1803 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1804 mm_table
->entries
[count
].vddc
);
1805 table
->SamuLevel
[count
].MinVoltage
.VddGfx
=
1806 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1807 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1808 mm_table
->entries
[count
].vddgfx
) : 0;
1809 table
->SamuLevel
[count
].MinVoltage
.Vddci
=
1810 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1811 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1812 table
->SamuLevel
[count
].MinVoltage
.Phases
= 1;
1814 /* retrieve divider value for VBIOS */
1815 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1816 table
->SamuLevel
[count
].Frequency
, ÷rs
);
1817 PP_ASSERT_WITH_CODE((0 == result
),
1818 "can not find divide id for samu clock", return result
);
1820 table
->SamuLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1822 CONVERT_FROM_HOST_TO_SMC_UL(table
->SamuLevel
[count
].Frequency
);
1829 * Populates the SMC MCLK structure using the provided memory clock
1831 * @param hwmgr the address of the hardware manager
1832 * @param memory_clock the memory clock to use to populate the structure
1833 * @param sclk the SMC SCLK structure to be populated
1835 static int tonga_calculate_mclk_params(
1836 struct pp_hwmgr
*hwmgr
,
1837 uint32_t memory_clock
,
1838 SMU72_Discrete_MemoryLevel
*mclk
,
1843 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1844 uint32_t dll_cntl
= data
->clock_registers
.vDLL_CNTL
;
1845 uint32_t mclk_pwrmgt_cntl
= data
->clock_registers
.vMCLK_PWRMGT_CNTL
;
1846 uint32_t mpll_ad_func_cntl
= data
->clock_registers
.vMPLL_AD_FUNC_CNTL
;
1847 uint32_t mpll_dq_func_cntl
= data
->clock_registers
.vMPLL_DQ_FUNC_CNTL
;
1848 uint32_t mpll_func_cntl
= data
->clock_registers
.vMPLL_FUNC_CNTL
;
1849 uint32_t mpll_func_cntl_1
= data
->clock_registers
.vMPLL_FUNC_CNTL_1
;
1850 uint32_t mpll_func_cntl_2
= data
->clock_registers
.vMPLL_FUNC_CNTL_2
;
1851 uint32_t mpll_ss1
= data
->clock_registers
.vMPLL_SS1
;
1852 uint32_t mpll_ss2
= data
->clock_registers
.vMPLL_SS2
;
1854 pp_atomctrl_memory_clock_param mpll_param
;
1857 result
= atomctrl_get_memory_pll_dividers_si(hwmgr
,
1858 memory_clock
, &mpll_param
, strobe_mode
);
1859 PP_ASSERT_WITH_CODE(0 == result
,
1860 "Error retrieving Memory Clock Parameters from VBIOS.", return result
);
1862 /* MPLL_FUNC_CNTL setup*/
1863 mpll_func_cntl
= PHM_SET_FIELD(mpll_func_cntl
, MPLL_FUNC_CNTL
, BWCTRL
, mpll_param
.bw_ctrl
);
1865 /* MPLL_FUNC_CNTL_1 setup*/
1866 mpll_func_cntl_1
= PHM_SET_FIELD(mpll_func_cntl_1
,
1867 MPLL_FUNC_CNTL_1
, CLKF
, mpll_param
.mpll_fb_divider
.cl_kf
);
1868 mpll_func_cntl_1
= PHM_SET_FIELD(mpll_func_cntl_1
,
1869 MPLL_FUNC_CNTL_1
, CLKFRAC
, mpll_param
.mpll_fb_divider
.clk_frac
);
1870 mpll_func_cntl_1
= PHM_SET_FIELD(mpll_func_cntl_1
,
1871 MPLL_FUNC_CNTL_1
, VCO_MODE
, mpll_param
.vco_mode
);
1873 /* MPLL_AD_FUNC_CNTL setup*/
1874 mpll_ad_func_cntl
= PHM_SET_FIELD(mpll_ad_func_cntl
,
1875 MPLL_AD_FUNC_CNTL
, YCLK_POST_DIV
, mpll_param
.mpll_post_divider
);
1877 if (data
->is_memory_GDDR5
) {
1878 /* MPLL_DQ_FUNC_CNTL setup*/
1879 mpll_dq_func_cntl
= PHM_SET_FIELD(mpll_dq_func_cntl
,
1880 MPLL_DQ_FUNC_CNTL
, YCLK_SEL
, mpll_param
.yclk_sel
);
1881 mpll_dq_func_cntl
= PHM_SET_FIELD(mpll_dq_func_cntl
,
1882 MPLL_DQ_FUNC_CNTL
, YCLK_POST_DIV
, mpll_param
.mpll_post_divider
);
1885 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
1886 PHM_PlatformCaps_MemorySpreadSpectrumSupport
)) {
1888 ************************************
1889 Fref = Reference Frequency
1890 NF = Feedback divider ratio
1891 NR = Reference divider ratio
1892 Fnom = Nominal VCO output frequency = Fref * NF / NR
1894 D = Percentage down-spread / 2
1895 Fint = Reference input frequency to PFD = Fref / NR
1896 NS = Spreading rate divider ratio = int(Fint / (2 * Fs))
1897 CLKS = NS - 1 = ISS_STEP_NUM[11:0]
1898 NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2)
1899 CLKV = 65536 * NV = ISS_STEP_SIZE[25:0]
1900 *************************************
1902 pp_atomctrl_internal_ss_info ss_info
;
1905 uint32_t reference_clock
= atomctrl_get_mpll_reference_clock(hwmgr
);
1907 /* for GDDR5 for all modes and DDR3 */
1908 if (1 == mpll_param
.qdr
)
1909 freq_nom
= memory_clock
* 4 * (1 << mpll_param
.mpll_post_divider
);
1911 freq_nom
= memory_clock
* 2 * (1 << mpll_param
.mpll_post_divider
);
1913 /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2 Note: S.I. reference_divider = 1*/
1914 tmp
= (freq_nom
/ reference_clock
);
1917 if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr
, freq_nom
, &ss_info
)) {
1918 /* ss_info.speed_spectrum_percentage -- in unit of 0.01% */
1919 /* ss.Info.speed_spectrum_rate -- in unit of khz */
1920 /* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */
1921 /* = reference_clock * 5 / speed_spectrum_rate */
1922 uint32_t clks
= reference_clock
* 5 / ss_info
.speed_spectrum_rate
;
1924 /* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */
1925 /* = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */
1927 (uint32_t)((((131 * ss_info
.speed_spectrum_percentage
*
1928 ss_info
.speed_spectrum_rate
) / 100) * tmp
) / freq_nom
);
1930 mpll_ss1
= PHM_SET_FIELD(mpll_ss1
, MPLL_SS1
, CLKV
, clkv
);
1931 mpll_ss2
= PHM_SET_FIELD(mpll_ss2
, MPLL_SS2
, CLKS
, clks
);
1935 /* MCLK_PWRMGT_CNTL setup */
1936 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
1937 MCLK_PWRMGT_CNTL
, DLL_SPEED
, mpll_param
.dll_speed
);
1938 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
1939 MCLK_PWRMGT_CNTL
, MRDCK0_PDNB
, dllStateOn
);
1940 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
1941 MCLK_PWRMGT_CNTL
, MRDCK1_PDNB
, dllStateOn
);
1944 /* Save the result data to outpupt memory level structure */
1945 mclk
->MclkFrequency
= memory_clock
;
1946 mclk
->MpllFuncCntl
= mpll_func_cntl
;
1947 mclk
->MpllFuncCntl_1
= mpll_func_cntl_1
;
1948 mclk
->MpllFuncCntl_2
= mpll_func_cntl_2
;
1949 mclk
->MpllAdFuncCntl
= mpll_ad_func_cntl
;
1950 mclk
->MpllDqFuncCntl
= mpll_dq_func_cntl
;
1951 mclk
->MclkPwrmgtCntl
= mclk_pwrmgt_cntl
;
1952 mclk
->DllCntl
= dll_cntl
;
1953 mclk
->MpllSs1
= mpll_ss1
;
1954 mclk
->MpllSs2
= mpll_ss2
;
1959 static uint8_t tonga_get_mclk_frequency_ratio(uint32_t memory_clock
,
1962 uint8_t mc_para_index
;
1965 if (memory_clock
< 12500) {
1966 mc_para_index
= 0x00;
1967 } else if (memory_clock
> 47500) {
1968 mc_para_index
= 0x0f;
1970 mc_para_index
= (uint8_t)((memory_clock
- 10000) / 2500);
1973 if (memory_clock
< 65000) {
1974 mc_para_index
= 0x00;
1975 } else if (memory_clock
> 135000) {
1976 mc_para_index
= 0x0f;
1978 mc_para_index
= (uint8_t)((memory_clock
- 60000) / 5000);
1982 return mc_para_index
;
1985 static uint8_t tonga_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock
)
1987 uint8_t mc_para_index
;
1989 if (memory_clock
< 10000) {
1991 } else if (memory_clock
>= 80000) {
1992 mc_para_index
= 0x0f;
1994 mc_para_index
= (uint8_t)((memory_clock
- 10000) / 5000 + 1);
1997 return mc_para_index
;
2000 static int tonga_populate_single_memory_level(
2001 struct pp_hwmgr
*hwmgr
,
2002 uint32_t memory_clock
,
2003 SMU72_Discrete_MemoryLevel
*memory_level
2006 uint32_t minMvdd
= 0;
2007 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2008 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2011 struct cgs_display_info info
= {0};
2014 if (NULL
!= pptable_info
->vdd_dep_on_mclk
) {
2015 result
= tonga_get_dependecy_volt_by_clk(hwmgr
,
2016 pptable_info
->vdd_dep_on_mclk
, memory_clock
, &memory_level
->MinVoltage
, &minMvdd
);
2017 PP_ASSERT_WITH_CODE((0 == result
),
2018 "can not find MinVddc voltage value from memory VDDC voltage dependency table", return result
);
2021 if (data
->mvdd_control
== TONGA_VOLTAGE_CONTROL_NONE
) {
2022 memory_level
->MinMvdd
= data
->vbios_boot_state
.mvdd_bootup_value
;
2024 memory_level
->MinMvdd
= minMvdd
;
2026 memory_level
->EnabledForThrottle
= 1;
2027 memory_level
->EnabledForActivity
= 0;
2028 memory_level
->UpHyst
= 0;
2029 memory_level
->DownHyst
= 100;
2030 memory_level
->VoltageDownHyst
= 0;
2032 /* Indicates maximum activity level for this performance level.*/
2033 memory_level
->ActivityLevel
= (uint16_t)data
->mclk_activity_target
;
2034 memory_level
->StutterEnable
= 0;
2035 memory_level
->StrobeEnable
= 0;
2036 memory_level
->EdcReadEnable
= 0;
2037 memory_level
->EdcWriteEnable
= 0;
2038 memory_level
->RttEnable
= 0;
2040 /* default set to low watermark. Highest level will be set to high later.*/
2041 memory_level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2043 cgs_get_active_displays_info(hwmgr
->device
, &info
);
2044 data
->display_timing
.num_existing_displays
= info
.display_count
;
2046 if ((data
->mclk_stutter_mode_threshold
!= 0) &&
2047 (memory_clock
<= data
->mclk_stutter_mode_threshold
) &&
2048 (!data
->is_uvd_enabled
)
2049 && (PHM_READ_FIELD(hwmgr
->device
, DPG_PIPE_STUTTER_CONTROL
, STUTTER_ENABLE
) & 0x1)
2050 && (data
->display_timing
.num_existing_displays
<= 2)
2051 && (data
->display_timing
.num_existing_displays
!= 0))
2052 memory_level
->StutterEnable
= 1;
2054 /* decide strobe mode*/
2055 memory_level
->StrobeEnable
= (data
->mclk_strobe_mode_threshold
!= 0) &&
2056 (memory_clock
<= data
->mclk_strobe_mode_threshold
);
2058 /* decide EDC mode and memory clock ratio*/
2059 if (data
->is_memory_GDDR5
) {
2060 memory_level
->StrobeRatio
= tonga_get_mclk_frequency_ratio(memory_clock
,
2061 memory_level
->StrobeEnable
);
2063 if ((data
->mclk_edc_enable_threshold
!= 0) &&
2064 (memory_clock
> data
->mclk_edc_enable_threshold
)) {
2065 memory_level
->EdcReadEnable
= 1;
2068 if ((data
->mclk_edc_wr_enable_threshold
!= 0) &&
2069 (memory_clock
> data
->mclk_edc_wr_enable_threshold
)) {
2070 memory_level
->EdcWriteEnable
= 1;
2073 if (memory_level
->StrobeEnable
) {
2074 if (tonga_get_mclk_frequency_ratio(memory_clock
, 1) >=
2075 ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC7
) >> 16) & 0xf)) {
2076 dllStateOn
= ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC5
) >> 1) & 0x1) ? 1 : 0;
2078 dllStateOn
= ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC6
) >> 1) & 0x1) ? 1 : 0;
2082 dllStateOn
= data
->dll_defaule_on
;
2085 memory_level
->StrobeRatio
=
2086 tonga_get_ddr3_mclk_frequency_ratio(memory_clock
);
2087 dllStateOn
= ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC5
) >> 1) & 0x1) ? 1 : 0;
2090 result
= tonga_calculate_mclk_params(hwmgr
,
2091 memory_clock
, memory_level
, memory_level
->StrobeEnable
, dllStateOn
);
2094 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MinMvdd
);
2095 /* MCLK frequency in units of 10KHz*/
2096 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MclkFrequency
);
2097 /* Indicates maximum activity level for this performance level.*/
2098 CONVERT_FROM_HOST_TO_SMC_US(memory_level
->ActivityLevel
);
2099 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllFuncCntl
);
2100 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllFuncCntl_1
);
2101 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllFuncCntl_2
);
2102 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllAdFuncCntl
);
2103 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllDqFuncCntl
);
2104 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MclkPwrmgtCntl
);
2105 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->DllCntl
);
2106 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllSs1
);
2107 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllSs2
);
2114 * Populates the SMC MVDD structure using the provided memory clock.
2116 * @param hwmgr the address of the hardware manager
2117 * @param mclk the MCLK value to be used in the decision if MVDD should be high or low.
2118 * @param voltage the SMC VOLTAGE structure to be populated
2120 int tonga_populate_mvdd_value(struct pp_hwmgr
*hwmgr
, uint32_t mclk
, SMIO_Pattern
*smio_pattern
)
2122 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2123 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2126 if (TONGA_VOLTAGE_CONTROL_NONE
!= data
->mvdd_control
) {
2127 /* find mvdd value which clock is more than request */
2128 for (i
= 0; i
< pptable_info
->vdd_dep_on_mclk
->count
; i
++) {
2129 if (mclk
<= pptable_info
->vdd_dep_on_mclk
->entries
[i
].clk
) {
2130 /* Always round to higher voltage. */
2131 smio_pattern
->Voltage
= data
->mvdd_voltage_table
.entries
[i
].value
;
2136 PP_ASSERT_WITH_CODE(i
< pptable_info
->vdd_dep_on_mclk
->count
,
2137 "MVDD Voltage is outside the supported range.", return -1);
2147 static int tonga_populate_smv_acpi_level(struct pp_hwmgr
*hwmgr
,
2148 SMU72_Discrete_DpmTable
*table
)
2151 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2152 pp_atomctrl_clock_dividers_vi dividers
;
2153 SMIO_Pattern voltage_level
;
2154 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
2155 uint32_t spll_func_cntl_2
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
;
2156 uint32_t dll_cntl
= data
->clock_registers
.vDLL_CNTL
;
2157 uint32_t mclk_pwrmgt_cntl
= data
->clock_registers
.vMCLK_PWRMGT_CNTL
;
2159 /* The ACPI state should not do DPM on DC (or ever).*/
2160 table
->ACPILevel
.Flags
&= ~PPSMC_SWSTATE_FLAG_DC
;
2162 table
->ACPILevel
.MinVoltage
= data
->smc_state_table
.GraphicsLevel
[0].MinVoltage
;
2164 /* assign zero for now*/
2165 table
->ACPILevel
.SclkFrequency
= atomctrl_get_reference_clock(hwmgr
);
2167 /* get the engine clock dividers for this clock value*/
2168 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
,
2169 table
->ACPILevel
.SclkFrequency
, ÷rs
);
2171 PP_ASSERT_WITH_CODE(result
== 0,
2172 "Error retrieving Engine Clock dividers from VBIOS.", return result
);
2174 /* divider ID for required SCLK*/
2175 table
->ACPILevel
.SclkDid
= (uint8_t)dividers
.pll_post_divider
;
2176 table
->ACPILevel
.DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2177 table
->ACPILevel
.DeepSleepDivId
= 0;
2179 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2180 CG_SPLL_FUNC_CNTL
, SPLL_PWRON
, 0);
2181 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2182 CG_SPLL_FUNC_CNTL
, SPLL_RESET
, 1);
2183 spll_func_cntl_2
= PHM_SET_FIELD(spll_func_cntl_2
,
2184 CG_SPLL_FUNC_CNTL_2
, SCLK_MUX_SEL
, 4);
2186 table
->ACPILevel
.CgSpllFuncCntl
= spll_func_cntl
;
2187 table
->ACPILevel
.CgSpllFuncCntl2
= spll_func_cntl_2
;
2188 table
->ACPILevel
.CgSpllFuncCntl3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
2189 table
->ACPILevel
.CgSpllFuncCntl4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
2190 table
->ACPILevel
.SpllSpreadSpectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
2191 table
->ACPILevel
.SpllSpreadSpectrum2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
2192 table
->ACPILevel
.CcPwrDynRm
= 0;
2193 table
->ACPILevel
.CcPwrDynRm1
= 0;
2196 /* For various features to be enabled/disabled while this level is active.*/
2197 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.Flags
);
2198 /* SCLK frequency in units of 10KHz*/
2199 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SclkFrequency
);
2200 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl
);
2201 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl2
);
2202 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl3
);
2203 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl4
);
2204 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum
);
2205 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum2
);
2206 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm
);
2207 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm1
);
2209 /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
2210 table
->MemoryACPILevel
.MinVoltage
= data
->smc_state_table
.MemoryLevel
[0].MinVoltage
;
2212 /* CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);*/
2214 if (0 == tonga_populate_mvdd_value(hwmgr
, 0, &voltage_level
))
2215 table
->MemoryACPILevel
.MinMvdd
=
2216 PP_HOST_TO_SMC_UL(voltage_level
.Voltage
* VOLTAGE_SCALE
);
2218 table
->MemoryACPILevel
.MinMvdd
= 0;
2220 /* Force reset on DLL*/
2221 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2222 MCLK_PWRMGT_CNTL
, MRDCK0_RESET
, 0x1);
2223 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2224 MCLK_PWRMGT_CNTL
, MRDCK1_RESET
, 0x1);
2226 /* Disable DLL in ACPIState*/
2227 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2228 MCLK_PWRMGT_CNTL
, MRDCK0_PDNB
, 0);
2229 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2230 MCLK_PWRMGT_CNTL
, MRDCK1_PDNB
, 0);
2232 /* Enable DLL bypass signal*/
2233 dll_cntl
= PHM_SET_FIELD(dll_cntl
,
2234 DLL_CNTL
, MRDCK0_BYPASS
, 0);
2235 dll_cntl
= PHM_SET_FIELD(dll_cntl
,
2236 DLL_CNTL
, MRDCK1_BYPASS
, 0);
2238 table
->MemoryACPILevel
.DllCntl
=
2239 PP_HOST_TO_SMC_UL(dll_cntl
);
2240 table
->MemoryACPILevel
.MclkPwrmgtCntl
=
2241 PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl
);
2242 table
->MemoryACPILevel
.MpllAdFuncCntl
=
2243 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_AD_FUNC_CNTL
);
2244 table
->MemoryACPILevel
.MpllDqFuncCntl
=
2245 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_DQ_FUNC_CNTL
);
2246 table
->MemoryACPILevel
.MpllFuncCntl
=
2247 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_FUNC_CNTL
);
2248 table
->MemoryACPILevel
.MpllFuncCntl_1
=
2249 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_FUNC_CNTL_1
);
2250 table
->MemoryACPILevel
.MpllFuncCntl_2
=
2251 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_FUNC_CNTL_2
);
2252 table
->MemoryACPILevel
.MpllSs1
=
2253 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_SS1
);
2254 table
->MemoryACPILevel
.MpllSs2
=
2255 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_SS2
);
2257 table
->MemoryACPILevel
.EnabledForThrottle
= 0;
2258 table
->MemoryACPILevel
.EnabledForActivity
= 0;
2259 table
->MemoryACPILevel
.UpHyst
= 0;
2260 table
->MemoryACPILevel
.DownHyst
= 100;
2261 table
->MemoryACPILevel
.VoltageDownHyst
= 0;
2262 /* Indicates maximum activity level for this performance level.*/
2263 table
->MemoryACPILevel
.ActivityLevel
= PP_HOST_TO_SMC_US((uint16_t)data
->mclk_activity_target
);
2265 table
->MemoryACPILevel
.StutterEnable
= 0;
2266 table
->MemoryACPILevel
.StrobeEnable
= 0;
2267 table
->MemoryACPILevel
.EdcReadEnable
= 0;
2268 table
->MemoryACPILevel
.EdcWriteEnable
= 0;
2269 table
->MemoryACPILevel
.RttEnable
= 0;
2274 static int tonga_find_boot_level(struct tonga_single_dpm_table
*table
, uint32_t value
, uint32_t *boot_level
)
2279 for (i
= 0; i
< table
->count
; i
++) {
2280 if (value
== table
->dpm_levels
[i
].value
) {
2288 static int tonga_populate_smc_boot_level(struct pp_hwmgr
*hwmgr
,
2289 SMU72_Discrete_DpmTable
*table
)
2292 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2294 table
->GraphicsBootLevel
= 0; /* 0 == DPM[0] (low), etc. */
2295 table
->MemoryBootLevel
= 0; /* 0 == DPM[0] (low), etc. */
2297 /* find boot level from dpm table*/
2298 result
= tonga_find_boot_level(&(data
->dpm_table
.sclk_table
),
2299 data
->vbios_boot_state
.sclk_bootup_value
,
2300 (uint32_t *)&(data
->smc_state_table
.GraphicsBootLevel
));
2303 data
->smc_state_table
.GraphicsBootLevel
= 0;
2304 printk(KERN_ERR
"[ powerplay ] VBIOS did not find boot engine clock value \
2305 in dependency table. Using Graphics DPM level 0!");
2309 result
= tonga_find_boot_level(&(data
->dpm_table
.mclk_table
),
2310 data
->vbios_boot_state
.mclk_bootup_value
,
2311 (uint32_t *)&(data
->smc_state_table
.MemoryBootLevel
));
2314 data
->smc_state_table
.MemoryBootLevel
= 0;
2315 printk(KERN_ERR
"[ powerplay ] VBIOS did not find boot engine clock value \
2316 in dependency table. Using Memory DPM level 0!");
2320 table
->BootVoltage
.Vddc
=
2321 tonga_get_voltage_id(&(data
->vddc_voltage_table
),
2322 data
->vbios_boot_state
.vddc_bootup_value
);
2323 table
->BootVoltage
.VddGfx
=
2324 tonga_get_voltage_id(&(data
->vddgfx_voltage_table
),
2325 data
->vbios_boot_state
.vddgfx_bootup_value
);
2326 table
->BootVoltage
.Vddci
=
2327 tonga_get_voltage_id(&(data
->vddci_voltage_table
),
2328 data
->vbios_boot_state
.vddci_bootup_value
);
2329 table
->BootMVdd
= data
->vbios_boot_state
.mvdd_bootup_value
;
2331 CONVERT_FROM_HOST_TO_SMC_US(table
->BootMVdd
);
2338 * Calculates the SCLK dividers using the provided engine clock
2340 * @param hwmgr the address of the hardware manager
2341 * @param engine_clock the engine clock to use to populate the structure
2342 * @param sclk the SMC SCLK structure to be populated
2344 int tonga_calculate_sclk_params(struct pp_hwmgr
*hwmgr
,
2345 uint32_t engine_clock
, SMU72_Discrete_GraphicsLevel
*sclk
)
2347 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2348 pp_atomctrl_clock_dividers_vi dividers
;
2349 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
2350 uint32_t spll_func_cntl_3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
2351 uint32_t spll_func_cntl_4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
2352 uint32_t cg_spll_spread_spectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
2353 uint32_t cg_spll_spread_spectrum_2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
2354 uint32_t reference_clock
;
2355 uint32_t reference_divider
;
2359 /* get the engine clock dividers for this clock value*/
2360 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
, engine_clock
, ÷rs
);
2362 PP_ASSERT_WITH_CODE(result
== 0,
2363 "Error retrieving Engine Clock dividers from VBIOS.", return result
);
2365 /* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/
2366 reference_clock
= atomctrl_get_reference_clock(hwmgr
);
2368 reference_divider
= 1 + dividers
.uc_pll_ref_div
;
2370 /* low 14 bits is fraction and high 12 bits is divider*/
2371 fbdiv
= dividers
.ul_fb_div
.ul_fb_divider
& 0x3FFFFFF;
2373 /* SPLL_FUNC_CNTL setup*/
2374 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2375 CG_SPLL_FUNC_CNTL
, SPLL_REF_DIV
, dividers
.uc_pll_ref_div
);
2376 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2377 CG_SPLL_FUNC_CNTL
, SPLL_PDIV_A
, dividers
.uc_pll_post_div
);
2379 /* SPLL_FUNC_CNTL_3 setup*/
2380 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
,
2381 CG_SPLL_FUNC_CNTL_3
, SPLL_FB_DIV
, fbdiv
);
2383 /* set to use fractional accumulation*/
2384 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
,
2385 CG_SPLL_FUNC_CNTL_3
, SPLL_DITHEN
, 1);
2387 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2388 PHM_PlatformCaps_EngineSpreadSpectrumSupport
)) {
2389 pp_atomctrl_internal_ss_info ss_info
;
2391 uint32_t vcoFreq
= engine_clock
* dividers
.uc_pll_post_div
;
2392 if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr
, vcoFreq
, &ss_info
)) {
2394 * ss_info.speed_spectrum_percentage -- in unit of 0.01%
2395 * ss_info.speed_spectrum_rate -- in unit of khz
2397 /* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */
2398 uint32_t clkS
= reference_clock
* 5 / (reference_divider
* ss_info
.speed_spectrum_rate
);
2400 /* clkv = 2 * D * fbdiv / NS */
2401 uint32_t clkV
= 4 * ss_info
.speed_spectrum_percentage
* fbdiv
/ (clkS
* 10000);
2403 cg_spll_spread_spectrum
=
2404 PHM_SET_FIELD(cg_spll_spread_spectrum
, CG_SPLL_SPREAD_SPECTRUM
, CLKS
, clkS
);
2405 cg_spll_spread_spectrum
=
2406 PHM_SET_FIELD(cg_spll_spread_spectrum
, CG_SPLL_SPREAD_SPECTRUM
, SSEN
, 1);
2407 cg_spll_spread_spectrum_2
=
2408 PHM_SET_FIELD(cg_spll_spread_spectrum_2
, CG_SPLL_SPREAD_SPECTRUM_2
, CLKV
, clkV
);
2412 sclk
->SclkFrequency
= engine_clock
;
2413 sclk
->CgSpllFuncCntl3
= spll_func_cntl_3
;
2414 sclk
->CgSpllFuncCntl4
= spll_func_cntl_4
;
2415 sclk
->SpllSpreadSpectrum
= cg_spll_spread_spectrum
;
2416 sclk
->SpllSpreadSpectrum2
= cg_spll_spread_spectrum_2
;
2417 sclk
->SclkDid
= (uint8_t)dividers
.pll_post_divider
;
2422 static uint8_t tonga_get_sleep_divider_id_from_clock(uint32_t engine_clock
,
2423 uint32_t min_engine_clock_in_sr
)
2426 uint32_t min
= max(min_engine_clock_in_sr
, (uint32_t)TONGA_MINIMUM_ENGINE_CLOCK
);
2428 PP_ASSERT_WITH_CODE((engine_clock
>= min
),
2429 "Engine clock can't satisfy stutter requirement!", return 0);
2431 for (i
= TONGA_MAX_DEEPSLEEP_DIVIDER_ID
;; i
--) {
2432 temp
= engine_clock
>> i
;
2434 if(temp
>= min
|| i
== 0)
2441 * Populates single SMC SCLK structure using the provided engine clock
2443 * @param hwmgr the address of the hardware manager
2444 * @param engine_clock the engine clock to use to populate the structure
2445 * @param sclk the SMC SCLK structure to be populated
2447 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
)
2452 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2453 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2455 result
= tonga_calculate_sclk_params(hwmgr
, engine_clock
, graphic_level
);
2458 /* populate graphics levels*/
2459 result
= tonga_get_dependecy_volt_by_clk(hwmgr
,
2460 pptable_info
->vdd_dep_on_sclk
, engine_clock
,
2461 &graphic_level
->MinVoltage
, &mvdd
);
2462 PP_ASSERT_WITH_CODE((0 == result
),
2463 "can not find VDDC voltage value for VDDC \
2464 engine clock dependency table", return result
);
2466 /* SCLK frequency in units of 10KHz*/
2467 graphic_level
->SclkFrequency
= engine_clock
;
2469 /* Indicates maximum activity level for this performance level. 50% for now*/
2470 graphic_level
->ActivityLevel
= sclk_activity_level_threshold
;
2472 graphic_level
->CcPwrDynRm
= 0;
2473 graphic_level
->CcPwrDynRm1
= 0;
2474 /* this level can be used if activity is high enough.*/
2475 graphic_level
->EnabledForActivity
= 0;
2476 /* this level can be used for throttling.*/
2477 graphic_level
->EnabledForThrottle
= 1;
2478 graphic_level
->UpHyst
= 0;
2479 graphic_level
->DownHyst
= 0;
2480 graphic_level
->VoltageDownHyst
= 0;
2481 graphic_level
->PowerThrottle
= 0;
2483 threshold
= engine_clock
* data
->fast_watermark_threshold
/ 100;
2485 *get the DAL clock. do it in funture.
2486 PECI_GetMinClockSettings(hwmgr->peci, &minClocks);
2487 data->display_timing.min_clock_insr = minClocks.engineClockInSR;
2489 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2490 PHM_PlatformCaps_SclkDeepSleep
))
2491 graphic_level
->DeepSleepDivId
=
2492 tonga_get_sleep_divider_id_from_clock(engine_clock
,
2493 data
->display_timing
.min_clock_insr
);
2495 /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
2496 graphic_level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2499 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVoltage);*/
2500 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases);*/
2501 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->SclkFrequency
);
2502 CONVERT_FROM_HOST_TO_SMC_US(graphic_level
->ActivityLevel
);
2503 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CgSpllFuncCntl3
);
2504 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CgSpllFuncCntl4
);
2505 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->SpllSpreadSpectrum
);
2506 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->SpllSpreadSpectrum2
);
2507 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CcPwrDynRm
);
2508 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CcPwrDynRm1
);
2515 * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
2517 * @param hwmgr the address of the hardware manager
2519 static int tonga_populate_all_graphic_levels(struct pp_hwmgr
*hwmgr
)
2521 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2522 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2523 struct tonga_dpm_table
*dpm_table
= &data
->dpm_table
;
2524 phm_ppt_v1_pcie_table
*pcie_table
= pptable_info
->pcie_table
;
2525 uint8_t pcie_entry_count
= (uint8_t) data
->dpm_table
.pcie_speed_table
.count
;
2527 uint32_t level_array_adress
= data
->dpm_table_start
+
2528 offsetof(SMU72_Discrete_DpmTable
, GraphicsLevel
);
2529 uint32_t level_array_size
= sizeof(SMU72_Discrete_GraphicsLevel
) *
2530 SMU72_MAX_LEVELS_GRAPHICS
; /* 64 -> long; 32 -> int*/
2531 SMU72_Discrete_GraphicsLevel
*levels
= data
->smc_state_table
.GraphicsLevel
;
2532 uint32_t i
, maxEntry
;
2533 uint8_t highest_pcie_level_enabled
= 0, lowest_pcie_level_enabled
= 0, mid_pcie_level_enabled
= 0, count
= 0;
2534 PECI_RegistryValue reg_value
;
2535 memset(levels
, 0x00, level_array_size
);
2537 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
2538 result
= tonga_populate_single_graphic_level(hwmgr
,
2539 dpm_table
->sclk_table
.dpm_levels
[i
].value
,
2540 (uint16_t)data
->activity_target
[i
],
2541 &(data
->smc_state_table
.GraphicsLevel
[i
]));
2546 /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
2548 data
->smc_state_table
.GraphicsLevel
[i
].DeepSleepDivId
= 0;
2553 data
->smc_state_table
.GraphicsLevel
[0].UpHyst
= (uint8_t)reg_value
;
2559 data
->smc_state_table
.GraphicsLevel
[1].UpHyst
= (uint8_t)reg_value
;
2563 /* Only enable level 0 for now. */
2564 data
->smc_state_table
.GraphicsLevel
[0].EnabledForActivity
= 1;
2566 /* set highest level watermark to high */
2567 if (dpm_table
->sclk_table
.count
> 1)
2568 data
->smc_state_table
.GraphicsLevel
[dpm_table
->sclk_table
.count
-1].DisplayWatermark
=
2569 PPSMC_DISPLAY_WATERMARK_HIGH
;
2571 data
->smc_state_table
.GraphicsDpmLevelCount
=
2572 (uint8_t)dpm_table
->sclk_table
.count
;
2573 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
=
2574 tonga_get_dpm_level_enable_mask_value(&dpm_table
->sclk_table
);
2576 if (pcie_table
!= NULL
) {
2577 PP_ASSERT_WITH_CODE((pcie_entry_count
>= 1),
2578 "There must be 1 or more PCIE levels defined in PPTable.", return -1);
2579 maxEntry
= pcie_entry_count
- 1; /* for indexing, we need to decrement by 1.*/
2580 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
2581 data
->smc_state_table
.GraphicsLevel
[i
].pcieDpmLevel
=
2582 (uint8_t) ((i
< maxEntry
) ? i
: maxEntry
);
2585 if (0 == data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
)
2586 printk(KERN_ERR
"[ powerplay ] Pcie Dpm Enablemask is 0!");
2588 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
2589 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2590 (1<<(highest_pcie_level_enabled
+1))) != 0)) {
2591 highest_pcie_level_enabled
++;
2594 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
2595 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2596 (1<<lowest_pcie_level_enabled
)) == 0)) {
2597 lowest_pcie_level_enabled
++;
2600 while ((count
< highest_pcie_level_enabled
) &&
2601 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2602 (1<<(lowest_pcie_level_enabled
+1+count
))) == 0)) {
2605 mid_pcie_level_enabled
= (lowest_pcie_level_enabled
+1+count
) < highest_pcie_level_enabled
?
2606 (lowest_pcie_level_enabled
+1+count
) : highest_pcie_level_enabled
;
2609 /* set pcieDpmLevel to highest_pcie_level_enabled*/
2610 for (i
= 2; i
< dpm_table
->sclk_table
.count
; i
++) {
2611 data
->smc_state_table
.GraphicsLevel
[i
].pcieDpmLevel
= highest_pcie_level_enabled
;
2614 /* set pcieDpmLevel to lowest_pcie_level_enabled*/
2615 data
->smc_state_table
.GraphicsLevel
[0].pcieDpmLevel
= lowest_pcie_level_enabled
;
2617 /* set pcieDpmLevel to mid_pcie_level_enabled*/
2618 data
->smc_state_table
.GraphicsLevel
[1].pcieDpmLevel
= mid_pcie_level_enabled
;
2620 /* level count will send to smc once at init smc table and never change*/
2621 result
= tonga_copy_bytes_to_smc(hwmgr
->smumgr
, level_array_adress
, (uint8_t *)levels
, (uint32_t)level_array_size
, data
->sram_end
);
2630 * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
2632 * @param hwmgr the address of the hardware manager
2635 static int tonga_populate_all_memory_levels(struct pp_hwmgr
*hwmgr
)
2637 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2638 struct tonga_dpm_table
*dpm_table
= &data
->dpm_table
;
2640 /* populate MCLK dpm table to SMU7 */
2641 uint32_t level_array_adress
= data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
, MemoryLevel
);
2642 uint32_t level_array_size
= sizeof(SMU72_Discrete_MemoryLevel
) * SMU72_MAX_LEVELS_MEMORY
;
2643 SMU72_Discrete_MemoryLevel
*levels
= data
->smc_state_table
.MemoryLevel
;
2646 memset(levels
, 0x00, level_array_size
);
2648 for (i
= 0; i
< dpm_table
->mclk_table
.count
; i
++) {
2649 PP_ASSERT_WITH_CODE((0 != dpm_table
->mclk_table
.dpm_levels
[i
].value
),
2650 "can not populate memory level as memory clock is zero", return -1);
2651 result
= tonga_populate_single_memory_level(hwmgr
, dpm_table
->mclk_table
.dpm_levels
[i
].value
,
2652 &(data
->smc_state_table
.MemoryLevel
[i
]));
2658 /* Only enable level 0 for now.*/
2659 data
->smc_state_table
.MemoryLevel
[0].EnabledForActivity
= 1;
2662 * in order to prevent MC activity from stutter mode to push DPM up.
2663 * the UVD change complements this by putting the MCLK in a higher state
2664 * by default such that we are not effected by up threshold or and MCLK DPM latency.
2666 data
->smc_state_table
.MemoryLevel
[0].ActivityLevel
= 0x1F;
2667 CONVERT_FROM_HOST_TO_SMC_US(data
->smc_state_table
.MemoryLevel
[0].ActivityLevel
);
2669 data
->smc_state_table
.MemoryDpmLevelCount
= (uint8_t)dpm_table
->mclk_table
.count
;
2670 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&dpm_table
->mclk_table
);
2671 /* set highest level watermark to high*/
2672 data
->smc_state_table
.MemoryLevel
[dpm_table
->mclk_table
.count
-1].DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_HIGH
;
2674 /* level count will send to smc once at init smc table and never change*/
2675 result
= tonga_copy_bytes_to_smc(hwmgr
->smumgr
,
2676 level_array_adress
, (uint8_t *)levels
, (uint32_t)level_array_size
, data
->sram_end
);
2685 struct TONGA_DLL_SPEED_SETTING
{
2686 uint16_t Min
; /* Minimum Data Rate*/
2687 uint16_t Max
; /* Maximum Data Rate*/
2688 uint32_t dll_speed
; /* The desired DLL_SPEED setting*/
2691 static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr
*hwmgr
)
2696 /* ---------------------------------------- ULV related functions ----------------------------------------------------*/
2699 static int tonga_reset_single_dpm_table(
2700 struct pp_hwmgr
*hwmgr
,
2701 struct tonga_single_dpm_table
*dpm_table
,
2705 if (!(count
<= MAX_REGULAR_DPM_NUMBER
))
2706 printk(KERN_ERR
"[ powerplay ] Fatal error, can not set up single DPM \
2707 table entries to exceed max number! \n");
2709 dpm_table
->count
= count
;
2710 for (i
= 0; i
< MAX_REGULAR_DPM_NUMBER
; i
++) {
2711 dpm_table
->dpm_levels
[i
].enabled
= false;
2717 static void tonga_setup_pcie_table_entry(
2718 struct tonga_single_dpm_table
*dpm_table
,
2719 uint32_t index
, uint32_t pcie_gen
,
2720 uint32_t pcie_lanes
)
2722 dpm_table
->dpm_levels
[index
].value
= pcie_gen
;
2723 dpm_table
->dpm_levels
[index
].param1
= pcie_lanes
;
2724 dpm_table
->dpm_levels
[index
].enabled
= true;
2727 static int tonga_setup_default_pcie_tables(struct pp_hwmgr
*hwmgr
)
2729 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2730 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2731 phm_ppt_v1_pcie_table
*pcie_table
= pptable_info
->pcie_table
;
2732 uint32_t i
, maxEntry
;
2734 if (data
->use_pcie_performance_levels
&& !data
->use_pcie_power_saving_levels
) {
2735 data
->pcie_gen_power_saving
= data
->pcie_gen_performance
;
2736 data
->pcie_lane_power_saving
= data
->pcie_lane_performance
;
2737 } else if (!data
->use_pcie_performance_levels
&& data
->use_pcie_power_saving_levels
) {
2738 data
->pcie_gen_performance
= data
->pcie_gen_power_saving
;
2739 data
->pcie_lane_performance
= data
->pcie_lane_power_saving
;
2742 tonga_reset_single_dpm_table(hwmgr
, &data
->dpm_table
.pcie_speed_table
, SMU72_MAX_LEVELS_LINK
);
2744 if (pcie_table
!= NULL
) {
2746 * maxEntry is used to make sure we reserve one PCIE level for boot level (fix for A+A PSPP issue).
2747 * If PCIE table from PPTable have ULV entry + 8 entries, then ignore the last entry.
2749 maxEntry
= (SMU72_MAX_LEVELS_LINK
< pcie_table
->count
) ?
2750 SMU72_MAX_LEVELS_LINK
: pcie_table
->count
;
2751 for (i
= 1; i
< maxEntry
; i
++) {
2752 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, i
-1,
2753 get_pcie_gen_support(data
->pcie_gen_cap
, pcie_table
->entries
[i
].gen_speed
),
2754 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2756 data
->dpm_table
.pcie_speed_table
.count
= maxEntry
- 1;
2758 /* Hardcode Pcie Table */
2759 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 0,
2760 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Min_PCIEGen
),
2761 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2762 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 1,
2763 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Min_PCIEGen
),
2764 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2765 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 2,
2766 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2767 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2768 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 3,
2769 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2770 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2771 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 4,
2772 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2773 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2774 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 5,
2775 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2776 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2777 data
->dpm_table
.pcie_speed_table
.count
= 6;
2779 /* Populate last level for boot PCIE level, but do not increment count. */
2780 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
,
2781 data
->dpm_table
.pcie_speed_table
.count
,
2782 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Min_PCIEGen
),
2783 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2790 * This function is to initalize all DPM state tables for SMU7 based on the dependency table.
2791 * Dynamic state patching function will then trim these state tables to the allowed range based
2792 * on the power policy or external client requests, such as UVD request, etc.
2794 static int tonga_setup_default_dpm_tables(struct pp_hwmgr
*hwmgr
)
2796 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2797 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2800 phm_ppt_v1_clock_voltage_dependency_table
*allowed_vdd_sclk_table
=
2801 pptable_info
->vdd_dep_on_sclk
;
2802 phm_ppt_v1_clock_voltage_dependency_table
*allowed_vdd_mclk_table
=
2803 pptable_info
->vdd_dep_on_mclk
;
2805 PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table
!= NULL
,
2806 "SCLK dependency table is missing. This table is mandatory", return -1);
2807 PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table
->count
>= 1,
2808 "SCLK dependency table has to have is missing. This table is mandatory", return -1);
2810 PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table
!= NULL
,
2811 "MCLK dependency table is missing. This table is mandatory", return -1);
2812 PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table
->count
>= 1,
2813 "VMCLK dependency table has to have is missing. This table is mandatory", return -1);
2815 /* clear the state table to reset everything to default */
2816 memset(&(data
->dpm_table
), 0x00, sizeof(data
->dpm_table
));
2817 tonga_reset_single_dpm_table(hwmgr
, &data
->dpm_table
.sclk_table
, SMU72_MAX_LEVELS_GRAPHICS
);
2818 tonga_reset_single_dpm_table(hwmgr
, &data
->dpm_table
.mclk_table
, SMU72_MAX_LEVELS_MEMORY
);
2819 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.VddcTable, SMU72_MAX_LEVELS_VDDC); */
2820 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_gfx_table, SMU72_MAX_LEVELS_VDDGFX);*/
2821 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_ci_table, SMU72_MAX_LEVELS_VDDCI);*/
2822 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.mvdd_table, SMU72_MAX_LEVELS_MVDD);*/
2824 PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table
!= NULL
,
2825 "SCLK dependency table is missing. This table is mandatory", return -1);
2826 /* Initialize Sclk DPM table based on allow Sclk values*/
2827 data
->dpm_table
.sclk_table
.count
= 0;
2829 for (i
= 0; i
< allowed_vdd_sclk_table
->count
; i
++) {
2830 if (i
== 0 || data
->dpm_table
.sclk_table
.dpm_levels
[data
->dpm_table
.sclk_table
.count
-1].value
!=
2831 allowed_vdd_sclk_table
->entries
[i
].clk
) {
2832 data
->dpm_table
.sclk_table
.dpm_levels
[data
->dpm_table
.sclk_table
.count
].value
=
2833 allowed_vdd_sclk_table
->entries
[i
].clk
;
2834 data
->dpm_table
.sclk_table
.dpm_levels
[data
->dpm_table
.sclk_table
.count
].enabled
= true; /*(i==0) ? 1 : 0; to do */
2835 data
->dpm_table
.sclk_table
.count
++;
2839 PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table
!= NULL
,
2840 "MCLK dependency table is missing. This table is mandatory", return -1);
2841 /* Initialize Mclk DPM table based on allow Mclk values */
2842 data
->dpm_table
.mclk_table
.count
= 0;
2843 for (i
= 0; i
< allowed_vdd_mclk_table
->count
; i
++) {
2844 if (i
== 0 || data
->dpm_table
.mclk_table
.dpm_levels
[data
->dpm_table
.mclk_table
.count
-1].value
!=
2845 allowed_vdd_mclk_table
->entries
[i
].clk
) {
2846 data
->dpm_table
.mclk_table
.dpm_levels
[data
->dpm_table
.mclk_table
.count
].value
=
2847 allowed_vdd_mclk_table
->entries
[i
].clk
;
2848 data
->dpm_table
.mclk_table
.dpm_levels
[data
->dpm_table
.mclk_table
.count
].enabled
= true; /*(i==0) ? 1 : 0; */
2849 data
->dpm_table
.mclk_table
.count
++;
2853 /* setup PCIE gen speed levels*/
2854 tonga_setup_default_pcie_tables(hwmgr
);
2856 /* save a copy of the default DPM table*/
2857 memcpy(&(data
->golden_dpm_table
), &(data
->dpm_table
), sizeof(struct tonga_dpm_table
));
2862 int tonga_populate_smc_initial_state(struct pp_hwmgr
*hwmgr
,
2863 const struct tonga_power_state
*bootState
)
2865 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2866 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2867 uint8_t count
, level
;
2869 count
= (uint8_t) (pptable_info
->vdd_dep_on_sclk
->count
);
2870 for (level
= 0; level
< count
; level
++) {
2871 if (pptable_info
->vdd_dep_on_sclk
->entries
[level
].clk
>=
2872 bootState
->performance_levels
[0].engine_clock
) {
2873 data
->smc_state_table
.GraphicsBootLevel
= level
;
2878 count
= (uint8_t) (pptable_info
->vdd_dep_on_mclk
->count
);
2879 for (level
= 0; level
< count
; level
++) {
2880 if (pptable_info
->vdd_dep_on_mclk
->entries
[level
].clk
>=
2881 bootState
->performance_levels
[0].memory_clock
) {
2882 data
->smc_state_table
.MemoryBootLevel
= level
;
2891 * Initializes the SMC table and uploads it
2893 * @param hwmgr the address of the powerplay hardware manager.
2894 * @param pInput the pointer to input data (PowerState)
2897 int tonga_init_smc_table(struct pp_hwmgr
*hwmgr
)
2900 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2901 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2902 SMU72_Discrete_DpmTable
*table
= &(data
->smc_state_table
);
2903 const phw_tonga_ulv_parm
*ulv
= &(data
->ulv
);
2905 PECI_RegistryValue reg_value
;
2906 pp_atomctrl_gpio_pin_assignment gpio_pin_assignment
;
2908 result
= tonga_setup_default_dpm_tables(hwmgr
);
2909 PP_ASSERT_WITH_CODE(0 == result
,
2910 "Failed to setup default DPM tables!", return result
;);
2911 memset(&(data
->smc_state_table
), 0x00, sizeof(data
->smc_state_table
));
2912 if (TONGA_VOLTAGE_CONTROL_NONE
!= data
->voltage_control
) {
2913 tonga_populate_smc_voltage_tables(hwmgr
, table
);
2916 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2917 PHM_PlatformCaps_AutomaticDCTransition
)) {
2918 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GPIO_DC
;
2921 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2922 PHM_PlatformCaps_StepVddc
)) {
2923 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_STEPVDDC
;
2926 if (data
->is_memory_GDDR5
) {
2927 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GDDR5
;
2930 i
= PHM_READ_FIELD(hwmgr
->device
, CC_MC_MAX_CHANNEL
, NOOFCHAN
);
2932 if (i
== 1 || i
== 0) {
2933 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_12CHANNEL
;
2936 if (ulv
->ulv_supported
&& pptable_info
->us_ulv_voltage_offset
) {
2937 PP_ASSERT_WITH_CODE(0 == result
,
2938 "Failed to initialize ULV state!", return result
;);
2940 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
2941 ixCG_ULV_PARAMETER
, ulv
->ch_ulv_parameter
);
2944 result
= tonga_populate_smc_link_level(hwmgr
, table
);
2945 PP_ASSERT_WITH_CODE(0 == result
,
2946 "Failed to initialize Link Level!", return result
;);
2948 result
= tonga_populate_all_graphic_levels(hwmgr
);
2949 PP_ASSERT_WITH_CODE(0 == result
,
2950 "Failed to initialize Graphics Level!", return result
;);
2952 result
= tonga_populate_all_memory_levels(hwmgr
);
2953 PP_ASSERT_WITH_CODE(0 == result
,
2954 "Failed to initialize Memory Level!", return result
;);
2956 result
= tonga_populate_smv_acpi_level(hwmgr
, table
);
2957 PP_ASSERT_WITH_CODE(0 == result
,
2958 "Failed to initialize ACPI Level!", return result
;);
2960 result
= tonga_populate_smc_vce_level(hwmgr
, table
);
2961 PP_ASSERT_WITH_CODE(0 == result
,
2962 "Failed to initialize VCE Level!", return result
;);
2964 result
= tonga_populate_smc_acp_level(hwmgr
, table
);
2965 PP_ASSERT_WITH_CODE(0 == result
,
2966 "Failed to initialize ACP Level!", return result
;);
2968 result
= tonga_populate_smc_samu_level(hwmgr
, table
);
2969 PP_ASSERT_WITH_CODE(0 == result
,
2970 "Failed to initialize SAMU Level!", return result
;);
2972 /* Since only the initial state is completely set up at this point (the other states are just copies of the boot state) we only */
2973 /* need to populate the ARB settings for the initial state. */
2974 result
= tonga_program_memory_timing_parameters(hwmgr
);
2975 PP_ASSERT_WITH_CODE(0 == result
,
2976 "Failed to Write ARB settings for the initial state.", return result
;);
2978 result
= tonga_populate_smc_uvd_level(hwmgr
, table
);
2979 PP_ASSERT_WITH_CODE(0 == result
,
2980 "Failed to initialize UVD Level!", return result
;);
2982 result
= tonga_populate_smc_boot_level(hwmgr
, table
);
2983 PP_ASSERT_WITH_CODE(0 == result
,
2984 "Failed to initialize Boot Level!", return result
;);
2986 result
= tonga_populate_bapm_parameters_in_dpm_table(hwmgr
);
2987 PP_ASSERT_WITH_CODE(result
== 0,
2988 "Failed to populate BAPM Parameters!", return result
);
2990 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2991 PHM_PlatformCaps_ClockStretcher
)) {
2992 result
= tonga_populate_clock_stretcher_data_table(hwmgr
);
2993 PP_ASSERT_WITH_CODE(0 == result
,
2994 "Failed to populate Clock Stretcher Data Table!", return result
;);
2996 table
->GraphicsVoltageChangeEnable
= 1;
2997 table
->GraphicsThermThrottleEnable
= 1;
2998 table
->GraphicsInterval
= 1;
2999 table
->VoltageInterval
= 1;
3000 table
->ThermalInterval
= 1;
3001 table
->TemperatureLimitHigh
=
3002 pptable_info
->cac_dtp_table
->usTargetOperatingTemp
*
3003 TONGA_Q88_FORMAT_CONVERSION_UNIT
;
3004 table
->TemperatureLimitLow
=
3005 (pptable_info
->cac_dtp_table
->usTargetOperatingTemp
- 1) *
3006 TONGA_Q88_FORMAT_CONVERSION_UNIT
;
3007 table
->MemoryVoltageChangeEnable
= 1;
3008 table
->MemoryInterval
= 1;
3009 table
->VoltageResponseTime
= 0;
3010 table
->PhaseResponseTime
= 0;
3011 table
->MemoryThermThrottleEnable
= 1;
3014 * Cail reads current link status and reports it as cap (we cannot change this due to some previous issues we had)
3015 * SMC drops the link status to lowest level after enabling DPM by PowerPlay. After pnp or toggling CF, driver gets reloaded again
3016 * but this time Cail reads current link status which was set to low by SMC and reports it as cap to powerplay
3017 * To avoid it, we set PCIeBootLinkLevel to highest dpm level
3019 PP_ASSERT_WITH_CODE((1 <= data
->dpm_table
.pcie_speed_table
.count
),
3020 "There must be 1 or more PCIE levels defined in PPTable.",
3023 table
->PCIeBootLinkLevel
= (uint8_t) (data
->dpm_table
.pcie_speed_table
.count
);
3025 table
->PCIeGenInterval
= 1;
3027 result
= tonga_populate_vr_config(hwmgr
, table
);
3028 PP_ASSERT_WITH_CODE(0 == result
,
3029 "Failed to populate VRConfig setting!", return result
);
3031 table
->ThermGpio
= 17;
3032 table
->SclkStepSize
= 0x4000;
3035 if ((0 == reg_value
) &&
3036 (atomctrl_get_pp_assign_pin(hwmgr
, VDDC_VRHOT_GPIO_PINID
,
3037 &gpio_pin_assignment
))) {
3038 table
->VRHotGpio
= gpio_pin_assignment
.uc_gpio_pin_bit_shift
;
3039 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3040 PHM_PlatformCaps_RegulatorHot
);
3042 table
->VRHotGpio
= TONGA_UNUSED_GPIO_PIN
;
3043 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3044 PHM_PlatformCaps_RegulatorHot
);
3047 /* ACDC Switch GPIO */
3049 if ((0 == reg_value
) &&
3050 (atomctrl_get_pp_assign_pin(hwmgr
, PP_AC_DC_SWITCH_GPIO_PINID
,
3051 &gpio_pin_assignment
))) {
3052 table
->AcDcGpio
= gpio_pin_assignment
.uc_gpio_pin_bit_shift
;
3053 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3054 PHM_PlatformCaps_AutomaticDCTransition
);
3056 table
->AcDcGpio
= TONGA_UNUSED_GPIO_PIN
;
3057 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3058 PHM_PlatformCaps_AutomaticDCTransition
);
3061 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3062 PHM_PlatformCaps_Falcon_QuickTransition
);
3065 if (1 == reg_value
) {
3066 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3067 PHM_PlatformCaps_AutomaticDCTransition
);
3068 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3069 PHM_PlatformCaps_Falcon_QuickTransition
);
3073 if ((0 == reg_value
) && (atomctrl_get_pp_assign_pin(hwmgr
,
3074 THERMAL_INT_OUTPUT_GPIO_PINID
, &gpio_pin_assignment
))) {
3075 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3076 PHM_PlatformCaps_ThermalOutGPIO
);
3078 table
->ThermOutGpio
= gpio_pin_assignment
.uc_gpio_pin_bit_shift
;
3080 table
->ThermOutPolarity
=
3081 (0 == (cgs_read_register(hwmgr
->device
, mmGPIOPAD_A
) &
3082 (1 << gpio_pin_assignment
.uc_gpio_pin_bit_shift
))) ? 1:0;
3084 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_ONLY
;
3086 /* if required, combine VRHot/PCC with thermal out GPIO*/
3087 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3088 PHM_PlatformCaps_RegulatorHot
) &&
3089 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3090 PHM_PlatformCaps_CombinePCCWithThermalSignal
)){
3091 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_VRHOT
;
3094 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3095 PHM_PlatformCaps_ThermalOutGPIO
);
3097 table
->ThermOutGpio
= 17;
3098 table
->ThermOutPolarity
= 1;
3099 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_DISABLE
;
3102 for (i
= 0; i
< SMU72_MAX_ENTRIES_SMIO
; i
++) {
3103 table
->Smio
[i
] = PP_HOST_TO_SMC_UL(table
->Smio
[i
]);
3105 CONVERT_FROM_HOST_TO_SMC_UL(table
->SystemFlags
);
3106 CONVERT_FROM_HOST_TO_SMC_UL(table
->VRConfig
);
3107 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask1
);
3108 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask2
);
3109 CONVERT_FROM_HOST_TO_SMC_UL(table
->SclkStepSize
);
3110 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitHigh
);
3111 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitLow
);
3112 CONVERT_FROM_HOST_TO_SMC_US(table
->VoltageResponseTime
);
3113 CONVERT_FROM_HOST_TO_SMC_US(table
->PhaseResponseTime
);
3115 /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
3116 result
= tonga_copy_bytes_to_smc(hwmgr
->smumgr
, data
->dpm_table_start
+
3117 offsetof(SMU72_Discrete_DpmTable
, SystemFlags
),
3118 (uint8_t *)&(table
->SystemFlags
),
3119 sizeof(SMU72_Discrete_DpmTable
)-3 * sizeof(SMU72_PIDController
),
3122 PP_ASSERT_WITH_CODE(0 == result
,
3123 "Failed to upload dpm data to SMC memory!", return result
;);
3128 /* Look up the voltaged based on DAL's requested level. and then send the requested VDDC voltage to SMC*/
3129 static void tonga_apply_dal_minimum_voltage_request(struct pp_hwmgr
*hwmgr
)
3134 int tonga_upload_dpm_level_enable_mask(struct pp_hwmgr
*hwmgr
)
3136 PPSMC_Result result
;
3137 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3139 /* Apply minimum voltage based on DAL's request level */
3140 tonga_apply_dal_minimum_voltage_request(hwmgr
);
3142 if (0 == data
->sclk_dpm_key_disabled
) {
3143 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
3144 if (tonga_is_dpm_running(hwmgr
))
3145 printk(KERN_ERR
"[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
3147 if (0 != data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
3148 result
= smum_send_msg_to_smc_with_parameter(
3150 (PPSMC_Msg
)PPSMC_MSG_SCLKDPM_SetEnabledMask
,
3151 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
3152 PP_ASSERT_WITH_CODE((0 == result
),
3153 "Set Sclk Dpm enable Mask failed", return -1);
3157 if (0 == data
->mclk_dpm_key_disabled
) {
3158 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
3159 if (tonga_is_dpm_running(hwmgr
))
3160 printk(KERN_ERR
"[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
3162 if (0 != data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
) {
3163 result
= smum_send_msg_to_smc_with_parameter(
3165 (PPSMC_Msg
)PPSMC_MSG_MCLKDPM_SetEnabledMask
,
3166 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
);
3167 PP_ASSERT_WITH_CODE((0 == result
),
3168 "Set Mclk Dpm enable Mask failed", return -1);
3176 int tonga_force_dpm_highest(struct pp_hwmgr
*hwmgr
)
3178 uint32_t level
, tmp
;
3179 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3181 if (0 == data
->pcie_dpm_key_disabled
) {
3183 if (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
!= 0) {
3185 tmp
= data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
;
3190 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr
, level
)),
3191 "force highest pcie dpm state failed!", return -1);
3196 if (0 == data
->sclk_dpm_key_disabled
) {
3198 if (data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
!= 0) {
3200 tmp
= data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
;
3205 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr
, level
)),
3206 "force highest sclk dpm state failed!", return -1);
3207 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
,
3208 CGS_IND_REG__SMC
, TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_SCLK_INDEX
) != level
)
3209 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3210 Curr_Sclk_Index does not match the level \n");
3216 if (0 == data
->mclk_dpm_key_disabled
) {
3218 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
!= 0) {
3220 tmp
= data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
;
3225 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr
, level
)),
3226 "force highest mclk dpm state failed!", return -1);
3227 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3228 TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_MCLK_INDEX
) != level
)
3229 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3230 Curr_Mclk_Index does not match the level \n");
3239 * Find the MC microcode version and store it in the HwMgr struct
3241 * @param hwmgr the address of the powerplay hardware manager.
3244 int tonga_get_mc_microcode_version (struct pp_hwmgr
*hwmgr
)
3246 cgs_write_register(hwmgr
->device
, mmMC_SEQ_IO_DEBUG_INDEX
, 0x9F);
3248 hwmgr
->microcode_version_info
.MC
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_IO_DEBUG_DATA
);
3254 * Initialize Dynamic State Adjustment Rule Settings
3256 * @param hwmgr the address of the powerplay hardware manager.
3258 int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr
*hwmgr
)
3260 uint32_t table_size
;
3261 struct phm_clock_voltage_dependency_table
*table_clk_vlt
;
3262 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3264 hwmgr
->dyn_state
.mclk_sclk_ratio
= 4;
3265 hwmgr
->dyn_state
.sclk_mclk_delta
= 15000; /* 150 MHz */
3266 hwmgr
->dyn_state
.vddc_vddci_delta
= 200; /* 200mV */
3268 /* initialize vddc_dep_on_dal_pwrl table */
3269 table_size
= sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record
);
3270 table_clk_vlt
= kzalloc(table_size
, GFP_KERNEL
);
3272 if (NULL
== table_clk_vlt
) {
3273 printk(KERN_ERR
"[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
3276 table_clk_vlt
->count
= 4;
3277 table_clk_vlt
->entries
[0].clk
= PP_DAL_POWERLEVEL_ULTRALOW
;
3278 table_clk_vlt
->entries
[0].v
= 0;
3279 table_clk_vlt
->entries
[1].clk
= PP_DAL_POWERLEVEL_LOW
;
3280 table_clk_vlt
->entries
[1].v
= 720;
3281 table_clk_vlt
->entries
[2].clk
= PP_DAL_POWERLEVEL_NOMINAL
;
3282 table_clk_vlt
->entries
[2].v
= 810;
3283 table_clk_vlt
->entries
[3].clk
= PP_DAL_POWERLEVEL_PERFORMANCE
;
3284 table_clk_vlt
->entries
[3].v
= 900;
3285 pptable_info
->vddc_dep_on_dal_pwrl
= table_clk_vlt
;
3286 hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
= table_clk_vlt
;
3292 static int tonga_set_private_var_based_on_pptale(struct pp_hwmgr
*hwmgr
)
3294 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3295 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3297 phm_ppt_v1_clock_voltage_dependency_table
*allowed_sclk_vdd_table
=
3298 pptable_info
->vdd_dep_on_sclk
;
3299 phm_ppt_v1_clock_voltage_dependency_table
*allowed_mclk_vdd_table
=
3300 pptable_info
->vdd_dep_on_mclk
;
3302 PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table
!= NULL
,
3303 "VDD dependency on SCLK table is missing. \
3304 This table is mandatory", return -1);
3305 PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table
->count
>= 1,
3306 "VDD dependency on SCLK table has to have is missing. \
3307 This table is mandatory", return -1);
3309 PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table
!= NULL
,
3310 "VDD dependency on MCLK table is missing. \
3311 This table is mandatory", return -1);
3312 PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table
->count
>= 1,
3313 "VDD dependency on MCLK table has to have is missing. \
3314 This table is mandatory", return -1);
3316 data
->min_vddc_in_pp_table
= (uint16_t)allowed_sclk_vdd_table
->entries
[0].vddc
;
3317 data
->max_vddc_in_pp_table
= (uint16_t)allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].vddc
;
3319 pptable_info
->max_clock_voltage_on_ac
.sclk
=
3320 allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].clk
;
3321 pptable_info
->max_clock_voltage_on_ac
.mclk
=
3322 allowed_mclk_vdd_table
->entries
[allowed_mclk_vdd_table
->count
- 1].clk
;
3323 pptable_info
->max_clock_voltage_on_ac
.vddc
=
3324 allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].vddc
;
3325 pptable_info
->max_clock_voltage_on_ac
.vddci
=
3326 allowed_mclk_vdd_table
->entries
[allowed_mclk_vdd_table
->count
- 1].vddci
;
3328 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.sclk
=
3329 pptable_info
->max_clock_voltage_on_ac
.sclk
;
3330 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.mclk
=
3331 pptable_info
->max_clock_voltage_on_ac
.mclk
;
3332 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.vddc
=
3333 pptable_info
->max_clock_voltage_on_ac
.vddc
;
3334 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.vddci
=
3335 pptable_info
->max_clock_voltage_on_ac
.vddci
;
3340 int tonga_unforce_dpm_levels(struct pp_hwmgr
*hwmgr
)
3342 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3345 PP_ASSERT_WITH_CODE (!tonga_is_dpm_running(hwmgr
),
3346 "Trying to Unforce DPM when DPM is disabled. Returning without sending SMC message.",
3349 if (0 == data
->pcie_dpm_key_disabled
) {
3350 PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(
3352 PPSMC_MSG_PCIeDPM_UnForceLevel
)),
3353 "unforce pcie level failed!",
3357 result
= tonga_upload_dpm_level_enable_mask(hwmgr
);
3362 static uint32_t tonga_get_lowest_enable_level(
3363 struct pp_hwmgr
*hwmgr
, uint32_t level_mask
)
3367 while (0 == (level_mask
& (1 << level
)))
3373 static int tonga_force_dpm_lowest(struct pp_hwmgr
*hwmgr
)
3376 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3378 if (0 == data
->pcie_dpm_key_disabled
) {
3380 if (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
!= 0) {
3381 level
= tonga_get_lowest_enable_level(hwmgr
,
3382 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
);
3383 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr
, level
)),
3384 "force lowest pcie dpm state failed!", return -1);
3388 if (0 == data
->sclk_dpm_key_disabled
) {
3390 if (0 != data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
3391 level
= tonga_get_lowest_enable_level(hwmgr
,
3392 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
3394 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr
, level
)),
3395 "force sclk dpm state failed!", return -1);
3397 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
,
3398 CGS_IND_REG__SMC
, TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_SCLK_INDEX
) != level
)
3399 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3400 Curr_Sclk_Index does not match the level \n");
3404 if (0 == data
->mclk_dpm_key_disabled
) {
3406 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
!= 0) {
3407 level
= tonga_get_lowest_enable_level(hwmgr
,
3408 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
);
3409 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr
, level
)),
3410 "force lowest mclk dpm state failed!", return -1);
3411 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3412 TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_MCLK_INDEX
) != level
)
3413 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3414 Curr_Mclk_Index does not match the level \n");
3421 static int tonga_patch_voltage_dependency_tables_with_lookup_table(struct pp_hwmgr
*hwmgr
)
3425 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3426 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3428 phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
= pptable_info
->vdd_dep_on_sclk
;
3429 phm_ppt_v1_clock_voltage_dependency_table
*mclk_table
= pptable_info
->vdd_dep_on_mclk
;
3430 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
3432 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3433 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
3434 voltageId
= sclk_table
->entries
[entryId
].vddInd
;
3435 sclk_table
->entries
[entryId
].vddgfx
=
3436 pptable_info
->vddgfx_lookup_table
->entries
[voltageId
].us_vdd
;
3439 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
3440 voltageId
= sclk_table
->entries
[entryId
].vddInd
;
3441 sclk_table
->entries
[entryId
].vddc
=
3442 pptable_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
3446 for (entryId
= 0; entryId
< mclk_table
->count
; ++entryId
) {
3447 voltageId
= mclk_table
->entries
[entryId
].vddInd
;
3448 mclk_table
->entries
[entryId
].vddc
=
3449 pptable_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
3452 for (entryId
= 0; entryId
< mm_table
->count
; ++entryId
) {
3453 voltageId
= mm_table
->entries
[entryId
].vddcInd
;
3454 mm_table
->entries
[entryId
].vddc
=
3455 pptable_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
3462 static int tonga_calc_voltage_dependency_tables(struct pp_hwmgr
*hwmgr
)
3465 phm_ppt_v1_voltage_lookup_record v_record
;
3466 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3467 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3469 phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
= pptable_info
->vdd_dep_on_sclk
;
3470 phm_ppt_v1_clock_voltage_dependency_table
*mclk_table
= pptable_info
->vdd_dep_on_mclk
;
3472 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3473 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
3474 if (sclk_table
->entries
[entryId
].vdd_offset
& (1 << 15))
3475 v_record
.us_vdd
= sclk_table
->entries
[entryId
].vddgfx
+
3476 sclk_table
->entries
[entryId
].vdd_offset
- 0xFFFF;
3478 v_record
.us_vdd
= sclk_table
->entries
[entryId
].vddgfx
+
3479 sclk_table
->entries
[entryId
].vdd_offset
;
3481 sclk_table
->entries
[entryId
].vddc
=
3482 v_record
.us_cac_low
= v_record
.us_cac_mid
=
3483 v_record
.us_cac_high
= v_record
.us_vdd
;
3485 tonga_add_voltage(hwmgr
, pptable_info
->vddc_lookup_table
, &v_record
);
3488 for (entryId
= 0; entryId
< mclk_table
->count
; ++entryId
) {
3489 if (mclk_table
->entries
[entryId
].vdd_offset
& (1 << 15))
3490 v_record
.us_vdd
= mclk_table
->entries
[entryId
].vddc
+
3491 mclk_table
->entries
[entryId
].vdd_offset
- 0xFFFF;
3493 v_record
.us_vdd
= mclk_table
->entries
[entryId
].vddc
+
3494 mclk_table
->entries
[entryId
].vdd_offset
;
3496 mclk_table
->entries
[entryId
].vddgfx
= v_record
.us_cac_low
=
3497 v_record
.us_cac_mid
= v_record
.us_cac_high
= v_record
.us_vdd
;
3498 tonga_add_voltage(hwmgr
, pptable_info
->vddgfx_lookup_table
, &v_record
);
3506 static int tonga_calc_mm_voltage_dependency_table(struct pp_hwmgr
*hwmgr
)
3509 phm_ppt_v1_voltage_lookup_record v_record
;
3510 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3511 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3512 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
3514 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3515 for (entryId
= 0; entryId
< mm_table
->count
; entryId
++) {
3516 if (mm_table
->entries
[entryId
].vddgfx_offset
& (1 << 15))
3517 v_record
.us_vdd
= mm_table
->entries
[entryId
].vddc
+
3518 mm_table
->entries
[entryId
].vddgfx_offset
- 0xFFFF;
3520 v_record
.us_vdd
= mm_table
->entries
[entryId
].vddc
+
3521 mm_table
->entries
[entryId
].vddgfx_offset
;
3523 /* Add the calculated VDDGFX to the VDDGFX lookup table */
3524 mm_table
->entries
[entryId
].vddgfx
= v_record
.us_cac_low
=
3525 v_record
.us_cac_mid
= v_record
.us_cac_high
= v_record
.us_vdd
;
3526 tonga_add_voltage(hwmgr
, pptable_info
->vddgfx_lookup_table
, &v_record
);
3534 * Change virtual leakage voltage to actual value.
3536 * @param hwmgr the address of the powerplay hardware manager.
3537 * @param pointer to changing voltage
3538 * @param pointer to leakage table
3540 static void tonga_patch_with_vdd_leakage(struct pp_hwmgr
*hwmgr
,
3541 uint16_t *voltage
, phw_tonga_leakage_voltage
*pLeakageTable
)
3543 uint32_t leakage_index
;
3545 /* search for leakage voltage ID 0xff01 ~ 0xff08 */
3546 for (leakage_index
= 0; leakage_index
< pLeakageTable
->count
; leakage_index
++) {
3547 /* if this voltage matches a leakage voltage ID */
3548 /* patch with actual leakage voltage */
3549 if (pLeakageTable
->leakage_id
[leakage_index
] == *voltage
) {
3550 *voltage
= pLeakageTable
->actual_voltage
[leakage_index
];
3555 if (*voltage
> ATOM_VIRTUAL_VOLTAGE_ID0
)
3556 printk(KERN_ERR
"[ powerplay ] Voltage value looks like a Leakage ID but it's not patched \n");
3560 * Patch voltage lookup table by EVV leakages.
3562 * @param hwmgr the address of the powerplay hardware manager.
3563 * @param pointer to voltage lookup table
3564 * @param pointer to leakage table
3567 static int tonga_patch_lookup_table_with_leakage(struct pp_hwmgr
*hwmgr
,
3568 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
3569 phw_tonga_leakage_voltage
*pLeakageTable
)
3573 for (i
= 0; i
< lookup_table
->count
; i
++) {
3574 tonga_patch_with_vdd_leakage(hwmgr
,
3575 &lookup_table
->entries
[i
].us_vdd
, pLeakageTable
);
3581 static int tonga_patch_clock_voltage_lomits_with_vddc_leakage(struct pp_hwmgr
*hwmgr
,
3582 phw_tonga_leakage_voltage
*pLeakageTable
, uint16_t *Vddc
)
3584 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3586 tonga_patch_with_vdd_leakage(hwmgr
, (uint16_t *)Vddc
, pLeakageTable
);
3587 hwmgr
->dyn_state
.max_clock_voltage_on_dc
.vddc
=
3588 pptable_info
->max_clock_voltage_on_dc
.vddc
;
3593 static int tonga_patch_clock_voltage_limits_with_vddgfx_leakage(
3594 struct pp_hwmgr
*hwmgr
, phw_tonga_leakage_voltage
*pLeakageTable
,
3597 tonga_patch_with_vdd_leakage(hwmgr
, (uint16_t *)Vddgfx
, pLeakageTable
);
3601 int tonga_sort_lookup_table(struct pp_hwmgr
*hwmgr
,
3602 phm_ppt_v1_voltage_lookup_table
*lookup_table
)
3604 uint32_t table_size
, i
, j
;
3605 phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record
;
3606 table_size
= lookup_table
->count
;
3608 PP_ASSERT_WITH_CODE(0 != lookup_table
->count
,
3609 "Lookup table is empty", return -1);
3611 /* Sorting voltages */
3612 for (i
= 0; i
< table_size
- 1; i
++) {
3613 for (j
= i
+ 1; j
> 0; j
--) {
3614 if (lookup_table
->entries
[j
].us_vdd
< lookup_table
->entries
[j
-1].us_vdd
) {
3615 tmp_voltage_lookup_record
= lookup_table
->entries
[j
-1];
3616 lookup_table
->entries
[j
-1] = lookup_table
->entries
[j
];
3617 lookup_table
->entries
[j
] = tmp_voltage_lookup_record
;
3625 static int tonga_complete_dependency_tables(struct pp_hwmgr
*hwmgr
)
3629 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
3630 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3632 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3633 tmp_result
= tonga_patch_lookup_table_with_leakage(hwmgr
,
3634 pptable_info
->vddgfx_lookup_table
, &(data
->vddcgfx_leakage
));
3635 if (tmp_result
!= 0)
3636 result
= tmp_result
;
3638 tmp_result
= tonga_patch_clock_voltage_limits_with_vddgfx_leakage(hwmgr
,
3639 &(data
->vddcgfx_leakage
), &pptable_info
->max_clock_voltage_on_dc
.vddgfx
);
3640 if (tmp_result
!= 0)
3641 result
= tmp_result
;
3643 tmp_result
= tonga_patch_lookup_table_with_leakage(hwmgr
,
3644 pptable_info
->vddc_lookup_table
, &(data
->vddc_leakage
));
3645 if (tmp_result
!= 0)
3646 result
= tmp_result
;
3648 tmp_result
= tonga_patch_clock_voltage_lomits_with_vddc_leakage(hwmgr
,
3649 &(data
->vddc_leakage
), &pptable_info
->max_clock_voltage_on_dc
.vddc
);
3650 if (tmp_result
!= 0)
3651 result
= tmp_result
;
3654 tmp_result
= tonga_patch_voltage_dependency_tables_with_lookup_table(hwmgr
);
3655 if (tmp_result
!= 0)
3656 result
= tmp_result
;
3658 tmp_result
= tonga_calc_voltage_dependency_tables(hwmgr
);
3659 if (tmp_result
!= 0)
3660 result
= tmp_result
;
3662 tmp_result
= tonga_calc_mm_voltage_dependency_table(hwmgr
);
3663 if (tmp_result
!= 0)
3664 result
= tmp_result
;
3666 tmp_result
= tonga_sort_lookup_table(hwmgr
, pptable_info
->vddgfx_lookup_table
);
3667 if (tmp_result
!= 0)
3668 result
= tmp_result
;
3670 tmp_result
= tonga_sort_lookup_table(hwmgr
, pptable_info
->vddc_lookup_table
);
3671 if (tmp_result
!= 0)
3672 result
= tmp_result
;
3677 int tonga_init_sclk_threshold(struct pp_hwmgr
*hwmgr
)
3679 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3680 data
->low_sclk_interrupt_threshold
= 0;
3685 int tonga_setup_asic_task(struct pp_hwmgr
*hwmgr
)
3687 int tmp_result
, result
= 0;
3689 tmp_result
= tonga_read_clock_registers(hwmgr
);
3690 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3691 "Failed to read clock registers!", result
= tmp_result
);
3693 tmp_result
= tonga_get_memory_type(hwmgr
);
3694 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3695 "Failed to get memory type!", result
= tmp_result
);
3697 tmp_result
= tonga_enable_acpi_power_management(hwmgr
);
3698 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3699 "Failed to enable ACPI power management!", result
= tmp_result
);
3701 tmp_result
= tonga_init_power_gate_state(hwmgr
);
3702 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3703 "Failed to init power gate state!", result
= tmp_result
);
3705 tmp_result
= tonga_get_mc_microcode_version(hwmgr
);
3706 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3707 "Failed to get MC microcode version!", result
= tmp_result
);
3709 tmp_result
= tonga_init_sclk_threshold(hwmgr
);
3710 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3711 "Failed to init sclk threshold!", result
= tmp_result
);
3717 * Enable voltage control
3719 * @param hwmgr the address of the powerplay hardware manager.
3722 int tonga_enable_voltage_control(struct pp_hwmgr
*hwmgr
)
3724 /* enable voltage control */
3725 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, VOLT_PWRMGT_EN
, 1);
3731 * Checks if we want to support voltage control
3733 * @param hwmgr the address of the powerplay hardware manager.
3735 bool cf_tonga_voltage_control(const struct pp_hwmgr
*hwmgr
)
3737 const struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
3739 return(TONGA_VOLTAGE_CONTROL_NONE
!= data
->voltage_control
);
3742 /*---------------------------MC----------------------------*/
3744 uint8_t tonga_get_memory_modile_index(struct pp_hwmgr
*hwmgr
)
3746 return (uint8_t) (0xFF & (cgs_read_register(hwmgr
->device
, mmBIOS_SCRATCH_4
) >> 16));
3749 bool tonga_check_s0_mc_reg_index(uint16_t inReg
, uint16_t *outReg
)
3754 case mmMC_SEQ_RAS_TIMING
:
3755 *outReg
= mmMC_SEQ_RAS_TIMING_LP
;
3758 case mmMC_SEQ_DLL_STBY
:
3759 *outReg
= mmMC_SEQ_DLL_STBY_LP
;
3762 case mmMC_SEQ_G5PDX_CMD0
:
3763 *outReg
= mmMC_SEQ_G5PDX_CMD0_LP
;
3766 case mmMC_SEQ_G5PDX_CMD1
:
3767 *outReg
= mmMC_SEQ_G5PDX_CMD1_LP
;
3770 case mmMC_SEQ_G5PDX_CTRL
:
3771 *outReg
= mmMC_SEQ_G5PDX_CTRL_LP
;
3774 case mmMC_SEQ_CAS_TIMING
:
3775 *outReg
= mmMC_SEQ_CAS_TIMING_LP
;
3778 case mmMC_SEQ_MISC_TIMING
:
3779 *outReg
= mmMC_SEQ_MISC_TIMING_LP
;
3782 case mmMC_SEQ_MISC_TIMING2
:
3783 *outReg
= mmMC_SEQ_MISC_TIMING2_LP
;
3786 case mmMC_SEQ_PMG_DVS_CMD
:
3787 *outReg
= mmMC_SEQ_PMG_DVS_CMD_LP
;
3790 case mmMC_SEQ_PMG_DVS_CTL
:
3791 *outReg
= mmMC_SEQ_PMG_DVS_CTL_LP
;
3794 case mmMC_SEQ_RD_CTL_D0
:
3795 *outReg
= mmMC_SEQ_RD_CTL_D0_LP
;
3798 case mmMC_SEQ_RD_CTL_D1
:
3799 *outReg
= mmMC_SEQ_RD_CTL_D1_LP
;
3802 case mmMC_SEQ_WR_CTL_D0
:
3803 *outReg
= mmMC_SEQ_WR_CTL_D0_LP
;
3806 case mmMC_SEQ_WR_CTL_D1
:
3807 *outReg
= mmMC_SEQ_WR_CTL_D1_LP
;
3810 case mmMC_PMG_CMD_EMRS
:
3811 *outReg
= mmMC_SEQ_PMG_CMD_EMRS_LP
;
3814 case mmMC_PMG_CMD_MRS
:
3815 *outReg
= mmMC_SEQ_PMG_CMD_MRS_LP
;
3818 case mmMC_PMG_CMD_MRS1
:
3819 *outReg
= mmMC_SEQ_PMG_CMD_MRS1_LP
;
3822 case mmMC_SEQ_PMG_TIMING
:
3823 *outReg
= mmMC_SEQ_PMG_TIMING_LP
;
3826 case mmMC_PMG_CMD_MRS2
:
3827 *outReg
= mmMC_SEQ_PMG_CMD_MRS2_LP
;
3830 case mmMC_SEQ_WR_CTL_2
:
3831 *outReg
= mmMC_SEQ_WR_CTL_2_LP
;
3842 int tonga_set_s0_mc_reg_index(phw_tonga_mc_reg_table
*table
)
3847 for (i
= 0; i
< table
->last
; i
++) {
3848 table
->mc_reg_address
[i
].s0
=
3849 tonga_check_s0_mc_reg_index(table
->mc_reg_address
[i
].s1
, &address
)
3850 ? address
: table
->mc_reg_address
[i
].s1
;
3855 int tonga_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table
*table
, phw_tonga_mc_reg_table
*ni_table
)
3859 PP_ASSERT_WITH_CODE((table
->last
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3860 "Invalid VramInfo table.", return -1);
3861 PP_ASSERT_WITH_CODE((table
->num_entries
<= MAX_AC_TIMING_ENTRIES
),
3862 "Invalid VramInfo table.", return -1);
3864 for (i
= 0; i
< table
->last
; i
++) {
3865 ni_table
->mc_reg_address
[i
].s1
= table
->mc_reg_address
[i
].s1
;
3867 ni_table
->last
= table
->last
;
3869 for (i
= 0; i
< table
->num_entries
; i
++) {
3870 ni_table
->mc_reg_table_entry
[i
].mclk_max
=
3871 table
->mc_reg_table_entry
[i
].mclk_max
;
3872 for (j
= 0; j
< table
->last
; j
++) {
3873 ni_table
->mc_reg_table_entry
[i
].mc_data
[j
] =
3874 table
->mc_reg_table_entry
[i
].mc_data
[j
];
3878 ni_table
->num_entries
= table
->num_entries
;
3884 * VBIOS omits some information to reduce size, we need to recover them here.
3885 * 1. when we see mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to mmMC_PMG_CMD_EMRS /_LP[15:0].
3886 * Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
3887 * 2. when we see mmMC_SEQ_RESERVE_M, bit[15:0] EMRS2, need to be write to mmMC_PMG_CMD_MRS1/_LP[15:0].
3888 * 3. need to set these data for each clock range
3890 * @param hwmgr the address of the powerplay hardware manager.
3891 * @param table the address of MCRegTable
3894 int tonga_set_mc_special_registers(struct pp_hwmgr
*hwmgr
, phw_tonga_mc_reg_table
*table
)
3898 const tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
3900 for (i
= 0, j
= table
->last
; i
< table
->last
; i
++) {
3901 PP_ASSERT_WITH_CODE((j
< SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3902 "Invalid VramInfo table.", return -1);
3903 switch (table
->mc_reg_address
[i
].s1
) {
3905 * mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to mmMC_PMG_CMD_EMRS /_LP[15:0].
3906 * Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
3908 case mmMC_SEQ_MISC1
:
3909 temp_reg
= cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_EMRS
);
3910 table
->mc_reg_address
[j
].s1
= mmMC_PMG_CMD_EMRS
;
3911 table
->mc_reg_address
[j
].s0
= mmMC_SEQ_PMG_CMD_EMRS_LP
;
3912 for (k
= 0; k
< table
->num_entries
; k
++) {
3913 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3914 ((temp_reg
& 0xffff0000)) |
3915 ((table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0xffff0000) >> 16);
3918 PP_ASSERT_WITH_CODE((j
< SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3919 "Invalid VramInfo table.", return -1);
3921 temp_reg
= cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS
);
3922 table
->mc_reg_address
[j
].s1
= mmMC_PMG_CMD_MRS
;
3923 table
->mc_reg_address
[j
].s0
= mmMC_SEQ_PMG_CMD_MRS_LP
;
3924 for (k
= 0; k
< table
->num_entries
; k
++) {
3925 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3926 (temp_reg
& 0xffff0000) |
3927 (table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0x0000ffff);
3929 if (!data
->is_memory_GDDR5
) {
3930 table
->mc_reg_table_entry
[k
].mc_data
[j
] |= 0x100;
3934 PP_ASSERT_WITH_CODE((j
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3935 "Invalid VramInfo table.", return -1);
3937 if (!data
->is_memory_GDDR5
) {
3938 table
->mc_reg_address
[j
].s1
= mmMC_PMG_AUTO_CMD
;
3939 table
->mc_reg_address
[j
].s0
= mmMC_PMG_AUTO_CMD
;
3940 for (k
= 0; k
< table
->num_entries
; k
++) {
3941 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3942 (table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0xffff0000) >> 16;
3945 PP_ASSERT_WITH_CODE((j
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3946 "Invalid VramInfo table.", return -1);
3951 case mmMC_SEQ_RESERVE_M
:
3952 temp_reg
= cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS1
);
3953 table
->mc_reg_address
[j
].s1
= mmMC_PMG_CMD_MRS1
;
3954 table
->mc_reg_address
[j
].s0
= mmMC_SEQ_PMG_CMD_MRS1_LP
;
3955 for (k
= 0; k
< table
->num_entries
; k
++) {
3956 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3957 (temp_reg
& 0xffff0000) |
3958 (table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0x0000ffff);
3961 PP_ASSERT_WITH_CODE((j
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3962 "Invalid VramInfo table.", return -1);
3976 int tonga_set_valid_flag(phw_tonga_mc_reg_table
*table
)
3979 for (i
= 0; i
< table
->last
; i
++) {
3980 for (j
= 1; j
< table
->num_entries
; j
++) {
3981 if (table
->mc_reg_table_entry
[j
-1].mc_data
[i
] !=
3982 table
->mc_reg_table_entry
[j
].mc_data
[i
]) {
3983 table
->validflag
|= (1<<i
);
3992 int tonga_initialize_mc_reg_table(struct pp_hwmgr
*hwmgr
)
3995 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3996 pp_atomctrl_mc_reg_table
*table
;
3997 phw_tonga_mc_reg_table
*ni_table
= &data
->tonga_mc_reg_table
;
3998 uint8_t module_index
= tonga_get_memory_modile_index(hwmgr
);
4000 table
= kzalloc(sizeof(pp_atomctrl_mc_reg_table
), GFP_KERNEL
);
4005 /* Program additional LP registers that are no longer programmed by VBIOS */
4006 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING
));
4007 cgs_write_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING
));
4008 cgs_write_register(hwmgr
->device
, mmMC_SEQ_DLL_STBY_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_DLL_STBY
));
4009 cgs_write_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD0_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD0
));
4010 cgs_write_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD1_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD1
));
4011 cgs_write_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CTRL_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CTRL
));
4012 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CMD_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CMD
));
4013 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CTL_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CTL
));
4014 cgs_write_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING
));
4015 cgs_write_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2
));
4016 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_EMRS_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_EMRS
));
4017 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_MRS_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS
));
4018 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_MRS1_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS1
));
4019 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D0_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D0
));
4020 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1
));
4021 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0
));
4022 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1
));
4023 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING
));
4024 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_MRS2_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS2
));
4025 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_2_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_2
));
4027 memset(table
, 0x00, sizeof(pp_atomctrl_mc_reg_table
));
4029 result
= atomctrl_initialize_mc_reg_table(hwmgr
, module_index
, table
);
4032 result
= tonga_copy_vbios_smc_reg_table(table
, ni_table
);
4035 tonga_set_s0_mc_reg_index(ni_table
);
4036 result
= tonga_set_mc_special_registers(hwmgr
, ni_table
);
4040 tonga_set_valid_flag(ni_table
);
4047 * Copy one arb setting to another and then switch the active set.
4048 * arbFreqSrc and arbFreqDest is one of the MC_CG_ARB_FREQ_Fx constants.
4050 int tonga_copy_and_switch_arb_sets(struct pp_hwmgr
*hwmgr
,
4051 uint32_t arbFreqSrc
, uint32_t arbFreqDest
)
4053 uint32_t mc_arb_dram_timing
;
4054 uint32_t mc_arb_dram_timing2
;
4055 uint32_t burst_time
;
4056 uint32_t mc_cg_config
;
4058 switch (arbFreqSrc
) {
4059 case MC_CG_ARB_FREQ_F0
:
4060 mc_arb_dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
4061 mc_arb_dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
4062 burst_time
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
);
4065 case MC_CG_ARB_FREQ_F1
:
4066 mc_arb_dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING_1
);
4067 mc_arb_dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2_1
);
4068 burst_time
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE1
);
4075 switch (arbFreqDest
) {
4076 case MC_CG_ARB_FREQ_F0
:
4077 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
, mc_arb_dram_timing
);
4078 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
, mc_arb_dram_timing2
);
4079 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
, burst_time
);
4082 case MC_CG_ARB_FREQ_F1
:
4083 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING_1
, mc_arb_dram_timing
);
4084 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2_1
, mc_arb_dram_timing2
);
4085 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE1
, burst_time
);
4092 mc_cg_config
= cgs_read_register(hwmgr
->device
, mmMC_CG_CONFIG
);
4093 mc_cg_config
|= 0x0000000F;
4094 cgs_write_register(hwmgr
->device
, mmMC_CG_CONFIG
, mc_cg_config
);
4095 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_CG
, CG_ARB_REQ
, arbFreqDest
);
4101 * Initial switch from ARB F0->F1
4103 * @param hwmgr the address of the powerplay hardware manager.
4105 * This function is to be called from the SetPowerState table.
4107 int tonga_initial_switch_from_arb_f0_to_f1(struct pp_hwmgr
*hwmgr
)
4109 return tonga_copy_and_switch_arb_sets(hwmgr
, MC_CG_ARB_FREQ_F0
, MC_CG_ARB_FREQ_F1
);
4113 * Initialize the ARB DRAM timing table's index field.
4115 * @param hwmgr the address of the powerplay hardware manager.
4118 int tonga_init_arb_table_index(struct pp_hwmgr
*hwmgr
)
4120 const tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4125 * This is a read-modify-write on the first byte of the ARB table.
4126 * The first byte in the SMU72_Discrete_MCArbDramTimingTable structure is the field 'current'.
4127 * This solution is ugly, but we never write the whole table only individual fields in it.
4128 * In reality this field should not be in that structure but in a soft register.
4130 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
4131 data
->arb_table_start
, &tmp
, data
->sram_end
);
4137 tmp
|= ((uint32_t)MC_CG_ARB_FREQ_F1
) << 24;
4139 return tonga_write_smc_sram_dword(hwmgr
->smumgr
,
4140 data
->arb_table_start
, tmp
, data
->sram_end
);
4143 int tonga_populate_mc_reg_address(struct pp_hwmgr
*hwmgr
, SMU72_Discrete_MCRegisters
*mc_reg_table
)
4145 const struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4149 for (i
= 0, j
= 0; j
< data
->tonga_mc_reg_table
.last
; j
++) {
4150 if (data
->tonga_mc_reg_table
.validflag
& 1<<j
) {
4151 PP_ASSERT_WITH_CODE(i
< SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
,
4152 "Index of mc_reg_table->address[] array out of boundary", return -1);
4153 mc_reg_table
->address
[i
].s0
=
4154 PP_HOST_TO_SMC_US(data
->tonga_mc_reg_table
.mc_reg_address
[j
].s0
);
4155 mc_reg_table
->address
[i
].s1
=
4156 PP_HOST_TO_SMC_US(data
->tonga_mc_reg_table
.mc_reg_address
[j
].s1
);
4161 mc_reg_table
->last
= (uint8_t)i
;
4166 /*convert register values from driver to SMC format */
4167 void tonga_convert_mc_registers(
4168 const phw_tonga_mc_reg_entry
* pEntry
,
4169 SMU72_Discrete_MCRegisterSet
*pData
,
4170 uint32_t numEntries
, uint32_t validflag
)
4174 for (i
= 0, j
= 0; j
< numEntries
; j
++) {
4175 if (validflag
& 1<<j
) {
4176 pData
->value
[i
] = PP_HOST_TO_SMC_UL(pEntry
->mc_data
[j
]);
4182 /* find the entry in the memory range table, then populate the value to SMC's tonga_mc_reg_table */
4183 int tonga_convert_mc_reg_table_entry_to_smc(
4184 struct pp_hwmgr
*hwmgr
,
4185 const uint32_t memory_clock
,
4186 SMU72_Discrete_MCRegisterSet
*mc_reg_table_data
4189 const tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4192 for (i
= 0; i
< data
->tonga_mc_reg_table
.num_entries
; i
++) {
4194 data
->tonga_mc_reg_table
.mc_reg_table_entry
[i
].mclk_max
) {
4199 if ((i
== data
->tonga_mc_reg_table
.num_entries
) && (i
> 0))
4202 tonga_convert_mc_registers(&data
->tonga_mc_reg_table
.mc_reg_table_entry
[i
],
4203 mc_reg_table_data
, data
->tonga_mc_reg_table
.last
, data
->tonga_mc_reg_table
.validflag
);
4208 int tonga_convert_mc_reg_table_to_smc(struct pp_hwmgr
*hwmgr
,
4209 SMU72_Discrete_MCRegisters
*mc_reg_table
)
4212 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4216 for (i
= 0; i
< data
->dpm_table
.mclk_table
.count
; i
++) {
4217 res
= tonga_convert_mc_reg_table_entry_to_smc(
4219 data
->dpm_table
.mclk_table
.dpm_levels
[i
].value
,
4220 &mc_reg_table
->data
[i
]
4230 int tonga_populate_initial_mc_reg_table(struct pp_hwmgr
*hwmgr
)
4233 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4235 memset(&data
->mc_reg_table
, 0x00, sizeof(SMU72_Discrete_MCRegisters
));
4236 result
= tonga_populate_mc_reg_address(hwmgr
, &(data
->mc_reg_table
));
4237 PP_ASSERT_WITH_CODE(0 == result
,
4238 "Failed to initialize MCRegTable for the MC register addresses!", return result
;);
4240 result
= tonga_convert_mc_reg_table_to_smc(hwmgr
, &data
->mc_reg_table
);
4241 PP_ASSERT_WITH_CODE(0 == result
,
4242 "Failed to initialize MCRegTable for driver state!", return result
;);
4244 return tonga_copy_bytes_to_smc(hwmgr
->smumgr
, data
->mc_reg_table_start
,
4245 (uint8_t *)&data
->mc_reg_table
, sizeof(SMU72_Discrete_MCRegisters
), data
->sram_end
);
4249 * Programs static screed detection parameters
4251 * @param hwmgr the address of the powerplay hardware manager.
4254 int tonga_program_static_screen_threshold_parameters(struct pp_hwmgr
*hwmgr
)
4256 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
4258 /* Set static screen threshold unit*/
4259 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
,
4260 CGS_IND_REG__SMC
, CG_STATIC_SCREEN_PARAMETER
, STATIC_SCREEN_THRESHOLD_UNIT
,
4261 data
->static_screen_threshold_unit
);
4262 /* Set static screen threshold*/
4263 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
,
4264 CGS_IND_REG__SMC
, CG_STATIC_SCREEN_PARAMETER
, STATIC_SCREEN_THRESHOLD
,
4265 data
->static_screen_threshold
);
4271 * Setup display gap for glitch free memory clock switching.
4273 * @param hwmgr the address of the powerplay hardware manager.
4276 int tonga_enable_display_gap(struct pp_hwmgr
*hwmgr
)
4278 uint32_t display_gap
= cgs_read_ind_register(hwmgr
->device
,
4279 CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
);
4281 display_gap
= PHM_SET_FIELD(display_gap
,
4282 CG_DISPLAY_GAP_CNTL
, DISP_GAP
, DISPLAY_GAP_IGNORE
);
4284 display_gap
= PHM_SET_FIELD(display_gap
,
4285 CG_DISPLAY_GAP_CNTL
, DISP_GAP_MCHG
, DISPLAY_GAP_VBLANK
);
4287 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4288 ixCG_DISPLAY_GAP_CNTL
, display_gap
);
4294 * Programs activity state transition voting clients
4296 * @param hwmgr the address of the powerplay hardware manager.
4299 int tonga_program_voting_clients(struct pp_hwmgr
*hwmgr
)
4301 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
4303 /* Clear reset for voting clients before enabling DPM */
4304 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
4305 SCLK_PWRMGT_CNTL
, RESET_SCLK_CNT
, 0);
4306 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
4307 SCLK_PWRMGT_CNTL
, RESET_BUSY_CNT
, 0);
4309 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4310 ixCG_FREQ_TRAN_VOTING_0
, data
->voting_rights_clients0
);
4311 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4312 ixCG_FREQ_TRAN_VOTING_1
, data
->voting_rights_clients1
);
4313 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4314 ixCG_FREQ_TRAN_VOTING_2
, data
->voting_rights_clients2
);
4315 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4316 ixCG_FREQ_TRAN_VOTING_3
, data
->voting_rights_clients3
);
4317 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4318 ixCG_FREQ_TRAN_VOTING_4
, data
->voting_rights_clients4
);
4319 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4320 ixCG_FREQ_TRAN_VOTING_5
, data
->voting_rights_clients5
);
4321 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4322 ixCG_FREQ_TRAN_VOTING_6
, data
->voting_rights_clients6
);
4323 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4324 ixCG_FREQ_TRAN_VOTING_7
, data
->voting_rights_clients7
);
4330 int tonga_enable_dpm_tasks(struct pp_hwmgr
*hwmgr
)
4332 int tmp_result
, result
= 0;
4334 tmp_result
= tonga_check_for_dpm_stopped(hwmgr
);
4336 if (cf_tonga_voltage_control(hwmgr
)) {
4337 tmp_result
= tonga_enable_voltage_control(hwmgr
);
4338 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4339 "Failed to enable voltage control!", result
= tmp_result
);
4341 tmp_result
= tonga_construct_voltage_tables(hwmgr
);
4342 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4343 "Failed to contruct voltage tables!", result
= tmp_result
);
4346 tmp_result
= tonga_initialize_mc_reg_table(hwmgr
);
4347 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4348 "Failed to initialize MC reg table!", result
= tmp_result
);
4350 tmp_result
= tonga_program_static_screen_threshold_parameters(hwmgr
);
4351 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4352 "Failed to program static screen threshold parameters!", result
= tmp_result
);
4354 tmp_result
= tonga_enable_display_gap(hwmgr
);
4355 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4356 "Failed to enable display gap!", result
= tmp_result
);
4358 tmp_result
= tonga_program_voting_clients(hwmgr
);
4359 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4360 "Failed to program voting clients!", result
= tmp_result
);
4362 tmp_result
= tonga_process_firmware_header(hwmgr
);
4363 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4364 "Failed to process firmware header!", result
= tmp_result
);
4366 tmp_result
= tonga_initial_switch_from_arb_f0_to_f1(hwmgr
);
4367 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4368 "Failed to initialize switch from ArbF0 to F1!", result
= tmp_result
);
4370 tmp_result
= tonga_init_smc_table(hwmgr
);
4371 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4372 "Failed to initialize SMC table!", result
= tmp_result
);
4374 tmp_result
= tonga_init_arb_table_index(hwmgr
);
4375 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4376 "Failed to initialize ARB table index!", result
= tmp_result
);
4378 tmp_result
= tonga_populate_pm_fuses(hwmgr
);
4379 PP_ASSERT_WITH_CODE((tmp_result
== 0),
4380 "Failed to populate PM fuses!", result
= tmp_result
);
4382 tmp_result
= tonga_populate_initial_mc_reg_table(hwmgr
);
4383 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4384 "Failed to populate initialize MC Reg table!", result
= tmp_result
);
4386 tmp_result
= tonga_notify_smc_display_change(hwmgr
, false);
4387 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4388 "Failed to notify no display!", result
= tmp_result
);
4390 /* enable SCLK control */
4391 tmp_result
= tonga_enable_sclk_control(hwmgr
);
4392 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4393 "Failed to enable SCLK control!", result
= tmp_result
);
4396 tmp_result
= tonga_start_dpm(hwmgr
);
4397 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4398 "Failed to start DPM!", result
= tmp_result
);
4400 tmp_result
= tonga_enable_smc_cac(hwmgr
);
4401 PP_ASSERT_WITH_CODE((tmp_result
== 0),
4402 "Failed to enable SMC CAC!", result
= tmp_result
);
4404 tmp_result
= tonga_enable_power_containment(hwmgr
);
4405 PP_ASSERT_WITH_CODE((tmp_result
== 0),
4406 "Failed to enable power containment!", result
= tmp_result
);
4408 tmp_result
= tonga_power_control_set_level(hwmgr
);
4409 PP_ASSERT_WITH_CODE((tmp_result
== 0),
4410 "Failed to power control set level!", result
= tmp_result
);
4415 int tonga_disable_dpm_tasks(struct pp_hwmgr
*hwmgr
)
4417 int tmp_result
, result
= 0;
4419 tmp_result
= tonga_check_for_dpm_running(hwmgr
);
4420 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4421 "SMC is still running!", return 0);
4423 tmp_result
= tonga_stop_dpm(hwmgr
);
4424 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4425 "Failed to stop DPM!", result
= tmp_result
);
4427 tmp_result
= tonga_reset_to_default(hwmgr
);
4428 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4429 "Failed to reset to default!", result
= tmp_result
);
4434 int tonga_reset_asic_tasks(struct pp_hwmgr
*hwmgr
)
4438 result
= tonga_set_boot_state(hwmgr
);
4440 printk(KERN_ERR
"[ powerplay ] Failed to reset asic via set boot state! \n");
4445 int tonga_hwmgr_backend_fini(struct pp_hwmgr
*hwmgr
)
4447 return phm_hwmgr_backend_fini(hwmgr
);
4451 * Initializes the Volcanic Islands Hardware Manager
4453 * @param hwmgr the address of the powerplay hardware manager.
4454 * @return 1 if success; otherwise appropriate error code.
4456 int tonga_hwmgr_backend_init(struct pp_hwmgr
*hwmgr
)
4459 SMU72_Discrete_DpmTable
*table
= NULL
;
4461 pp_atomctrl_gpio_pin_assignment gpio_pin_assignment
;
4462 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4463 phw_tonga_ulv_parm
*ulv
;
4464 struct cgs_system_info sys_info
= {0};
4466 PP_ASSERT_WITH_CODE((NULL
!= hwmgr
),
4467 "Invalid Parameter!", return -1;);
4469 data
= kzalloc(sizeof(struct tonga_hwmgr
), GFP_KERNEL
);
4473 hwmgr
->backend
= data
;
4475 data
->dll_defaule_on
= false;
4476 data
->sram_end
= SMC_RAM_END
;
4478 data
->activity_target
[0] = PPTONGA_TARGETACTIVITY_DFLT
;
4479 data
->activity_target
[1] = PPTONGA_TARGETACTIVITY_DFLT
;
4480 data
->activity_target
[2] = PPTONGA_TARGETACTIVITY_DFLT
;
4481 data
->activity_target
[3] = PPTONGA_TARGETACTIVITY_DFLT
;
4482 data
->activity_target
[4] = PPTONGA_TARGETACTIVITY_DFLT
;
4483 data
->activity_target
[5] = PPTONGA_TARGETACTIVITY_DFLT
;
4484 data
->activity_target
[6] = PPTONGA_TARGETACTIVITY_DFLT
;
4485 data
->activity_target
[7] = PPTONGA_TARGETACTIVITY_DFLT
;
4487 data
->vddc_vddci_delta
= VDDC_VDDCI_DELTA
;
4488 data
->vddc_vddgfx_delta
= VDDC_VDDGFX_DELTA
;
4489 data
->mclk_activity_target
= PPTONGA_MCLK_TARGETACTIVITY_DFLT
;
4491 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4492 PHM_PlatformCaps_DisableVoltageIsland
);
4494 data
->sclk_dpm_key_disabled
= 0;
4495 data
->mclk_dpm_key_disabled
= 0;
4496 data
->pcie_dpm_key_disabled
= 0;
4497 data
->pcc_monitor_enabled
= 0;
4499 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4500 PHM_PlatformCaps_UnTabledHardwareInterface
);
4502 data
->gpio_debug
= 0;
4503 data
->engine_clock_data
= 0;
4504 data
->memory_clock_data
= 0;
4505 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4506 PHM_PlatformCaps_DynamicPatchPowerState
);
4508 /* need to set voltage control types before EVV patching*/
4509 data
->voltage_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4510 data
->vdd_ci_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4511 data
->vdd_gfx_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4512 data
->mvdd_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4513 data
->force_pcie_gen
= PP_PCIEGenInvalid
;
4515 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4516 VOLTAGE_TYPE_VDDC
, VOLTAGE_OBJ_SVID2
)) {
4517 data
->voltage_control
= TONGA_VOLTAGE_CONTROL_BY_SVID2
;
4520 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4521 PHM_PlatformCaps_ControlVDDGFX
)) {
4522 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4523 VOLTAGE_TYPE_VDDGFX
, VOLTAGE_OBJ_SVID2
)) {
4524 data
->vdd_gfx_control
= TONGA_VOLTAGE_CONTROL_BY_SVID2
;
4528 if (TONGA_VOLTAGE_CONTROL_NONE
== data
->vdd_gfx_control
) {
4529 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4530 PHM_PlatformCaps_ControlVDDGFX
);
4533 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4534 PHM_PlatformCaps_EnableMVDDControl
)) {
4535 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4536 VOLTAGE_TYPE_MVDDC
, VOLTAGE_OBJ_GPIO_LUT
)) {
4537 data
->mvdd_control
= TONGA_VOLTAGE_CONTROL_BY_GPIO
;
4541 if (TONGA_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
) {
4542 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4543 PHM_PlatformCaps_EnableMVDDControl
);
4546 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4547 PHM_PlatformCaps_ControlVDDCI
)) {
4548 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4549 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_GPIO_LUT
))
4550 data
->vdd_ci_control
= TONGA_VOLTAGE_CONTROL_BY_GPIO
;
4551 else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4552 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_SVID2
))
4553 data
->vdd_ci_control
= TONGA_VOLTAGE_CONTROL_BY_SVID2
;
4556 if (TONGA_VOLTAGE_CONTROL_NONE
== data
->vdd_ci_control
)
4557 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4558 PHM_PlatformCaps_ControlVDDCI
);
4560 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4561 PHM_PlatformCaps_TablelessHardwareInterface
);
4563 if (pptable_info
->cac_dtp_table
->usClockStretchAmount
!= 0)
4564 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4565 PHM_PlatformCaps_ClockStretcher
);
4567 /* Initializes DPM default values*/
4568 tonga_initialize_dpm_defaults(hwmgr
);
4570 /* Get leakage voltage based on leakage ID.*/
4571 PP_ASSERT_WITH_CODE((0 == tonga_get_evv_voltage(hwmgr
)),
4572 "Get EVV Voltage Failed. Abort Driver loading!", return -1);
4574 tonga_complete_dependency_tables(hwmgr
);
4576 /* Parse pptable data read from VBIOS*/
4577 tonga_set_private_var_based_on_pptale(hwmgr
);
4581 ulv
->ulv_supported
= false;
4583 /* Initalize Dynamic State Adjustment Rule Settings*/
4584 result
= tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr
);
4586 printk(KERN_ERR
"[ powerplay ] tonga_initializa_dynamic_state_adjustment_rule_settings failed!\n");
4587 data
->uvd_enabled
= false;
4589 table
= &(data
->smc_state_table
);
4592 * if ucGPIO_ID=VDDC_PCC_GPIO_PINID in GPIO_LUTable,
4593 * Peak Current Control feature is enabled and we should program PCC HW register
4595 if (atomctrl_get_pp_assign_pin(hwmgr
, VDDC_PCC_GPIO_PINID
, &gpio_pin_assignment
)) {
4596 uint32_t temp_reg
= cgs_read_ind_register(hwmgr
->device
,
4597 CGS_IND_REG__SMC
, ixCNB_PWRMGT_CNTL
);
4599 switch (gpio_pin_assignment
.uc_gpio_pin_bit_shift
) {
4601 temp_reg
= PHM_SET_FIELD(temp_reg
,
4602 CNB_PWRMGT_CNTL
, GNB_SLOW_MODE
, 0x1);
4605 temp_reg
= PHM_SET_FIELD(temp_reg
,
4606 CNB_PWRMGT_CNTL
, GNB_SLOW_MODE
, 0x2);
4609 temp_reg
= PHM_SET_FIELD(temp_reg
,
4610 CNB_PWRMGT_CNTL
, GNB_SLOW
, 0x1);
4613 temp_reg
= PHM_SET_FIELD(temp_reg
,
4614 CNB_PWRMGT_CNTL
, FORCE_NB_PS1
, 0x1);
4617 temp_reg
= PHM_SET_FIELD(temp_reg
,
4618 CNB_PWRMGT_CNTL
, DPM_ENABLED
, 0x1);
4621 printk(KERN_ERR
"[ powerplay ] Failed to setup PCC HW register! \
4622 Wrong GPIO assigned for VDDC_PCC_GPIO_PINID! \n");
4625 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4626 ixCNB_PWRMGT_CNTL
, temp_reg
);
4629 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4630 PHM_PlatformCaps_EnableSMU7ThermalManagement
);
4631 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4632 PHM_PlatformCaps_SMU7
);
4634 data
->vddc_phase_shed_control
= false;
4636 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4637 PHM_PlatformCaps_UVDPowerGating
);
4638 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4639 PHM_PlatformCaps_VCEPowerGating
);
4640 sys_info
.size
= sizeof(struct cgs_system_info
);
4641 sys_info
.info_id
= CGS_SYSTEM_INFO_PG_FLAGS
;
4642 result
= cgs_query_system_info(hwmgr
->device
, &sys_info
);
4644 if (sys_info
.value
& AMD_PG_SUPPORT_UVD
)
4645 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4646 PHM_PlatformCaps_UVDPowerGating
);
4647 if (sys_info
.value
& AMD_PG_SUPPORT_VCE
)
4648 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4649 PHM_PlatformCaps_VCEPowerGating
);
4653 data
->is_tlu_enabled
= false;
4654 hwmgr
->platform_descriptor
.hardwareActivityPerformanceLevels
=
4655 TONGA_MAX_HARDWARE_POWERLEVELS
;
4656 hwmgr
->platform_descriptor
.hardwarePerformanceLevels
= 2;
4657 hwmgr
->platform_descriptor
.minimumClocksReductionPercentage
= 50;
4659 sys_info
.size
= sizeof(struct cgs_system_info
);
4660 sys_info
.info_id
= CGS_SYSTEM_INFO_PCIE_GEN_INFO
;
4661 result
= cgs_query_system_info(hwmgr
->device
, &sys_info
);
4663 data
->pcie_gen_cap
= AMDGPU_DEFAULT_PCIE_GEN_MASK
;
4665 data
->pcie_gen_cap
= (uint32_t)sys_info
.value
;
4666 if (data
->pcie_gen_cap
& CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3
)
4667 data
->pcie_spc_cap
= 20;
4668 sys_info
.size
= sizeof(struct cgs_system_info
);
4669 sys_info
.info_id
= CGS_SYSTEM_INFO_PCIE_MLW
;
4670 result
= cgs_query_system_info(hwmgr
->device
, &sys_info
);
4672 data
->pcie_lane_cap
= AMDGPU_DEFAULT_PCIE_MLW_MASK
;
4674 data
->pcie_lane_cap
= (uint32_t)sys_info
.value
;
4676 /* Ignore return value in here, we are cleaning up a mess. */
4677 tonga_hwmgr_backend_fini(hwmgr
);
4683 static int tonga_force_dpm_level(struct pp_hwmgr
*hwmgr
,
4684 enum amd_dpm_forced_level level
)
4689 case AMD_DPM_FORCED_LEVEL_HIGH
:
4690 ret
= tonga_force_dpm_highest(hwmgr
);
4694 case AMD_DPM_FORCED_LEVEL_LOW
:
4695 ret
= tonga_force_dpm_lowest(hwmgr
);
4699 case AMD_DPM_FORCED_LEVEL_AUTO
:
4700 ret
= tonga_unforce_dpm_levels(hwmgr
);
4708 hwmgr
->dpm_level
= level
;
4712 static int tonga_apply_state_adjust_rules(struct pp_hwmgr
*hwmgr
,
4713 struct pp_power_state
*prequest_ps
,
4714 const struct pp_power_state
*pcurrent_ps
)
4716 struct tonga_power_state
*tonga_ps
=
4717 cast_phw_tonga_power_state(&prequest_ps
->hardware
);
4721 struct PP_Clocks minimum_clocks
= {0};
4722 bool disable_mclk_switching
;
4723 bool disable_mclk_switching_for_frame_lock
;
4724 struct cgs_display_info info
= {0};
4725 const struct phm_clock_and_voltage_limits
*max_limits
;
4727 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4728 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4731 int32_t stable_pstate_sclk
= 0, stable_pstate_mclk
= 0;
4733 data
->battery_state
= (PP_StateUILabel_Battery
== prequest_ps
->classification
.ui_label
);
4735 PP_ASSERT_WITH_CODE(tonga_ps
->performance_level_count
== 2,
4736 "VI should always have 2 performance levels",
4739 max_limits
= (PP_PowerSource_AC
== hwmgr
->power_source
) ?
4740 &(hwmgr
->dyn_state
.max_clock_voltage_on_ac
) :
4741 &(hwmgr
->dyn_state
.max_clock_voltage_on_dc
);
4743 if (PP_PowerSource_DC
== hwmgr
->power_source
) {
4744 for (i
= 0; i
< tonga_ps
->performance_level_count
; i
++) {
4745 if (tonga_ps
->performance_levels
[i
].memory_clock
> max_limits
->mclk
)
4746 tonga_ps
->performance_levels
[i
].memory_clock
= max_limits
->mclk
;
4747 if (tonga_ps
->performance_levels
[i
].engine_clock
> max_limits
->sclk
)
4748 tonga_ps
->performance_levels
[i
].engine_clock
= max_limits
->sclk
;
4752 tonga_ps
->vce_clocks
.EVCLK
= hwmgr
->vce_arbiter
.evclk
;
4753 tonga_ps
->vce_clocks
.ECCLK
= hwmgr
->vce_arbiter
.ecclk
;
4755 tonga_ps
->acp_clk
= hwmgr
->acp_arbiter
.acpclk
;
4757 cgs_get_active_displays_info(hwmgr
->device
, &info
);
4759 /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
4761 /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
4763 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
)) {
4765 max_limits
= &(hwmgr
->dyn_state
.max_clock_voltage_on_ac
);
4766 stable_pstate_sclk
= (max_limits
->sclk
* 75) / 100;
4768 for (count
= pptable_info
->vdd_dep_on_sclk
->count
-1; count
>= 0; count
--) {
4769 if (stable_pstate_sclk
>= pptable_info
->vdd_dep_on_sclk
->entries
[count
].clk
) {
4770 stable_pstate_sclk
= pptable_info
->vdd_dep_on_sclk
->entries
[count
].clk
;
4776 stable_pstate_sclk
= pptable_info
->vdd_dep_on_sclk
->entries
[0].clk
;
4778 stable_pstate_mclk
= max_limits
->mclk
;
4780 minimum_clocks
.engineClock
= stable_pstate_sclk
;
4781 minimum_clocks
.memoryClock
= stable_pstate_mclk
;
4784 if (minimum_clocks
.engineClock
< hwmgr
->gfx_arbiter
.sclk
)
4785 minimum_clocks
.engineClock
= hwmgr
->gfx_arbiter
.sclk
;
4787 if (minimum_clocks
.memoryClock
< hwmgr
->gfx_arbiter
.mclk
)
4788 minimum_clocks
.memoryClock
= hwmgr
->gfx_arbiter
.mclk
;
4790 tonga_ps
->sclk_threshold
= hwmgr
->gfx_arbiter
.sclk_threshold
;
4792 if (0 != hwmgr
->gfx_arbiter
.sclk_over_drive
) {
4793 PP_ASSERT_WITH_CODE((hwmgr
->gfx_arbiter
.sclk_over_drive
<= hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
),
4794 "Overdrive sclk exceeds limit",
4795 hwmgr
->gfx_arbiter
.sclk_over_drive
= hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
);
4797 if (hwmgr
->gfx_arbiter
.sclk_over_drive
>= hwmgr
->gfx_arbiter
.sclk
)
4798 tonga_ps
->performance_levels
[1].engine_clock
= hwmgr
->gfx_arbiter
.sclk_over_drive
;
4801 if (0 != hwmgr
->gfx_arbiter
.mclk_over_drive
) {
4802 PP_ASSERT_WITH_CODE((hwmgr
->gfx_arbiter
.mclk_over_drive
<= hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
),
4803 "Overdrive mclk exceeds limit",
4804 hwmgr
->gfx_arbiter
.mclk_over_drive
= hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
);
4806 if (hwmgr
->gfx_arbiter
.mclk_over_drive
>= hwmgr
->gfx_arbiter
.mclk
)
4807 tonga_ps
->performance_levels
[1].memory_clock
= hwmgr
->gfx_arbiter
.mclk_over_drive
;
4810 disable_mclk_switching_for_frame_lock
= phm_cap_enabled(
4811 hwmgr
->platform_descriptor
.platformCaps
,
4812 PHM_PlatformCaps_DisableMclkSwitchingForFrameLock
);
4814 disable_mclk_switching
= (1 < info
.display_count
) ||
4815 disable_mclk_switching_for_frame_lock
;
4817 sclk
= tonga_ps
->performance_levels
[0].engine_clock
;
4818 mclk
= tonga_ps
->performance_levels
[0].memory_clock
;
4820 if (disable_mclk_switching
)
4821 mclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
- 1].memory_clock
;
4823 if (sclk
< minimum_clocks
.engineClock
)
4824 sclk
= (minimum_clocks
.engineClock
> max_limits
->sclk
) ? max_limits
->sclk
: minimum_clocks
.engineClock
;
4826 if (mclk
< minimum_clocks
.memoryClock
)
4827 mclk
= (minimum_clocks
.memoryClock
> max_limits
->mclk
) ? max_limits
->mclk
: minimum_clocks
.memoryClock
;
4829 tonga_ps
->performance_levels
[0].engine_clock
= sclk
;
4830 tonga_ps
->performance_levels
[0].memory_clock
= mclk
;
4832 tonga_ps
->performance_levels
[1].engine_clock
=
4833 (tonga_ps
->performance_levels
[1].engine_clock
>= tonga_ps
->performance_levels
[0].engine_clock
) ?
4834 tonga_ps
->performance_levels
[1].engine_clock
:
4835 tonga_ps
->performance_levels
[0].engine_clock
;
4837 if (disable_mclk_switching
) {
4838 if (mclk
< tonga_ps
->performance_levels
[1].memory_clock
)
4839 mclk
= tonga_ps
->performance_levels
[1].memory_clock
;
4841 tonga_ps
->performance_levels
[0].memory_clock
= mclk
;
4842 tonga_ps
->performance_levels
[1].memory_clock
= mclk
;
4844 if (tonga_ps
->performance_levels
[1].memory_clock
< tonga_ps
->performance_levels
[0].memory_clock
)
4845 tonga_ps
->performance_levels
[1].memory_clock
= tonga_ps
->performance_levels
[0].memory_clock
;
4848 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
)) {
4849 for (i
=0; i
< tonga_ps
->performance_level_count
; i
++) {
4850 tonga_ps
->performance_levels
[i
].engine_clock
= stable_pstate_sclk
;
4851 tonga_ps
->performance_levels
[i
].memory_clock
= stable_pstate_mclk
;
4852 tonga_ps
->performance_levels
[i
].pcie_gen
= data
->pcie_gen_performance
.max
;
4853 tonga_ps
->performance_levels
[i
].pcie_lane
= data
->pcie_gen_performance
.max
;
4860 int tonga_get_power_state_size(struct pp_hwmgr
*hwmgr
)
4862 return sizeof(struct tonga_power_state
);
4865 static int tonga_dpm_get_mclk(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].memory_clock
;
4883 return tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].memory_clock
;
4886 static int tonga_dpm_get_sclk(struct pp_hwmgr
*hwmgr
, bool low
)
4888 struct pp_power_state
*ps
;
4889 struct tonga_power_state
*tonga_ps
;
4894 ps
= hwmgr
->request_ps
;
4899 tonga_ps
= cast_phw_tonga_power_state(&ps
->hardware
);
4902 return tonga_ps
->performance_levels
[0].engine_clock
;
4904 return tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].engine_clock
;
4907 static uint16_t tonga_get_current_pcie_speed(
4908 struct pp_hwmgr
*hwmgr
)
4910 uint32_t speed_cntl
= 0;
4912 speed_cntl
= cgs_read_ind_register(hwmgr
->device
,
4914 ixPCIE_LC_SPEED_CNTL
);
4915 return((uint16_t)PHM_GET_FIELD(speed_cntl
,
4916 PCIE_LC_SPEED_CNTL
, LC_CURRENT_DATA_RATE
));
4919 static int tonga_get_current_pcie_lane_number(
4920 struct pp_hwmgr
*hwmgr
)
4922 uint32_t link_width
;
4924 link_width
= PHM_READ_INDIRECT_FIELD(hwmgr
->device
,
4926 PCIE_LC_LINK_WIDTH_CNTL
,
4929 PP_ASSERT_WITH_CODE((7 >= link_width
),
4930 "Invalid PCIe lane width!", return 0);
4932 return decode_pcie_lane_width(link_width
);
4935 static int tonga_dpm_patch_boot_state(struct pp_hwmgr
*hwmgr
,
4936 struct pp_hw_power_state
*hw_ps
)
4938 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4939 struct tonga_power_state
*ps
= (struct tonga_power_state
*)hw_ps
;
4940 ATOM_FIRMWARE_INFO_V2_2
*fw_info
;
4943 int index
= GetIndexIntoMasterTable(DATA
, FirmwareInfo
);
4945 /* First retrieve the Boot clocks and VDDC from the firmware info table.
4946 * We assume here that fw_info is unchanged if this call fails.
4948 fw_info
= (ATOM_FIRMWARE_INFO_V2_2
*)cgs_atom_get_data_table(
4949 hwmgr
->device
, index
,
4950 &size
, &frev
, &crev
);
4952 /* During a test, there is no firmware info table. */
4955 /* Patch the state. */
4956 data
->vbios_boot_state
.sclk_bootup_value
= le32_to_cpu(fw_info
->ulDefaultEngineClock
);
4957 data
->vbios_boot_state
.mclk_bootup_value
= le32_to_cpu(fw_info
->ulDefaultMemoryClock
);
4958 data
->vbios_boot_state
.mvdd_bootup_value
= le16_to_cpu(fw_info
->usBootUpMVDDCVoltage
);
4959 data
->vbios_boot_state
.vddc_bootup_value
= le16_to_cpu(fw_info
->usBootUpVDDCVoltage
);
4960 data
->vbios_boot_state
.vddci_bootup_value
= le16_to_cpu(fw_info
->usBootUpVDDCIVoltage
);
4961 data
->vbios_boot_state
.pcie_gen_bootup_value
= tonga_get_current_pcie_speed(hwmgr
);
4962 data
->vbios_boot_state
.pcie_lane_bootup_value
=
4963 (uint16_t)tonga_get_current_pcie_lane_number(hwmgr
);
4965 /* set boot power state */
4966 ps
->performance_levels
[0].memory_clock
= data
->vbios_boot_state
.mclk_bootup_value
;
4967 ps
->performance_levels
[0].engine_clock
= data
->vbios_boot_state
.sclk_bootup_value
;
4968 ps
->performance_levels
[0].pcie_gen
= data
->vbios_boot_state
.pcie_gen_bootup_value
;
4969 ps
->performance_levels
[0].pcie_lane
= data
->vbios_boot_state
.pcie_lane_bootup_value
;
4974 static int tonga_get_pp_table_entry_callback_func(struct pp_hwmgr
*hwmgr
,
4975 void *state
, struct pp_power_state
*power_state
,
4976 void *pp_table
, uint32_t classification_flag
)
4978 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4980 struct tonga_power_state
*tonga_ps
=
4981 (struct tonga_power_state
*)(&(power_state
->hardware
));
4983 struct tonga_performance_level
*performance_level
;
4985 ATOM_Tonga_State
*state_entry
= (ATOM_Tonga_State
*)state
;
4987 ATOM_Tonga_POWERPLAYTABLE
*powerplay_table
=
4988 (ATOM_Tonga_POWERPLAYTABLE
*)pp_table
;
4990 ATOM_Tonga_SCLK_Dependency_Table
*sclk_dep_table
=
4991 (ATOM_Tonga_SCLK_Dependency_Table
*)
4992 (((unsigned long)powerplay_table
) +
4993 le16_to_cpu(powerplay_table
->usSclkDependencyTableOffset
));
4995 ATOM_Tonga_MCLK_Dependency_Table
*mclk_dep_table
=
4996 (ATOM_Tonga_MCLK_Dependency_Table
*)
4997 (((unsigned long)powerplay_table
) +
4998 le16_to_cpu(powerplay_table
->usMclkDependencyTableOffset
));
5000 /* The following fields are not initialized here: id orderedList allStatesList */
5001 power_state
->classification
.ui_label
=
5002 (le16_to_cpu(state_entry
->usClassification
) &
5003 ATOM_PPLIB_CLASSIFICATION_UI_MASK
) >>
5004 ATOM_PPLIB_CLASSIFICATION_UI_SHIFT
;
5005 power_state
->classification
.flags
= classification_flag
;
5006 /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
5008 power_state
->classification
.temporary_state
= false;
5009 power_state
->classification
.to_be_deleted
= false;
5011 power_state
->validation
.disallowOnDC
=
5012 (0 != (le32_to_cpu(state_entry
->ulCapsAndSettings
) & ATOM_Tonga_DISALLOW_ON_DC
));
5014 power_state
->pcie
.lanes
= 0;
5016 power_state
->display
.disableFrameModulation
= false;
5017 power_state
->display
.limitRefreshrate
= false;
5018 power_state
->display
.enableVariBright
=
5019 (0 != (le32_to_cpu(state_entry
->ulCapsAndSettings
) & ATOM_Tonga_ENABLE_VARIBRIGHT
));
5021 power_state
->validation
.supportedPowerLevels
= 0;
5022 power_state
->uvd_clocks
.VCLK
= 0;
5023 power_state
->uvd_clocks
.DCLK
= 0;
5024 power_state
->temperatures
.min
= 0;
5025 power_state
->temperatures
.max
= 0;
5027 performance_level
= &(tonga_ps
->performance_levels
5028 [tonga_ps
->performance_level_count
++]);
5030 PP_ASSERT_WITH_CODE(
5031 (tonga_ps
->performance_level_count
< SMU72_MAX_LEVELS_GRAPHICS
),
5032 "Performance levels exceeds SMC limit!",
5035 PP_ASSERT_WITH_CODE(
5036 (tonga_ps
->performance_level_count
<=
5037 hwmgr
->platform_descriptor
.hardwareActivityPerformanceLevels
),
5038 "Performance levels exceeds Driver limit!",
5041 /* Performance levels are arranged from low to high. */
5042 performance_level
->memory_clock
=
5043 le32_to_cpu(mclk_dep_table
->entries
[state_entry
->ucMemoryClockIndexLow
].ulMclk
);
5045 performance_level
->engine_clock
=
5046 le32_to_cpu(sclk_dep_table
->entries
[state_entry
->ucEngineClockIndexLow
].ulSclk
);
5048 performance_level
->pcie_gen
= get_pcie_gen_support(
5050 state_entry
->ucPCIEGenLow
);
5052 performance_level
->pcie_lane
= get_pcie_lane_support(
5053 data
->pcie_lane_cap
,
5054 state_entry
->ucPCIELaneHigh
);
5057 &(tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
++]);
5059 performance_level
->memory_clock
=
5060 le32_to_cpu(mclk_dep_table
->entries
[state_entry
->ucMemoryClockIndexHigh
].ulMclk
);
5062 performance_level
->engine_clock
=
5063 le32_to_cpu(sclk_dep_table
->entries
[state_entry
->ucEngineClockIndexHigh
].ulSclk
);
5065 performance_level
->pcie_gen
= get_pcie_gen_support(
5067 state_entry
->ucPCIEGenHigh
);
5069 performance_level
->pcie_lane
= get_pcie_lane_support(
5070 data
->pcie_lane_cap
,
5071 state_entry
->ucPCIELaneHigh
);
5076 static int tonga_get_pp_table_entry(struct pp_hwmgr
*hwmgr
,
5077 unsigned long entry_index
, struct pp_power_state
*ps
)
5080 struct tonga_power_state
*tonga_ps
;
5081 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5083 struct phm_ppt_v1_information
*table_info
=
5084 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
5086 struct phm_ppt_v1_clock_voltage_dependency_table
*dep_mclk_table
=
5087 table_info
->vdd_dep_on_mclk
;
5089 ps
->hardware
.magic
= PhwTonga_Magic
;
5091 tonga_ps
= cast_phw_tonga_power_state(&(ps
->hardware
));
5093 result
= tonga_get_powerplay_table_entry(hwmgr
, entry_index
, ps
,
5094 tonga_get_pp_table_entry_callback_func
);
5096 /* This is the earliest time we have all the dependency table and the VBIOS boot state
5097 * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
5098 * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
5100 if (dep_mclk_table
!= NULL
&& dep_mclk_table
->count
== 1) {
5101 if (dep_mclk_table
->entries
[0].clk
!=
5102 data
->vbios_boot_state
.mclk_bootup_value
)
5103 printk(KERN_ERR
"Single MCLK entry VDDCI/MCLK dependency table "
5104 "does not match VBIOS boot MCLK level");
5105 if (dep_mclk_table
->entries
[0].vddci
!=
5106 data
->vbios_boot_state
.vddci_bootup_value
)
5107 printk(KERN_ERR
"Single VDDCI entry VDDCI/MCLK dependency table "
5108 "does not match VBIOS boot VDDCI level");
5111 /* set DC compatible flag if this state supports DC */
5112 if (!ps
->validation
.disallowOnDC
)
5113 tonga_ps
->dc_compatible
= true;
5115 if (ps
->classification
.flags
& PP_StateClassificationFlag_ACPI
)
5116 data
->acpi_pcie_gen
= tonga_ps
->performance_levels
[0].pcie_gen
;
5117 else if (ps
->classification
.flags
& PP_StateClassificationFlag_Boot
) {
5118 if (data
->bacos
.best_match
== 0xffff) {
5119 /* For V.I. use boot state as base BACO state */
5120 data
->bacos
.best_match
= PP_StateClassificationFlag_Boot
;
5121 data
->bacos
.performance_level
= tonga_ps
->performance_levels
[0];
5125 tonga_ps
->uvd_clocks
.VCLK
= ps
->uvd_clocks
.VCLK
;
5126 tonga_ps
->uvd_clocks
.DCLK
= ps
->uvd_clocks
.DCLK
;
5131 switch (ps
->classification
.ui_label
) {
5132 case PP_StateUILabel_Performance
:
5133 data
->use_pcie_performance_levels
= true;
5135 for (i
= 0; i
< tonga_ps
->performance_level_count
; i
++) {
5136 if (data
->pcie_gen_performance
.max
<
5137 tonga_ps
->performance_levels
[i
].pcie_gen
)
5138 data
->pcie_gen_performance
.max
=
5139 tonga_ps
->performance_levels
[i
].pcie_gen
;
5141 if (data
->pcie_gen_performance
.min
>
5142 tonga_ps
->performance_levels
[i
].pcie_gen
)
5143 data
->pcie_gen_performance
.min
=
5144 tonga_ps
->performance_levels
[i
].pcie_gen
;
5146 if (data
->pcie_lane_performance
.max
<
5147 tonga_ps
->performance_levels
[i
].pcie_lane
)
5148 data
->pcie_lane_performance
.max
=
5149 tonga_ps
->performance_levels
[i
].pcie_lane
;
5151 if (data
->pcie_lane_performance
.min
>
5152 tonga_ps
->performance_levels
[i
].pcie_lane
)
5153 data
->pcie_lane_performance
.min
=
5154 tonga_ps
->performance_levels
[i
].pcie_lane
;
5157 case PP_StateUILabel_Battery
:
5158 data
->use_pcie_power_saving_levels
= true;
5160 for (i
= 0; i
< tonga_ps
->performance_level_count
; i
++) {
5161 if (data
->pcie_gen_power_saving
.max
<
5162 tonga_ps
->performance_levels
[i
].pcie_gen
)
5163 data
->pcie_gen_power_saving
.max
=
5164 tonga_ps
->performance_levels
[i
].pcie_gen
;
5166 if (data
->pcie_gen_power_saving
.min
>
5167 tonga_ps
->performance_levels
[i
].pcie_gen
)
5168 data
->pcie_gen_power_saving
.min
=
5169 tonga_ps
->performance_levels
[i
].pcie_gen
;
5171 if (data
->pcie_lane_power_saving
.max
<
5172 tonga_ps
->performance_levels
[i
].pcie_lane
)
5173 data
->pcie_lane_power_saving
.max
=
5174 tonga_ps
->performance_levels
[i
].pcie_lane
;
5176 if (data
->pcie_lane_power_saving
.min
>
5177 tonga_ps
->performance_levels
[i
].pcie_lane
)
5178 data
->pcie_lane_power_saving
.min
=
5179 tonga_ps
->performance_levels
[i
].pcie_lane
;
5190 tonga_print_current_perforce_level(struct pp_hwmgr
*hwmgr
, struct seq_file
*m
)
5192 uint32_t sclk
, mclk
, activity_percent
;
5194 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5196 smum_send_msg_to_smc(hwmgr
->smumgr
, (PPSMC_Msg
)(PPSMC_MSG_API_GetSclkFrequency
));
5198 sclk
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5200 smum_send_msg_to_smc(hwmgr
->smumgr
, (PPSMC_Msg
)(PPSMC_MSG_API_GetMclkFrequency
));
5202 mclk
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5203 seq_printf(m
, "\n [ mclk ]: %u MHz\n\n [ sclk ]: %u MHz\n", mclk
/100, sclk
/100);
5205 offset
= data
->soft_regs_start
+ offsetof(SMU72_SoftRegisters
, AverageGraphicsActivity
);
5206 activity_percent
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, offset
);
5207 activity_percent
+= 0x80;
5208 activity_percent
>>= 8;
5210 seq_printf(m
, "\n [GPU load]: %u%%\n\n", activity_percent
> 100 ? 100 : activity_percent
);
5212 seq_printf(m
, "uvd %sabled\n", data
->uvd_power_gated
? "dis" : "en");
5214 seq_printf(m
, "vce %sabled\n", data
->vce_power_gated
? "dis" : "en");
5217 static int tonga_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr
*hwmgr
, const void *input
)
5219 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5220 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5221 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5222 struct tonga_single_dpm_table
*psclk_table
= &(data
->dpm_table
.sclk_table
);
5223 uint32_t sclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].engine_clock
;
5224 struct tonga_single_dpm_table
*pmclk_table
= &(data
->dpm_table
.mclk_table
);
5225 uint32_t mclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].memory_clock
;
5226 struct PP_Clocks min_clocks
= {0};
5228 struct cgs_display_info info
= {0};
5230 data
->need_update_smu7_dpm_table
= 0;
5232 for (i
= 0; i
< psclk_table
->count
; i
++) {
5233 if (sclk
== psclk_table
->dpm_levels
[i
].value
)
5237 if (i
>= psclk_table
->count
)
5238 data
->need_update_smu7_dpm_table
|= DPMTABLE_OD_UPDATE_SCLK
;
5240 /* TODO: Check SCLK in DAL's minimum clocks in case DeepSleep divider update is required.*/
5241 if(data
->display_timing
.min_clock_insr
!= min_clocks
.engineClockInSR
)
5242 data
->need_update_smu7_dpm_table
|= DPMTABLE_UPDATE_SCLK
;
5245 for (i
=0; i
< pmclk_table
->count
; i
++) {
5246 if (mclk
== pmclk_table
->dpm_levels
[i
].value
)
5250 if (i
>= pmclk_table
->count
)
5251 data
->need_update_smu7_dpm_table
|= DPMTABLE_OD_UPDATE_MCLK
;
5253 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5255 if (data
->display_timing
.num_existing_displays
!= info
.display_count
)
5256 data
->need_update_smu7_dpm_table
|= DPMTABLE_UPDATE_MCLK
;
5261 static uint16_t tonga_get_maximum_link_speed(struct pp_hwmgr
*hwmgr
, const struct tonga_power_state
*hw_ps
)
5264 uint32_t sclk
, max_sclk
= 0;
5265 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5266 struct tonga_dpm_table
*pdpm_table
= &data
->dpm_table
;
5268 for (i
= 0; i
< hw_ps
->performance_level_count
; i
++) {
5269 sclk
= hw_ps
->performance_levels
[i
].engine_clock
;
5270 if (max_sclk
< sclk
)
5274 for (i
= 0; i
< pdpm_table
->sclk_table
.count
; i
++) {
5275 if (pdpm_table
->sclk_table
.dpm_levels
[i
].value
== max_sclk
)
5276 return (uint16_t) ((i
>= pdpm_table
->pcie_speed_table
.count
) ?
5277 pdpm_table
->pcie_speed_table
.dpm_levels
[pdpm_table
->pcie_speed_table
.count
-1].value
:
5278 pdpm_table
->pcie_speed_table
.dpm_levels
[i
].value
);
5284 static int tonga_request_link_speed_change_before_state_change(struct pp_hwmgr
*hwmgr
, const void *input
)
5286 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5287 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5288 const struct tonga_power_state
*tonga_nps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5289 const struct tonga_power_state
*tonga_cps
= cast_const_phw_tonga_power_state(states
->pcurrent_state
);
5291 uint16_t target_link_speed
= tonga_get_maximum_link_speed(hwmgr
, tonga_nps
);
5292 uint16_t current_link_speed
;
5294 if (data
->force_pcie_gen
== PP_PCIEGenInvalid
)
5295 current_link_speed
= tonga_get_maximum_link_speed(hwmgr
, tonga_cps
);
5297 current_link_speed
= data
->force_pcie_gen
;
5299 data
->force_pcie_gen
= PP_PCIEGenInvalid
;
5300 data
->pspp_notify_required
= false;
5301 if (target_link_speed
> current_link_speed
) {
5302 switch(target_link_speed
) {
5304 if (0 == acpi_pcie_perf_request(hwmgr
->device
, PCIE_PERF_REQ_GEN3
, false))
5306 data
->force_pcie_gen
= PP_PCIEGen2
;
5307 if (current_link_speed
== PP_PCIEGen2
)
5310 if (0 == acpi_pcie_perf_request(hwmgr
->device
, PCIE_PERF_REQ_GEN2
, false))
5313 data
->force_pcie_gen
= tonga_get_current_pcie_speed(hwmgr
);
5317 if (target_link_speed
< current_link_speed
)
5318 data
->pspp_notify_required
= true;
5324 static int tonga_freeze_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
5326 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5328 if (0 == data
->need_update_smu7_dpm_table
)
5331 if ((0 == data
->sclk_dpm_key_disabled
) &&
5332 (data
->need_update_smu7_dpm_table
&
5333 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
))) {
5334 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
5335 "Trying to freeze SCLK DPM when DPM is disabled",
5337 PP_ASSERT_WITH_CODE(
5338 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5339 PPSMC_MSG_SCLKDPM_FreezeLevel
),
5340 "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
5344 if ((0 == data
->mclk_dpm_key_disabled
) &&
5345 (data
->need_update_smu7_dpm_table
&
5346 DPMTABLE_OD_UPDATE_MCLK
)) {
5347 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
5348 "Trying to freeze MCLK DPM when DPM is disabled",
5350 PP_ASSERT_WITH_CODE(
5351 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5352 PPSMC_MSG_MCLKDPM_FreezeLevel
),
5353 "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
5360 static int tonga_populate_and_upload_sclk_mclk_dpm_levels(struct pp_hwmgr
*hwmgr
, const void *input
)
5364 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5365 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5366 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5367 uint32_t sclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].engine_clock
;
5368 uint32_t mclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].memory_clock
;
5369 struct tonga_dpm_table
*pdpm_table
= &data
->dpm_table
;
5371 struct tonga_dpm_table
*pgolden_dpm_table
= &data
->golden_dpm_table
;
5372 uint32_t dpm_count
, clock_percent
;
5375 if (0 == data
->need_update_smu7_dpm_table
)
5378 if (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_SCLK
) {
5379 pdpm_table
->sclk_table
.dpm_levels
[pdpm_table
->sclk_table
.count
-1].value
= sclk
;
5381 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinACSupport
) ||
5382 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinDCSupport
)) {
5383 /* Need to do calculation based on the golden DPM table
5384 * as the Heatmap GPU Clock axis is also based on the default values
5386 PP_ASSERT_WITH_CODE(
5387 (pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
!= 0),
5390 dpm_count
= pdpm_table
->sclk_table
.count
< 2 ? 0 : pdpm_table
->sclk_table
.count
-2;
5391 for (i
= dpm_count
; i
> 1; i
--) {
5392 if (sclk
> pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
) {
5393 clock_percent
= ((sclk
- pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
)*100) /
5394 pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
;
5396 pdpm_table
->sclk_table
.dpm_levels
[i
].value
=
5397 pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
+
5398 (pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5400 } else if (pgolden_dpm_table
->sclk_table
.dpm_levels
[pdpm_table
->sclk_table
.count
-1].value
> sclk
) {
5401 clock_percent
= ((pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
- sclk
)*100) /
5402 pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
;
5404 pdpm_table
->sclk_table
.dpm_levels
[i
].value
=
5405 pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
-
5406 (pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5408 pdpm_table
->sclk_table
.dpm_levels
[i
].value
=
5409 pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
;
5414 if (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
) {
5415 pdpm_table
->mclk_table
.dpm_levels
[pdpm_table
->mclk_table
.count
-1].value
= mclk
;
5417 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinACSupport
) ||
5418 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinDCSupport
)) {
5420 PP_ASSERT_WITH_CODE(
5421 (pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
!= 0),
5424 dpm_count
= pdpm_table
->mclk_table
.count
< 2? 0 : pdpm_table
->mclk_table
.count
-2;
5425 for (i
= dpm_count
; i
> 1; i
--) {
5426 if (mclk
> pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
) {
5427 clock_percent
= ((mclk
- pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
)*100) /
5428 pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
;
5430 pdpm_table
->mclk_table
.dpm_levels
[i
].value
=
5431 pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
+
5432 (pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5434 } else if (pgolden_dpm_table
->mclk_table
.dpm_levels
[pdpm_table
->mclk_table
.count
-1].value
> mclk
) {
5435 clock_percent
= ((pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
- mclk
)*100) /
5436 pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
;
5438 pdpm_table
->mclk_table
.dpm_levels
[i
].value
=
5439 pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
-
5440 (pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5442 pdpm_table
->mclk_table
.dpm_levels
[i
].value
= pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
;
5447 if (data
->need_update_smu7_dpm_table
& (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
)) {
5448 result
= tonga_populate_all_graphic_levels(hwmgr
);
5449 PP_ASSERT_WITH_CODE((0 == result
),
5450 "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
5454 if (data
->need_update_smu7_dpm_table
& (DPMTABLE_OD_UPDATE_MCLK
+ DPMTABLE_UPDATE_MCLK
)) {
5455 /*populate MCLK dpm table to SMU7 */
5456 result
= tonga_populate_all_memory_levels(hwmgr
);
5457 PP_ASSERT_WITH_CODE((0 == result
),
5458 "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
5465 static int tonga_trim_single_dpm_states(struct pp_hwmgr
*hwmgr
,
5466 struct tonga_single_dpm_table
* pdpm_table
,
5467 uint32_t low_limit
, uint32_t high_limit
)
5471 for (i
= 0; i
< pdpm_table
->count
; i
++) {
5472 if ((pdpm_table
->dpm_levels
[i
].value
< low_limit
) ||
5473 (pdpm_table
->dpm_levels
[i
].value
> high_limit
))
5474 pdpm_table
->dpm_levels
[i
].enabled
= false;
5476 pdpm_table
->dpm_levels
[i
].enabled
= true;
5481 static int tonga_trim_dpm_states(struct pp_hwmgr
*hwmgr
, const struct tonga_power_state
*hw_state
)
5483 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5484 uint32_t high_limit_count
;
5486 PP_ASSERT_WITH_CODE((hw_state
->performance_level_count
>= 1),
5487 "power state did not have any performance level",
5490 high_limit_count
= (1 == hw_state
->performance_level_count
) ? 0: 1;
5492 tonga_trim_single_dpm_states(hwmgr
,
5493 &(data
->dpm_table
.sclk_table
),
5494 hw_state
->performance_levels
[0].engine_clock
,
5495 hw_state
->performance_levels
[high_limit_count
].engine_clock
);
5497 tonga_trim_single_dpm_states(hwmgr
,
5498 &(data
->dpm_table
.mclk_table
),
5499 hw_state
->performance_levels
[0].memory_clock
,
5500 hw_state
->performance_levels
[high_limit_count
].memory_clock
);
5505 static int tonga_generate_dpm_level_enable_mask(struct pp_hwmgr
*hwmgr
, const void *input
)
5508 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5509 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5510 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5512 result
= tonga_trim_dpm_states(hwmgr
, tonga_ps
);
5516 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&data
->dpm_table
.sclk_table
);
5517 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&data
->dpm_table
.mclk_table
);
5518 data
->last_mclk_dpm_enable_mask
= data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
;
5519 if (data
->uvd_enabled
)
5520 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
&= 0xFFFFFFFE;
5522 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&data
->dpm_table
.pcie_speed_table
);
5527 int tonga_enable_disable_vce_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
5529 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
5530 (PPSMC_Msg
)PPSMC_MSG_VCEDPM_Enable
:
5531 (PPSMC_Msg
)PPSMC_MSG_VCEDPM_Disable
);
5534 int tonga_enable_disable_uvd_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
5536 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
5537 (PPSMC_Msg
)PPSMC_MSG_UVDDPM_Enable
:
5538 (PPSMC_Msg
)PPSMC_MSG_UVDDPM_Disable
);
5541 int tonga_update_uvd_dpm(struct pp_hwmgr
*hwmgr
, bool bgate
)
5543 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5544 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
5545 struct phm_ppt_v1_information
*ptable_information
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
5548 data
->smc_state_table
.UvdBootLevel
= (uint8_t) (ptable_information
->mm_dep_table
->count
- 1);
5549 mm_boot_level_offset
= data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
, UvdBootLevel
);
5550 mm_boot_level_offset
/= 4;
5551 mm_boot_level_offset
*= 4;
5552 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
);
5553 mm_boot_level_value
&= 0x00FFFFFF;
5554 mm_boot_level_value
|= data
->smc_state_table
.UvdBootLevel
<< 24;
5555 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
5557 if (!phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_UVDDPM
) ||
5558 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
))
5559 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5560 PPSMC_MSG_UVDDPM_SetEnabledMask
,
5561 (uint32_t)(1 << data
->smc_state_table
.UvdBootLevel
));
5564 return tonga_enable_disable_uvd_dpm(hwmgr
, !bgate
);
5567 int tonga_update_vce_dpm(struct pp_hwmgr
*hwmgr
, const void *input
)
5569 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5570 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5571 const struct tonga_power_state
*tonga_nps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5572 const struct tonga_power_state
*tonga_cps
= cast_const_phw_tonga_power_state(states
->pcurrent_state
);
5574 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
5575 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
5577 if (tonga_nps
->vce_clocks
.EVCLK
> 0 && (tonga_cps
== NULL
|| tonga_cps
->vce_clocks
.EVCLK
== 0)) {
5578 data
->smc_state_table
.VceBootLevel
= (uint8_t) (pptable_info
->mm_dep_table
->count
- 1);
5580 mm_boot_level_offset
= data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
, VceBootLevel
);
5581 mm_boot_level_offset
/= 4;
5582 mm_boot_level_offset
*= 4;
5583 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
);
5584 mm_boot_level_value
&= 0xFF00FFFF;
5585 mm_boot_level_value
|= data
->smc_state_table
.VceBootLevel
<< 16;
5586 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
5588 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
))
5589 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5590 PPSMC_MSG_VCEDPM_SetEnabledMask
,
5591 (uint32_t)(1 << data
->smc_state_table
.VceBootLevel
));
5593 tonga_enable_disable_vce_dpm(hwmgr
, true);
5594 } else if (tonga_nps
->vce_clocks
.EVCLK
== 0 && tonga_cps
!= NULL
&& tonga_cps
->vce_clocks
.EVCLK
> 0)
5595 tonga_enable_disable_vce_dpm(hwmgr
, false);
5600 static int tonga_update_and_upload_mc_reg_table(struct pp_hwmgr
*hwmgr
)
5602 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5607 if (0 == (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
))
5611 memset(&data
->mc_reg_table
, 0, sizeof(SMU72_Discrete_MCRegisters
));
5613 result
= tonga_convert_mc_reg_table_to_smc(hwmgr
, &(data
->mc_reg_table
));
5619 address
= data
->mc_reg_table_start
+ (uint32_t)offsetof(SMU72_Discrete_MCRegisters
, data
[0]);
5621 return tonga_copy_bytes_to_smc(hwmgr
->smumgr
, address
,
5622 (uint8_t *)&data
->mc_reg_table
.data
[0],
5623 sizeof(SMU72_Discrete_MCRegisterSet
) * data
->dpm_table
.mclk_table
.count
,
5627 static int tonga_program_memory_timing_parameters_conditionally(struct pp_hwmgr
*hwmgr
)
5629 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5631 if (data
->need_update_smu7_dpm_table
&
5632 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_OD_UPDATE_MCLK
))
5633 return tonga_program_memory_timing_parameters(hwmgr
);
5638 static int tonga_unfreeze_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
5640 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5642 if (0 == data
->need_update_smu7_dpm_table
)
5645 if ((0 == data
->sclk_dpm_key_disabled
) &&
5646 (data
->need_update_smu7_dpm_table
&
5647 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
))) {
5649 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
5650 "Trying to Unfreeze SCLK DPM when DPM is disabled",
5652 PP_ASSERT_WITH_CODE(
5653 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5654 PPSMC_MSG_SCLKDPM_UnfreezeLevel
),
5655 "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
5659 if ((0 == data
->mclk_dpm_key_disabled
) &&
5660 (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
)) {
5662 PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr
),
5663 "Trying to Unfreeze MCLK DPM when DPM is disabled",
5665 PP_ASSERT_WITH_CODE(
5666 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5667 PPSMC_MSG_SCLKDPM_UnfreezeLevel
),
5668 "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
5672 data
->need_update_smu7_dpm_table
= 0;
5677 static int tonga_notify_link_speed_change_after_state_change(struct pp_hwmgr
*hwmgr
, const void *input
)
5679 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5680 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5681 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5682 uint16_t target_link_speed
= tonga_get_maximum_link_speed(hwmgr
, tonga_ps
);
5685 if (data
->pspp_notify_required
||
5686 data
->pcie_performance_request
) {
5687 if (target_link_speed
== PP_PCIEGen3
)
5688 request
= PCIE_PERF_REQ_GEN3
;
5689 else if (target_link_speed
== PP_PCIEGen2
)
5690 request
= PCIE_PERF_REQ_GEN2
;
5692 request
= PCIE_PERF_REQ_GEN1
;
5694 if(request
== PCIE_PERF_REQ_GEN1
&& tonga_get_current_pcie_speed(hwmgr
) > 0) {
5695 data
->pcie_performance_request
= false;
5699 if (0 != acpi_pcie_perf_request(hwmgr
->device
, request
, false)) {
5700 if (PP_PCIEGen2
== target_link_speed
)
5701 printk("PSPP request to switch to Gen2 from Gen3 Failed!");
5703 printk("PSPP request to switch to Gen1 from Gen2 Failed!");
5707 data
->pcie_performance_request
= false;
5711 static int tonga_set_power_state_tasks(struct pp_hwmgr
*hwmgr
, const void *input
)
5713 int tmp_result
, result
= 0;
5715 tmp_result
= tonga_find_dpm_states_clocks_in_dpm_table(hwmgr
, input
);
5716 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to find DPM states clocks in DPM table!", result
= tmp_result
);
5718 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_PCIEPerformanceRequest
)) {
5719 tmp_result
= tonga_request_link_speed_change_before_state_change(hwmgr
, input
);
5720 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to request link speed change before state change!", result
= tmp_result
);
5723 tmp_result
= tonga_freeze_sclk_mclk_dpm(hwmgr
);
5724 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to freeze SCLK MCLK DPM!", result
= tmp_result
);
5726 tmp_result
= tonga_populate_and_upload_sclk_mclk_dpm_levels(hwmgr
, input
);
5727 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to populate and upload SCLK MCLK DPM levels!", result
= tmp_result
);
5729 tmp_result
= tonga_generate_dpm_level_enable_mask(hwmgr
, input
);
5730 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to generate DPM level enabled mask!", result
= tmp_result
);
5732 tmp_result
= tonga_update_vce_dpm(hwmgr
, input
);
5733 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to update VCE DPM!", result
= tmp_result
);
5735 tmp_result
= tonga_update_sclk_threshold(hwmgr
);
5736 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to update SCLK threshold!", result
= tmp_result
);
5738 tmp_result
= tonga_update_and_upload_mc_reg_table(hwmgr
);
5739 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to upload MC reg table!", result
= tmp_result
);
5741 tmp_result
= tonga_program_memory_timing_parameters_conditionally(hwmgr
);
5742 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to program memory timing parameters!", result
= tmp_result
);
5744 tmp_result
= tonga_unfreeze_sclk_mclk_dpm(hwmgr
);
5745 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to unfreeze SCLK MCLK DPM!", result
= tmp_result
);
5747 tmp_result
= tonga_upload_dpm_level_enable_mask(hwmgr
);
5748 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to upload DPM level enabled mask!", result
= tmp_result
);
5750 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_PCIEPerformanceRequest
)) {
5751 tmp_result
= tonga_notify_link_speed_change_after_state_change(hwmgr
, input
);
5752 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to notify link speed change after state change!", result
= tmp_result
);
5759 * Set maximum target operating fan output PWM
5761 * @param pHwMgr: the address of the powerplay hardware manager.
5762 * @param usMaxFanPwm: max operating fan PWM in percents
5763 * @return The response that came from the SMC.
5765 static int tonga_set_max_fan_pwm_output(struct pp_hwmgr
*hwmgr
, uint16_t us_max_fan_pwm
)
5767 hwmgr
->thermal_controller
.advanceFanControlParameters
.usMaxFanPWM
= us_max_fan_pwm
;
5769 if (phm_is_hw_access_blocked(hwmgr
))
5772 return (0 == smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
, PPSMC_MSG_SetFanPwmMax
, us_max_fan_pwm
) ? 0 : -1);
5775 int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr
*hwmgr
)
5777 uint32_t num_active_displays
= 0;
5778 struct cgs_display_info info
= {0};
5779 info
.mode_info
= NULL
;
5781 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5783 num_active_displays
= info
.display_count
;
5785 if (num_active_displays
> 1) /* to do && (pHwMgr->pPECI->displayConfiguration.bMultiMonitorInSync != TRUE)) */
5786 tonga_notify_smc_display_change(hwmgr
, false);
5788 tonga_notify_smc_display_change(hwmgr
, true);
5794 * Programs the display gap
5796 * @param hwmgr the address of the powerplay hardware manager.
5799 int tonga_program_display_gap(struct pp_hwmgr
*hwmgr
)
5801 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5802 uint32_t num_active_displays
= 0;
5803 uint32_t display_gap
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
);
5804 uint32_t display_gap2
;
5805 uint32_t pre_vbi_time_in_us
;
5806 uint32_t frame_time_in_us
;
5808 uint32_t refresh_rate
= 0;
5809 struct cgs_display_info info
= {0};
5810 struct cgs_mode_info mode_info
;
5812 info
.mode_info
= &mode_info
;
5814 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5815 num_active_displays
= info
.display_count
;
5817 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
);
5818 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
, display_gap
);
5820 ref_clock
= mode_info
.ref_clock
;
5821 refresh_rate
= mode_info
.refresh_rate
;
5823 if(0 == refresh_rate
)
5826 frame_time_in_us
= 1000000 / refresh_rate
;
5828 pre_vbi_time_in_us
= frame_time_in_us
- 200 - mode_info
.vblank_time_us
;
5829 display_gap2
= pre_vbi_time_in_us
* (ref_clock
/ 100);
5831 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL2
, display_gap2
);
5833 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, data
->soft_regs_start
+ offsetof(SMU72_SoftRegisters
, PreVBlankGap
), 0x64);
5835 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
));
5837 if (num_active_displays
== 1)
5838 tonga_notify_smc_display_change(hwmgr
, true);
5843 int tonga_display_configuration_changed_task(struct pp_hwmgr
*hwmgr
)
5846 tonga_program_display_gap(hwmgr
);
5848 /* to do PhwTonga_CacUpdateDisplayConfiguration(pHwMgr); */
5853 * Set maximum target operating fan output RPM
5855 * @param pHwMgr: the address of the powerplay hardware manager.
5856 * @param usMaxFanRpm: max operating fan RPM value.
5857 * @return The response that came from the SMC.
5859 static int tonga_set_max_fan_rpm_output(struct pp_hwmgr
*hwmgr
, uint16_t us_max_fan_pwm
)
5861 hwmgr
->thermal_controller
.advanceFanControlParameters
.usMaxFanRPM
= us_max_fan_pwm
;
5863 if (phm_is_hw_access_blocked(hwmgr
))
5866 return (0 == smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
, PPSMC_MSG_SetFanRpmMax
, us_max_fan_pwm
) ? 0 : -1);
5869 uint32_t tonga_get_xclk(struct pp_hwmgr
*hwmgr
)
5871 uint32_t reference_clock
;
5875 ATOM_FIRMWARE_INFO
*fw_info
;
5878 int index
= GetIndexIntoMasterTable(DATA
, FirmwareInfo
);
5880 tc
= PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, CG_CLKPIN_CNTL_2
, MUX_TCLK_TO_XCLK
);
5885 fw_info
= (ATOM_FIRMWARE_INFO
*)cgs_atom_get_data_table(hwmgr
->device
, index
,
5886 &size
, &frev
, &crev
);
5891 reference_clock
= le16_to_cpu(fw_info
->usReferenceClock
);
5893 divide
= PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, CG_CLKPIN_CNTL
, XTALIN_DIVIDE
);
5896 return reference_clock
/ 4;
5898 return reference_clock
;
5901 int tonga_dpm_set_interrupt_state(void *private_data
,
5902 unsigned src_id
, unsigned type
,
5905 uint32_t cg_thermal_int
;
5906 struct pp_hwmgr
*hwmgr
= ((struct pp_eventmgr
*)private_data
)->hwmgr
;
5912 case AMD_THERMAL_IRQ_LOW_TO_HIGH
:
5914 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5915 cg_thermal_int
|= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK
;
5916 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5918 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5919 cg_thermal_int
&= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK
;
5920 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5924 case AMD_THERMAL_IRQ_HIGH_TO_LOW
:
5926 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5927 cg_thermal_int
|= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK
;
5928 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5930 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5931 cg_thermal_int
&= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK
;
5932 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5941 int tonga_register_internal_thermal_interrupt(struct pp_hwmgr
*hwmgr
,
5942 const void *thermal_interrupt_info
)
5945 const struct pp_interrupt_registration_info
*info
=
5946 (const struct pp_interrupt_registration_info
*)thermal_interrupt_info
;
5951 result
= cgs_add_irq_source(hwmgr
->device
, 230, AMD_THERMAL_IRQ_LAST
,
5952 tonga_dpm_set_interrupt_state
,
5953 info
->call_back
, info
->context
);
5958 result
= cgs_add_irq_source(hwmgr
->device
, 231, AMD_THERMAL_IRQ_LAST
,
5959 tonga_dpm_set_interrupt_state
,
5960 info
->call_back
, info
->context
);
5968 bool tonga_check_smc_update_required_for_display_configuration(struct pp_hwmgr
*hwmgr
)
5970 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5971 bool is_update_required
= false;
5972 struct cgs_display_info info
= {0,0,NULL
};
5974 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5976 if (data
->display_timing
.num_existing_displays
!= info
.display_count
)
5977 is_update_required
= true;
5978 /* TO DO NEED TO GET DEEP SLEEP CLOCK FROM DAL
5979 if (phm_cap_enabled(hwmgr->hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
5980 cgs_get_min_clock_settings(hwmgr->device, &min_clocks);
5981 if(min_clocks.engineClockInSR != data->display_timing.minClockInSR)
5982 is_update_required = true;
5984 return is_update_required
;
5987 static inline bool tonga_are_power_levels_equal(const struct tonga_performance_level
*pl1
,
5988 const struct tonga_performance_level
*pl2
)
5990 return ((pl1
->memory_clock
== pl2
->memory_clock
) &&
5991 (pl1
->engine_clock
== pl2
->engine_clock
) &&
5992 (pl1
->pcie_gen
== pl2
->pcie_gen
) &&
5993 (pl1
->pcie_lane
== pl2
->pcie_lane
));
5996 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
)
5998 const struct tonga_power_state
*psa
= cast_const_phw_tonga_power_state(pstate1
);
5999 const struct tonga_power_state
*psb
= cast_const_phw_tonga_power_state(pstate2
);
6002 if (equal
== NULL
|| psa
== NULL
|| psb
== NULL
)
6005 /* If the two states don't even have the same number of performance levels they cannot be the same state. */
6006 if (psa
->performance_level_count
!= psb
->performance_level_count
) {
6011 for (i
= 0; i
< psa
->performance_level_count
; i
++) {
6012 if (!tonga_are_power_levels_equal(&(psa
->performance_levels
[i
]), &(psb
->performance_levels
[i
]))) {
6013 /* If we have found even one performance level pair that is different the states are different. */
6019 /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
6020 *equal
= ((psa
->uvd_clocks
.VCLK
== psb
->uvd_clocks
.VCLK
) && (psa
->uvd_clocks
.DCLK
== psb
->uvd_clocks
.DCLK
));
6021 *equal
&= ((psa
->vce_clocks
.EVCLK
== psb
->vce_clocks
.EVCLK
) && (psa
->vce_clocks
.ECCLK
== psb
->vce_clocks
.ECCLK
));
6022 *equal
&= (psa
->sclk_threshold
== psb
->sclk_threshold
);
6023 *equal
&= (psa
->acp_clk
== psb
->acp_clk
);
6028 static int tonga_set_fan_control_mode(struct pp_hwmgr
*hwmgr
, uint32_t mode
)
6031 /* stop auto-manage */
6032 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
6033 PHM_PlatformCaps_MicrocodeFanControl
))
6034 tonga_fan_ctrl_stop_smc_fan_control(hwmgr
);
6035 tonga_fan_ctrl_set_static_mode(hwmgr
, mode
);
6037 /* restart auto-manage */
6038 tonga_fan_ctrl_reset_fan_speed_to_default(hwmgr
);
6043 static int tonga_get_fan_control_mode(struct pp_hwmgr
*hwmgr
)
6045 if (hwmgr
->fan_ctrl_is_in_default_mode
)
6046 return hwmgr
->fan_ctrl_default_mode
;
6048 return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
6049 CG_FDO_CTRL2
, FDO_PWM_MODE
);
6052 static int tonga_force_clock_level(struct pp_hwmgr
*hwmgr
,
6053 enum pp_clock_type type
, uint32_t mask
)
6055 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
6057 if (hwmgr
->dpm_level
!= AMD_DPM_FORCED_LEVEL_MANUAL
)
6062 if (!data
->sclk_dpm_key_disabled
)
6063 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
6064 PPSMC_MSG_SCLKDPM_SetEnabledMask
,
6065 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
& mask
);
6068 if (!data
->mclk_dpm_key_disabled
)
6069 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
6070 PPSMC_MSG_MCLKDPM_SetEnabledMask
,
6071 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
& mask
);
6075 uint32_t tmp
= mask
& data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
;
6081 if (!data
->pcie_dpm_key_disabled
)
6082 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
6083 PPSMC_MSG_PCIeDPM_ForceLevel
,
6094 static int tonga_print_clock_levels(struct pp_hwmgr
*hwmgr
,
6095 enum pp_clock_type type
, char *buf
)
6097 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
6098 struct tonga_single_dpm_table
*sclk_table
= &(data
->dpm_table
.sclk_table
);
6099 struct tonga_single_dpm_table
*mclk_table
= &(data
->dpm_table
.mclk_table
);
6100 struct tonga_single_dpm_table
*pcie_table
= &(data
->dpm_table
.pcie_speed_table
);
6101 int i
, now
, size
= 0;
6102 uint32_t clock
, pcie_speed
;
6106 smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_API_GetSclkFrequency
);
6107 clock
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
6109 for (i
= 0; i
< sclk_table
->count
; i
++) {
6110 if (clock
> sclk_table
->dpm_levels
[i
].value
)
6116 for (i
= 0; i
< sclk_table
->count
; i
++)
6117 size
+= sprintf(buf
+ size
, "%d: %uMhz %s\n",
6118 i
, sclk_table
->dpm_levels
[i
].value
/ 100,
6119 (i
== now
) ? "*" : "");
6122 smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_API_GetMclkFrequency
);
6123 clock
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
6125 for (i
= 0; i
< mclk_table
->count
; i
++) {
6126 if (clock
> mclk_table
->dpm_levels
[i
].value
)
6132 for (i
= 0; i
< mclk_table
->count
; i
++)
6133 size
+= sprintf(buf
+ size
, "%d: %uMhz %s\n",
6134 i
, mclk_table
->dpm_levels
[i
].value
/ 100,
6135 (i
== now
) ? "*" : "");
6138 pcie_speed
= tonga_get_current_pcie_speed(hwmgr
);
6139 for (i
= 0; i
< pcie_table
->count
; i
++) {
6140 if (pcie_speed
!= pcie_table
->dpm_levels
[i
].value
)
6146 for (i
= 0; i
< pcie_table
->count
; i
++)
6147 size
+= sprintf(buf
+ size
, "%d: %s %s\n", i
,
6148 (pcie_table
->dpm_levels
[i
].value
== 0) ? "2.5GB, x8" :
6149 (pcie_table
->dpm_levels
[i
].value
== 1) ? "5.0GB, x16" :
6150 (pcie_table
->dpm_levels
[i
].value
== 2) ? "8.0GB, x16" : "",
6151 (i
== now
) ? "*" : "");
6159 static int tonga_get_sclk_od(struct pp_hwmgr
*hwmgr
)
6161 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
6162 struct tonga_single_dpm_table
*sclk_table
= &(data
->dpm_table
.sclk_table
);
6163 struct tonga_single_dpm_table
*golden_sclk_table
=
6164 &(data
->golden_dpm_table
.sclk_table
);
6167 value
= (sclk_table
->dpm_levels
[sclk_table
->count
- 1].value
-
6168 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
) *
6170 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
;
6175 static int tonga_set_sclk_od(struct pp_hwmgr
*hwmgr
, uint32_t value
)
6177 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
6178 struct tonga_single_dpm_table
*golden_sclk_table
=
6179 &(data
->golden_dpm_table
.sclk_table
);
6180 struct pp_power_state
*ps
;
6181 struct tonga_power_state
*tonga_ps
;
6186 ps
= hwmgr
->request_ps
;
6191 tonga_ps
= cast_phw_tonga_power_state(&ps
->hardware
);
6193 tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
- 1].engine_clock
=
6194 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
*
6196 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
;
6201 static int tonga_get_mclk_od(struct pp_hwmgr
*hwmgr
)
6203 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
6204 struct tonga_single_dpm_table
*mclk_table
= &(data
->dpm_table
.mclk_table
);
6205 struct tonga_single_dpm_table
*golden_mclk_table
=
6206 &(data
->golden_dpm_table
.mclk_table
);
6209 value
= (mclk_table
->dpm_levels
[mclk_table
->count
- 1].value
-
6210 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
) *
6212 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
;
6217 static int tonga_set_mclk_od(struct pp_hwmgr
*hwmgr
, uint32_t value
)
6219 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
6220 struct tonga_single_dpm_table
*golden_mclk_table
=
6221 &(data
->golden_dpm_table
.mclk_table
);
6222 struct pp_power_state
*ps
;
6223 struct tonga_power_state
*tonga_ps
;
6228 ps
= hwmgr
->request_ps
;
6233 tonga_ps
= cast_phw_tonga_power_state(&ps
->hardware
);
6235 tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
- 1].memory_clock
=
6236 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
*
6238 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
;
6243 static const struct pp_hwmgr_func tonga_hwmgr_funcs
= {
6244 .backend_init
= &tonga_hwmgr_backend_init
,
6245 .backend_fini
= &tonga_hwmgr_backend_fini
,
6246 .asic_setup
= &tonga_setup_asic_task
,
6247 .dynamic_state_management_enable
= &tonga_enable_dpm_tasks
,
6248 .dynamic_state_management_disable
= &tonga_disable_dpm_tasks
,
6249 .apply_state_adjust_rules
= tonga_apply_state_adjust_rules
,
6250 .force_dpm_level
= &tonga_force_dpm_level
,
6251 .power_state_set
= tonga_set_power_state_tasks
,
6252 .get_power_state_size
= tonga_get_power_state_size
,
6253 .get_mclk
= tonga_dpm_get_mclk
,
6254 .get_sclk
= tonga_dpm_get_sclk
,
6255 .patch_boot_state
= tonga_dpm_patch_boot_state
,
6256 .get_pp_table_entry
= tonga_get_pp_table_entry
,
6257 .get_num_of_pp_table_entries
= tonga_get_number_of_powerplay_table_entries
,
6258 .print_current_perforce_level
= tonga_print_current_perforce_level
,
6259 .powerdown_uvd
= tonga_phm_powerdown_uvd
,
6260 .powergate_uvd
= tonga_phm_powergate_uvd
,
6261 .powergate_vce
= tonga_phm_powergate_vce
,
6262 .disable_clock_power_gating
= tonga_phm_disable_clock_power_gating
,
6263 .update_clock_gatings
= tonga_phm_update_clock_gatings
,
6264 .notify_smc_display_config_after_ps_adjustment
= tonga_notify_smc_display_config_after_ps_adjustment
,
6265 .display_config_changed
= tonga_display_configuration_changed_task
,
6266 .set_max_fan_pwm_output
= tonga_set_max_fan_pwm_output
,
6267 .set_max_fan_rpm_output
= tonga_set_max_fan_rpm_output
,
6268 .get_temperature
= tonga_thermal_get_temperature
,
6269 .stop_thermal_controller
= tonga_thermal_stop_thermal_controller
,
6270 .get_fan_speed_info
= tonga_fan_ctrl_get_fan_speed_info
,
6271 .get_fan_speed_percent
= tonga_fan_ctrl_get_fan_speed_percent
,
6272 .set_fan_speed_percent
= tonga_fan_ctrl_set_fan_speed_percent
,
6273 .reset_fan_speed_to_default
= tonga_fan_ctrl_reset_fan_speed_to_default
,
6274 .get_fan_speed_rpm
= tonga_fan_ctrl_get_fan_speed_rpm
,
6275 .set_fan_speed_rpm
= tonga_fan_ctrl_set_fan_speed_rpm
,
6276 .uninitialize_thermal_controller
= tonga_thermal_ctrl_uninitialize_thermal_controller
,
6277 .register_internal_thermal_interrupt
= tonga_register_internal_thermal_interrupt
,
6278 .check_smc_update_required_for_display_configuration
= tonga_check_smc_update_required_for_display_configuration
,
6279 .check_states_equal
= tonga_check_states_equal
,
6280 .set_fan_control_mode
= tonga_set_fan_control_mode
,
6281 .get_fan_control_mode
= tonga_get_fan_control_mode
,
6282 .force_clock_level
= tonga_force_clock_level
,
6283 .print_clock_levels
= tonga_print_clock_levels
,
6284 .get_sclk_od
= tonga_get_sclk_od
,
6285 .set_sclk_od
= tonga_set_sclk_od
,
6286 .get_mclk_od
= tonga_get_mclk_od
,
6287 .set_mclk_od
= tonga_set_mclk_od
,
6290 int tonga_hwmgr_init(struct pp_hwmgr
*hwmgr
)
6292 hwmgr
->hwmgr_func
= &tonga_hwmgr_funcs
;
6293 hwmgr
->pptable_func
= &tonga_pptable_funcs
;
6294 pp_tonga_thermal_initialize(hwmgr
);