2 * Copyright 2015 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
23 #include <linux/module.h>
24 #include <linux/slab.h>
26 #include "linux/delay.h"
30 #include "tonga_hwmgr.h"
32 #include "processpptables.h"
33 #include "tonga_processpptables.h"
34 #include "tonga_pptable.h"
36 #include "tonga_ppsmc.h"
37 #include "cgs_common.h"
38 #include "pppcielanes.h"
39 #include "tonga_dyn_defaults.h"
41 #include "tonga_smumgr.h"
43 #include "smu/smu_7_1_2_d.h"
44 #include "smu/smu_7_1_2_sh_mask.h"
46 #include "gmc/gmc_8_1_d.h"
47 #include "gmc/gmc_8_1_sh_mask.h"
49 #include "bif/bif_5_0_d.h"
50 #include "bif/bif_5_0_sh_mask.h"
52 #define MC_CG_ARB_FREQ_F0 0x0a
53 #define MC_CG_ARB_FREQ_F1 0x0b
54 #define MC_CG_ARB_FREQ_F2 0x0c
55 #define MC_CG_ARB_FREQ_F3 0x0d
57 #define MC_CG_SEQ_DRAMCONF_S0 0x05
58 #define MC_CG_SEQ_DRAMCONF_S1 0x06
59 #define MC_CG_SEQ_YCLK_SUSPEND 0x04
60 #define MC_CG_SEQ_YCLK_RESUME 0x0a
62 #define PCIE_BUS_CLK 10000
63 #define TCLK (PCIE_BUS_CLK / 10)
65 #define SMC_RAM_END 0x40000
66 #define SMC_CG_IND_START 0xc0030000
67 #define SMC_CG_IND_END 0xc0040000 /* First byte after SMC_CG_IND*/
69 #define VOLTAGE_SCALE 4
70 #define VOLTAGE_VID_OFFSET_SCALE1 625
71 #define VOLTAGE_VID_OFFSET_SCALE2 100
73 #define VDDC_VDDCI_DELTA 200
74 #define VDDC_VDDGFX_DELTA 300
76 #define MC_SEQ_MISC0_GDDR5_SHIFT 28
77 #define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000
78 #define MC_SEQ_MISC0_GDDR5_VALUE 5
80 typedef uint32_t PECI_RegistryValue
;
82 /* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ] */
83 uint16_t PP_ClockStretcherLookupTable
[2][4] = {
87 /* [FF, SS] type, [] 4 voltage ranges, and [Floor Freq, Boundary Freq, VID min , VID max] */
88 uint32_t PP_ClockStretcherDDTTable
[2][4][4] = {
89 { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
90 { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
92 /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] (coming from PWR_CKS_CNTL.stretch_amount reg spec) */
93 uint8_t PP_ClockStretchAmountConversion
[2][6] = {
97 /* Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
99 DPM_EVENT_SRC_ANALOG
= 0, /* Internal analog trip point */
100 DPM_EVENT_SRC_EXTERNAL
= 1, /* External (GPIO 17) signal */
101 DPM_EVENT_SRC_DIGITAL
= 2, /* Internal digital trip point (DIG_THERM_DPM) */
102 DPM_EVENT_SRC_ANALOG_OR_EXTERNAL
= 3, /* Internal analog or external */
103 DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL
= 4 /* Internal digital or external */
105 typedef enum DPM_EVENT_SRC DPM_EVENT_SRC
;
108 DISPLAY_GAP_VBLANK_OR_WM
= 0, /* Wait for vblank or MCHG watermark. */
109 DISPLAY_GAP_VBLANK
= 1, /* Wait for vblank. */
110 DISPLAY_GAP_WATERMARK
= 2, /* Wait for MCHG watermark. (Note that HW may deassert WM in VBI depending on DC_STUTTER_CNTL.) */
111 DISPLAY_GAP_IGNORE
= 3 /* Do not wait. */
113 typedef enum DISPLAY_GAP DISPLAY_GAP
;
115 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
)
120 PP_ASSERT_WITH_CODE((PhwTonga_Magic
== hw_ps
->magic
),
121 "Invalid Powerstate Type!",
124 return (struct tonga_power_state
*)hw_ps
;
127 const struct tonga_power_state
*cast_const_phw_tonga_power_state(
128 const struct pp_hw_power_state
*hw_ps
)
130 PP_ASSERT_WITH_CODE((PhwTonga_Magic
== hw_ps
->magic
),
131 "Invalid Powerstate Type!",
134 return (const struct tonga_power_state
*)hw_ps
;
137 int tonga_add_voltage(struct pp_hwmgr
*hwmgr
,
138 phm_ppt_v1_voltage_lookup_table
*look_up_table
,
139 phm_ppt_v1_voltage_lookup_record
*record
)
142 PP_ASSERT_WITH_CODE((NULL
!= look_up_table
),
143 "Lookup Table empty.", return -1;);
144 PP_ASSERT_WITH_CODE((0 != look_up_table
->count
),
145 "Lookup Table empty.", return -1;);
146 PP_ASSERT_WITH_CODE((SMU72_MAX_LEVELS_VDDGFX
>= look_up_table
->count
),
147 "Lookup Table is full.", return -1;);
149 /* This is to avoid entering duplicate calculated records. */
150 for (i
= 0; i
< look_up_table
->count
; i
++) {
151 if (look_up_table
->entries
[i
].us_vdd
== record
->us_vdd
) {
152 if (look_up_table
->entries
[i
].us_calculated
== 1)
159 look_up_table
->entries
[i
].us_calculated
= 1;
160 look_up_table
->entries
[i
].us_vdd
= record
->us_vdd
;
161 look_up_table
->entries
[i
].us_cac_low
= record
->us_cac_low
;
162 look_up_table
->entries
[i
].us_cac_mid
= record
->us_cac_mid
;
163 look_up_table
->entries
[i
].us_cac_high
= record
->us_cac_high
;
164 /* Only increment the count when we're appending, not replacing duplicate entry. */
165 if (i
== look_up_table
->count
)
166 look_up_table
->count
++;
171 int tonga_notify_smc_display_change(struct pp_hwmgr
*hwmgr
, bool has_display
)
173 PPSMC_Msg msg
= has_display
? (PPSMC_Msg
)PPSMC_HasDisplay
: (PPSMC_Msg
)PPSMC_NoDisplay
;
175 return (smum_send_msg_to_smc(hwmgr
->smumgr
, msg
) == 0) ? 0 : -1;
178 uint8_t tonga_get_voltage_id(pp_atomctrl_voltage_table
*voltage_table
,
181 uint8_t count
= (uint8_t) (voltage_table
->count
);
184 PP_ASSERT_WITH_CODE((NULL
!= voltage_table
),
185 "Voltage Table empty.", return 0;);
186 PP_ASSERT_WITH_CODE((0 != count
),
187 "Voltage Table empty.", return 0;);
189 for (i
= 0; i
< count
; i
++) {
190 /* find first voltage bigger than requested */
191 if (voltage_table
->entries
[i
].value
>= voltage
)
195 /* voltage is bigger than max voltage in the table */
200 * @brief PhwTonga_GetVoltageOrder
201 * Returns index of requested voltage record in lookup(table)
202 * @param hwmgr - pointer to hardware manager
203 * @param lookupTable - lookup list to search in
204 * @param voltage - voltage to look for
205 * @return 0 on success
207 uint8_t tonga_get_voltage_index(phm_ppt_v1_voltage_lookup_table
*look_up_table
,
210 uint8_t count
= (uint8_t) (look_up_table
->count
);
213 PP_ASSERT_WITH_CODE((NULL
!= look_up_table
), "Lookup Table empty.", return 0;);
214 PP_ASSERT_WITH_CODE((0 != count
), "Lookup Table empty.", return 0;);
216 for (i
= 0; i
< count
; i
++) {
217 /* find first voltage equal or bigger than requested */
218 if (look_up_table
->entries
[i
].us_vdd
>= voltage
)
222 /* voltage is bigger than max voltage in the table */
226 bool tonga_is_dpm_running(struct pp_hwmgr
*hwmgr
)
229 * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
230 * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
231 * whereas voltage control is a fundemental change that will not be disabled
234 return (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
235 FEATURE_STATUS
, VOLTAGE_CONTROLLER_ON
) ? 1 : 0);
239 * Re-generate the DPM level mask value
240 * @param hwmgr the address of the hardware manager
242 static uint32_t tonga_get_dpm_level_enable_mask_value(
243 struct tonga_single_dpm_table
* dpm_table
)
246 uint32_t mask_value
= 0;
248 for (i
= dpm_table
->count
; i
> 0; i
--) {
249 mask_value
= mask_value
<< 1;
251 if (dpm_table
->dpm_levels
[i
-1].enabled
)
254 mask_value
&= 0xFFFFFFFE;
260 * Retrieve DPM default values from registry (if available)
262 * @param hwmgr the address of the powerplay hardware manager.
264 void tonga_initialize_dpm_defaults(struct pp_hwmgr
*hwmgr
)
266 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
267 phw_tonga_ulv_parm
*ulv
= &(data
->ulv
);
270 ulv
->ch_ulv_parameter
= PPTONGA_CGULVPARAMETER_DFLT
;
271 data
->voting_rights_clients0
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0
;
272 data
->voting_rights_clients1
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1
;
273 data
->voting_rights_clients2
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2
;
274 data
->voting_rights_clients3
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3
;
275 data
->voting_rights_clients4
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4
;
276 data
->voting_rights_clients5
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5
;
277 data
->voting_rights_clients6
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6
;
278 data
->voting_rights_clients7
= PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7
;
280 data
->static_screen_threshold_unit
= PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT
;
281 data
->static_screen_threshold
= PPTONGA_STATICSCREENTHRESHOLD_DFLT
;
283 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
284 PHM_PlatformCaps_ABM
);
285 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
286 PHM_PlatformCaps_NonABMSupportInPPLib
);
290 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
291 PHM_PlatformCaps_DynamicACTiming
);
295 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
296 PHM_PlatformCaps_DisableMemoryTransition
);
298 data
->mclk_strobe_mode_threshold
= 40000;
299 data
->mclk_stutter_mode_threshold
= 30000;
300 data
->mclk_edc_enable_threshold
= 40000;
301 data
->mclk_edc_wr_enable_threshold
= 40000;
305 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
306 PHM_PlatformCaps_DisableMCLS
);
308 data
->pcie_gen_performance
.max
= PP_PCIEGen1
;
309 data
->pcie_gen_performance
.min
= PP_PCIEGen3
;
310 data
->pcie_gen_power_saving
.max
= PP_PCIEGen1
;
311 data
->pcie_gen_power_saving
.min
= PP_PCIEGen3
;
313 data
->pcie_lane_performance
.max
= 0;
314 data
->pcie_lane_performance
.min
= 16;
315 data
->pcie_lane_power_saving
.max
= 0;
316 data
->pcie_lane_power_saving
.min
= 16;
321 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
322 PHM_PlatformCaps_SclkThrottleLowNotification
);
324 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
325 PHM_PlatformCaps_DynamicUVDState
);
329 int tonga_update_sclk_threshold(struct pp_hwmgr
*hwmgr
)
331 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
334 uint32_t low_sclk_interrupt_threshold
= 0;
336 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
337 PHM_PlatformCaps_SclkThrottleLowNotification
)
338 && (hwmgr
->gfx_arbiter
.sclk_threshold
!= data
->low_sclk_interrupt_threshold
)) {
339 data
->low_sclk_interrupt_threshold
= hwmgr
->gfx_arbiter
.sclk_threshold
;
340 low_sclk_interrupt_threshold
= data
->low_sclk_interrupt_threshold
;
342 CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold
);
344 result
= tonga_copy_bytes_to_smc(
346 data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
,
347 LowSclkInterruptThreshold
),
348 (uint8_t *)&low_sclk_interrupt_threshold
,
358 * Find SCLK value that is associated with specified virtual_voltage_Id.
360 * @param hwmgr the address of the powerplay hardware manager.
361 * @param virtual_voltage_Id voltageId to look for.
362 * @param sclk output value .
363 * @return always 0 if success and 2 if association not found
365 static int tonga_get_sclk_for_voltage_evv(struct pp_hwmgr
*hwmgr
,
366 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
367 uint16_t virtual_voltage_id
, uint32_t *sclk
)
371 struct phm_ppt_v1_information
*pptable_info
=
372 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
374 PP_ASSERT_WITH_CODE(lookup_table
->count
!= 0, "Lookup table is empty", return -1);
376 /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
377 for (entryId
= 0; entryId
< pptable_info
->vdd_dep_on_sclk
->count
; entryId
++) {
378 voltageId
= pptable_info
->vdd_dep_on_sclk
->entries
[entryId
].vddInd
;
379 if (lookup_table
->entries
[voltageId
].us_vdd
== virtual_voltage_id
)
383 PP_ASSERT_WITH_CODE(entryId
< pptable_info
->vdd_dep_on_sclk
->count
,
384 "Can't find requested voltage id in vdd_dep_on_sclk table!",
388 *sclk
= pptable_info
->vdd_dep_on_sclk
->entries
[entryId
].clk
;
394 * Get Leakage VDDC based on leakage ID.
396 * @param hwmgr the address of the powerplay hardware manager.
397 * @return 2 if vddgfx returned is greater than 2V or if BIOS
399 int tonga_get_evv_voltage(struct pp_hwmgr
*hwmgr
)
401 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
402 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
403 phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
= pptable_info
->vdd_dep_on_sclk
;
404 uint16_t virtual_voltage_id
;
410 /* retrieve voltage for leakage ID (0xff01 + i) */
411 for (i
= 0; i
< TONGA_MAX_LEAKAGE_COUNT
; i
++) {
412 virtual_voltage_id
= ATOM_VIRTUAL_VOLTAGE_ID0
+ i
;
414 /* in split mode we should have only vddgfx EVV leakages */
415 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
416 if (0 == tonga_get_sclk_for_voltage_evv(hwmgr
,
417 pptable_info
->vddgfx_lookup_table
, virtual_voltage_id
, &sclk
)) {
418 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
419 PHM_PlatformCaps_ClockStretcher
)) {
420 for (j
= 1; j
< sclk_table
->count
; j
++) {
421 if (sclk_table
->entries
[j
].clk
== sclk
&&
422 sclk_table
->entries
[j
].cks_enable
== 0) {
428 PP_ASSERT_WITH_CODE(0 == atomctrl_get_voltage_evv_on_sclk
429 (hwmgr
, VOLTAGE_TYPE_VDDGFX
, sclk
,
430 virtual_voltage_id
, &vddgfx
),
431 "Error retrieving EVV voltage value!", continue);
433 /* need to make sure vddgfx is less than 2v or else, it could burn the ASIC. */
434 PP_ASSERT_WITH_CODE((vddgfx
< 2000 && vddgfx
!= 0), "Invalid VDDGFX value!", return -1);
436 /* the voltage should not be zero nor equal to leakage ID */
437 if (vddgfx
!= 0 && vddgfx
!= virtual_voltage_id
) {
438 data
->vddcgfx_leakage
.actual_voltage
[data
->vddcgfx_leakage
.count
] = vddgfx
;
439 data
->vddcgfx_leakage
.leakage_id
[data
->vddcgfx_leakage
.count
] = virtual_voltage_id
;
440 data
->vddcgfx_leakage
.count
++;
444 /* in merged mode we have only vddc EVV leakages */
445 if (0 == tonga_get_sclk_for_voltage_evv(hwmgr
,
446 pptable_info
->vddc_lookup_table
,
447 virtual_voltage_id
, &sclk
)) {
448 PP_ASSERT_WITH_CODE(0 == atomctrl_get_voltage_evv_on_sclk
449 (hwmgr
, VOLTAGE_TYPE_VDDC
, sclk
,
450 virtual_voltage_id
, &vddc
),
451 "Error retrieving EVV voltage value!", continue);
453 /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
455 printk(KERN_ERR
"[ powerplay ] Invalid VDDC value! \n");
457 /* the voltage should not be zero nor equal to leakage ID */
458 if (vddc
!= 0 && vddc
!= virtual_voltage_id
) {
459 data
->vddc_leakage
.actual_voltage
[data
->vddc_leakage
.count
] = vddc
;
460 data
->vddc_leakage
.leakage_id
[data
->vddc_leakage
.count
] = virtual_voltage_id
;
461 data
->vddc_leakage
.count
++;
470 int tonga_enable_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
472 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
474 /* enable SCLK dpm */
475 if (0 == data
->sclk_dpm_key_disabled
) {
477 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
478 PPSMC_MSG_DPM_Enable
)),
479 "Failed to enable SCLK DPM during DPM Start Function!",
483 /* enable MCLK dpm */
484 if (0 == data
->mclk_dpm_key_disabled
) {
486 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
487 PPSMC_MSG_MCLKDPM_Enable
)),
488 "Failed to enable MCLK DPM during DPM Start Function!",
491 PHM_WRITE_FIELD(hwmgr
->device
, MC_SEQ_CNTL_3
, CAC_EN
, 0x1);
493 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
494 ixLCAC_MC0_CNTL
, 0x05);/* CH0,1 read */
495 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
496 ixLCAC_MC1_CNTL
, 0x05);/* CH2,3 read */
497 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
498 ixLCAC_CPL_CNTL
, 0x100005);/*Read */
502 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
503 ixLCAC_MC0_CNTL
, 0x400005);/* CH0,1 write */
504 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
505 ixLCAC_MC1_CNTL
, 0x400005);/* CH2,3 write */
506 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
507 ixLCAC_CPL_CNTL
, 0x500005);/* write */
514 int tonga_start_dpm(struct pp_hwmgr
*hwmgr
)
516 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
518 /* enable general power management */
519 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, GLOBAL_PWRMGT_EN
, 1);
520 /* enable sclk deep sleep */
521 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
, DYNAMIC_PM_EN
, 1);
523 /* prepare for PCIE DPM */
524 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, data
->soft_regs_start
+
525 offsetof(SMU72_SoftRegisters
, VoltageChangeTimeout
), 0x1000);
527 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__PCIE
, SWRST_COMMAND_1
, RESETLC
, 0x0);
530 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
531 PPSMC_MSG_Voltage_Cntl_Enable
)),
532 "Failed to enable voltage DPM during DPM Start Function!",
535 if (0 != tonga_enable_sclk_mclk_dpm(hwmgr
)) {
536 PP_ASSERT_WITH_CODE(0, "Failed to enable Sclk DPM and Mclk DPM!", return -1);
539 /* enable PCIE dpm */
540 if (0 == data
->pcie_dpm_key_disabled
) {
542 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
543 PPSMC_MSG_PCIeDPM_Enable
)),
544 "Failed to enable pcie DPM during DPM Start Function!",
549 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
550 PHM_PlatformCaps_Falcon_QuickTransition
)) {
551 smum_send_msg_to_smc(hwmgr
->smumgr
,
552 PPSMC_MSG_EnableACDCGPIOInterrupt
);
558 int tonga_disable_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
560 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
562 /* disable SCLK dpm */
563 if (0 == data
->sclk_dpm_key_disabled
) {
564 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
566 (0 == tonga_is_dpm_running(hwmgr
)),
567 "Trying to Disable SCLK DPM when DPM is disabled",
572 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
573 PPSMC_MSG_DPM_Disable
)),
574 "Failed to disable SCLK DPM during DPM stop Function!",
578 /* disable MCLK dpm */
579 if (0 == data
->mclk_dpm_key_disabled
) {
580 /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
582 (0 == tonga_is_dpm_running(hwmgr
)),
583 "Trying to Disable MCLK DPM when DPM is disabled",
588 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
589 PPSMC_MSG_MCLKDPM_Disable
)),
590 "Failed to Disable MCLK DPM during DPM stop Function!",
597 int tonga_stop_dpm(struct pp_hwmgr
*hwmgr
)
599 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
601 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, GLOBAL_PWRMGT_EN
, 0);
602 /* disable sclk deep sleep*/
603 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
, DYNAMIC_PM_EN
, 0);
605 /* disable PCIE dpm */
606 if (0 == data
->pcie_dpm_key_disabled
) {
607 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
609 (0 == tonga_is_dpm_running(hwmgr
)),
610 "Trying to Disable PCIE DPM when DPM is disabled",
614 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
615 PPSMC_MSG_PCIeDPM_Disable
)),
616 "Failed to disable pcie DPM during DPM stop Function!",
620 if (0 != tonga_disable_sclk_mclk_dpm(hwmgr
))
621 PP_ASSERT_WITH_CODE(0, "Failed to disable Sclk DPM and Mclk DPM!", return -1);
623 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
625 (0 == tonga_is_dpm_running(hwmgr
)),
626 "Trying to Disable Voltage CNTL when DPM is disabled",
631 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
632 PPSMC_MSG_Voltage_Cntl_Disable
)),
633 "Failed to disable voltage DPM during DPM stop Function!",
639 int tonga_enable_sclk_control(struct pp_hwmgr
*hwmgr
)
641 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
, SCLK_PWRMGT_OFF
, 0);
647 * Send a message to the SMC and return a parameter
649 * @param hwmgr: the address of the powerplay hardware manager.
650 * @param msg: the message to send.
651 * @param parameter: pointer to the received parameter
652 * @return The response that came from the SMC.
654 PPSMC_Result
tonga_send_msg_to_smc_return_parameter(
655 struct pp_hwmgr
*hwmgr
,
661 result
= smum_send_msg_to_smc(hwmgr
->smumgr
, msg
);
663 if ((0 == result
) && parameter
) {
664 *parameter
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
671 * force DPM power State
673 * @param hwmgr: the address of the powerplay hardware manager.
674 * @param n : DPM level
675 * @return The response that came from the SMC.
677 int tonga_dpm_force_state(struct pp_hwmgr
*hwmgr
, uint32_t n
)
679 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
680 uint32_t level_mask
= 1 << n
;
682 /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
683 PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr
),
684 "Trying to force SCLK when DPM is disabled", return -1;);
685 if (0 == data
->sclk_dpm_key_disabled
)
686 return (0 == smum_send_msg_to_smc_with_parameter(
688 (PPSMC_Msg
)(PPSMC_MSG_SCLKDPM_SetEnabledMask
),
689 level_mask
) ? 0 : 1);
695 * force DPM power State
697 * @param hwmgr: the address of the powerplay hardware manager.
698 * @param n : DPM level
699 * @return The response that came from the SMC.
701 int tonga_dpm_force_state_mclk(struct pp_hwmgr
*hwmgr
, uint32_t n
)
703 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
704 uint32_t level_mask
= 1 << n
;
706 /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
707 PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr
),
708 "Trying to Force MCLK when DPM is disabled", return -1;);
709 if (0 == data
->mclk_dpm_key_disabled
)
710 return (0 == smum_send_msg_to_smc_with_parameter(
712 (PPSMC_Msg
)(PPSMC_MSG_MCLKDPM_SetEnabledMask
),
713 level_mask
) ? 0 : 1);
719 * force DPM power State
721 * @param hwmgr: the address of the powerplay hardware manager.
722 * @param n : DPM level
723 * @return The response that came from the SMC.
725 int tonga_dpm_force_state_pcie(struct pp_hwmgr
*hwmgr
, uint32_t n
)
727 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
729 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
730 PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr
),
731 "Trying to Force PCIE level when DPM is disabled", return -1;);
732 if (0 == data
->pcie_dpm_key_disabled
)
733 return (0 == smum_send_msg_to_smc_with_parameter(
735 (PPSMC_Msg
)(PPSMC_MSG_PCIeDPM_ForceLevel
),
742 * Set the initial state by calling SMC to switch to this state directly
744 * @param hwmgr the address of the powerplay hardware manager.
747 int tonga_set_boot_state(struct pp_hwmgr
*hwmgr
)
750 * SMC only stores one state that SW will ask to switch too,
751 * so we switch the the just uploaded one
753 return (0 == tonga_disable_sclk_mclk_dpm(hwmgr
)) ? 0 : 1;
757 * Get the location of various tables inside the FW image.
759 * @param hwmgr the address of the powerplay hardware manager.
762 int tonga_process_firmware_header(struct pp_hwmgr
*hwmgr
)
764 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
765 struct tonga_smumgr
*tonga_smu
= (struct tonga_smumgr
*)(hwmgr
->smumgr
->backend
);
771 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
772 SMU72_FIRMWARE_HEADER_LOCATION
+
773 offsetof(SMU72_Firmware_Header
, DpmTable
),
774 &tmp
, data
->sram_end
);
777 data
->dpm_table_start
= tmp
;
780 error
|= (0 != result
);
782 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
783 SMU72_FIRMWARE_HEADER_LOCATION
+
784 offsetof(SMU72_Firmware_Header
, SoftRegisters
),
785 &tmp
, data
->sram_end
);
788 data
->soft_regs_start
= tmp
;
789 tonga_smu
->ulSoftRegsStart
= tmp
;
792 error
|= (0 != result
);
795 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
796 SMU72_FIRMWARE_HEADER_LOCATION
+
797 offsetof(SMU72_Firmware_Header
, mcRegisterTable
),
798 &tmp
, data
->sram_end
);
801 data
->mc_reg_table_start
= tmp
;
804 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
805 SMU72_FIRMWARE_HEADER_LOCATION
+
806 offsetof(SMU72_Firmware_Header
, FanTable
),
807 &tmp
, data
->sram_end
);
810 data
->fan_table_start
= tmp
;
813 error
|= (0 != result
);
815 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
816 SMU72_FIRMWARE_HEADER_LOCATION
+
817 offsetof(SMU72_Firmware_Header
, mcArbDramTimingTable
),
818 &tmp
, data
->sram_end
);
821 data
->arb_table_start
= tmp
;
824 error
|= (0 != result
);
827 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
828 SMU72_FIRMWARE_HEADER_LOCATION
+
829 offsetof(SMU72_Firmware_Header
, Version
),
830 &tmp
, data
->sram_end
);
833 hwmgr
->microcode_version_info
.SMC
= tmp
;
836 error
|= (0 != result
);
838 return error
? 1 : 0;
842 * Read clock related registers.
844 * @param hwmgr the address of the powerplay hardware manager.
847 int tonga_read_clock_registers(struct pp_hwmgr
*hwmgr
)
849 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
851 data
->clock_registers
.vCG_SPLL_FUNC_CNTL
=
852 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL
);
853 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
=
854 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL_2
);
855 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
=
856 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL_3
);
857 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
=
858 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_FUNC_CNTL_4
);
859 data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
=
860 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_SPREAD_SPECTRUM
);
861 data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
=
862 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_SPLL_SPREAD_SPECTRUM_2
);
863 data
->clock_registers
.vDLL_CNTL
=
864 cgs_read_register(hwmgr
->device
, mmDLL_CNTL
);
865 data
->clock_registers
.vMCLK_PWRMGT_CNTL
=
866 cgs_read_register(hwmgr
->device
, mmMCLK_PWRMGT_CNTL
);
867 data
->clock_registers
.vMPLL_AD_FUNC_CNTL
=
868 cgs_read_register(hwmgr
->device
, mmMPLL_AD_FUNC_CNTL
);
869 data
->clock_registers
.vMPLL_DQ_FUNC_CNTL
=
870 cgs_read_register(hwmgr
->device
, mmMPLL_DQ_FUNC_CNTL
);
871 data
->clock_registers
.vMPLL_FUNC_CNTL
=
872 cgs_read_register(hwmgr
->device
, mmMPLL_FUNC_CNTL
);
873 data
->clock_registers
.vMPLL_FUNC_CNTL_1
=
874 cgs_read_register(hwmgr
->device
, mmMPLL_FUNC_CNTL_1
);
875 data
->clock_registers
.vMPLL_FUNC_CNTL_2
=
876 cgs_read_register(hwmgr
->device
, mmMPLL_FUNC_CNTL_2
);
877 data
->clock_registers
.vMPLL_SS1
=
878 cgs_read_register(hwmgr
->device
, mmMPLL_SS1
);
879 data
->clock_registers
.vMPLL_SS2
=
880 cgs_read_register(hwmgr
->device
, mmMPLL_SS2
);
886 * Find out if memory is GDDR5.
888 * @param hwmgr the address of the powerplay hardware manager.
891 int tonga_get_memory_type(struct pp_hwmgr
*hwmgr
)
893 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
896 temp
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC0
);
898 data
->is_memory_GDDR5
= (MC_SEQ_MISC0_GDDR5_VALUE
==
899 ((temp
& MC_SEQ_MISC0_GDDR5_MASK
) >>
900 MC_SEQ_MISC0_GDDR5_SHIFT
));
906 * Enables Dynamic Power Management by SMC
908 * @param hwmgr the address of the powerplay hardware manager.
911 int tonga_enable_acpi_power_management(struct pp_hwmgr
*hwmgr
)
913 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, STATIC_PM_EN
, 1);
919 * Initialize PowerGating States for different engines
921 * @param hwmgr the address of the powerplay hardware manager.
924 int tonga_init_power_gate_state(struct pp_hwmgr
*hwmgr
)
926 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
928 data
->uvd_power_gated
= 0;
929 data
->vce_power_gated
= 0;
930 data
->samu_power_gated
= 0;
931 data
->acp_power_gated
= 0;
932 data
->pg_acp_init
= 1;
938 * Checks if DPM is enabled
940 * @param hwmgr the address of the powerplay hardware manager.
943 int tonga_check_for_dpm_running(struct pp_hwmgr
*hwmgr
)
946 * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
947 * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
948 * whereas voltage control is a fundemental change that will not be disabled
950 return (0 == tonga_is_dpm_running(hwmgr
) ? 0 : 1);
954 * Checks if DPM is stopped
956 * @param hwmgr the address of the powerplay hardware manager.
959 int tonga_check_for_dpm_stopped(struct pp_hwmgr
*hwmgr
)
961 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
963 if (0 != tonga_is_dpm_running(hwmgr
)) {
964 /* If HW Virtualization is enabled, dpm_table_start will not have a valid value */
965 if (!data
->dpm_table_start
) {
974 * Remove repeated voltage values and create table with unique values.
976 * @param hwmgr the address of the powerplay hardware manager.
977 * @param voltage_table the pointer to changing voltage table
978 * @return 1 in success
981 static int tonga_trim_voltage_table(struct pp_hwmgr
*hwmgr
,
982 pp_atomctrl_voltage_table
*voltage_table
)
984 uint32_t table_size
, i
, j
;
986 bool bVoltageFound
= 0;
987 pp_atomctrl_voltage_table
*table
;
989 PP_ASSERT_WITH_CODE((NULL
!= voltage_table
), "Voltage Table empty.", return -1;);
990 table_size
= sizeof(pp_atomctrl_voltage_table
);
991 table
= kzalloc(table_size
, GFP_KERNEL
);
996 memset(table
, 0x00, table_size
);
997 table
->mask_low
= voltage_table
->mask_low
;
998 table
->phase_delay
= voltage_table
->phase_delay
;
1000 for (i
= 0; i
< voltage_table
->count
; i
++) {
1001 vvalue
= voltage_table
->entries
[i
].value
;
1004 for (j
= 0; j
< table
->count
; j
++) {
1005 if (vvalue
== table
->entries
[j
].value
) {
1011 if (!bVoltageFound
) {
1012 table
->entries
[table
->count
].value
= vvalue
;
1013 table
->entries
[table
->count
].smio_low
=
1014 voltage_table
->entries
[i
].smio_low
;
1019 memcpy(table
, voltage_table
, sizeof(pp_atomctrl_voltage_table
));
1026 static int tonga_get_svi2_vdd_ci_voltage_table(
1027 struct pp_hwmgr
*hwmgr
,
1028 phm_ppt_v1_clock_voltage_dependency_table
*voltage_dependency_table
)
1032 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1033 pp_atomctrl_voltage_table
*vddci_voltage_table
= &(data
->vddci_voltage_table
);
1035 PP_ASSERT_WITH_CODE((0 != voltage_dependency_table
->count
),
1036 "Voltage Dependency Table empty.", return -1;);
1038 vddci_voltage_table
->mask_low
= 0;
1039 vddci_voltage_table
->phase_delay
= 0;
1040 vddci_voltage_table
->count
= voltage_dependency_table
->count
;
1042 for (i
= 0; i
< voltage_dependency_table
->count
; i
++) {
1043 vddci_voltage_table
->entries
[i
].value
=
1044 voltage_dependency_table
->entries
[i
].vddci
;
1045 vddci_voltage_table
->entries
[i
].smio_low
= 0;
1048 result
= tonga_trim_voltage_table(hwmgr
, vddci_voltage_table
);
1049 PP_ASSERT_WITH_CODE((0 == result
),
1050 "Failed to trim VDDCI table.", return result
;);
1057 static int tonga_get_svi2_vdd_voltage_table(
1058 struct pp_hwmgr
*hwmgr
,
1059 phm_ppt_v1_voltage_lookup_table
*look_up_table
,
1060 pp_atomctrl_voltage_table
*voltage_table
)
1064 PP_ASSERT_WITH_CODE((0 != look_up_table
->count
),
1065 "Voltage Lookup Table empty.", return -1;);
1067 voltage_table
->mask_low
= 0;
1068 voltage_table
->phase_delay
= 0;
1070 voltage_table
->count
= look_up_table
->count
;
1072 for (i
= 0; i
< voltage_table
->count
; i
++) {
1073 voltage_table
->entries
[i
].value
= look_up_table
->entries
[i
].us_vdd
;
1074 voltage_table
->entries
[i
].smio_low
= 0;
1081 * -------------------------------------------------------- Voltage Tables --------------------------------------------------------------------------
1082 * If the voltage table would be bigger than what will fit into the state table on the SMC keep only the higher entries.
1085 static void tonga_trim_voltage_table_to_fit_state_table(
1086 struct pp_hwmgr
*hwmgr
,
1087 uint32_t max_voltage_steps
,
1088 pp_atomctrl_voltage_table
*voltage_table
)
1090 unsigned int i
, diff
;
1092 if (voltage_table
->count
<= max_voltage_steps
) {
1096 diff
= voltage_table
->count
- max_voltage_steps
;
1098 for (i
= 0; i
< max_voltage_steps
; i
++) {
1099 voltage_table
->entries
[i
] = voltage_table
->entries
[i
+ diff
];
1102 voltage_table
->count
= max_voltage_steps
;
1108 * Create Voltage Tables.
1110 * @param hwmgr the address of the powerplay hardware manager.
1113 int tonga_construct_voltage_tables(struct pp_hwmgr
*hwmgr
)
1115 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1116 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1119 /* MVDD has only GPIO voltage control */
1120 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1121 result
= atomctrl_get_voltage_table_v3(hwmgr
,
1122 VOLTAGE_TYPE_MVDDC
, VOLTAGE_OBJ_GPIO_LUT
, &(data
->mvdd_voltage_table
));
1123 PP_ASSERT_WITH_CODE((0 == result
),
1124 "Failed to retrieve MVDD table.", return result
;);
1127 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->vdd_ci_control
) {
1129 result
= atomctrl_get_voltage_table_v3(hwmgr
,
1130 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_GPIO_LUT
, &(data
->vddci_voltage_table
));
1131 PP_ASSERT_WITH_CODE((0 == result
),
1132 "Failed to retrieve VDDCI table.", return result
;);
1133 } else if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_ci_control
) {
1135 result
= tonga_get_svi2_vdd_ci_voltage_table(hwmgr
,
1136 pptable_info
->vdd_dep_on_mclk
);
1137 PP_ASSERT_WITH_CODE((0 == result
),
1138 "Failed to retrieve SVI2 VDDCI table from dependancy table.", return result
;);
1141 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_gfx_control
) {
1142 /* VDDGFX has only SVI2 voltage control */
1143 result
= tonga_get_svi2_vdd_voltage_table(hwmgr
,
1144 pptable_info
->vddgfx_lookup_table
, &(data
->vddgfx_voltage_table
));
1145 PP_ASSERT_WITH_CODE((0 == result
),
1146 "Failed to retrieve SVI2 VDDGFX table from lookup table.", return result
;);
1149 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1150 /* VDDC has only SVI2 voltage control */
1151 result
= tonga_get_svi2_vdd_voltage_table(hwmgr
,
1152 pptable_info
->vddc_lookup_table
, &(data
->vddc_voltage_table
));
1153 PP_ASSERT_WITH_CODE((0 == result
),
1154 "Failed to retrieve SVI2 VDDC table from lookup table.", return result
;);
1157 PP_ASSERT_WITH_CODE(
1158 (data
->vddc_voltage_table
.count
<= (SMU72_MAX_LEVELS_VDDC
)),
1159 "Too many voltage values for VDDC. Trimming to fit state table.",
1160 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1161 SMU72_MAX_LEVELS_VDDC
, &(data
->vddc_voltage_table
));
1164 PP_ASSERT_WITH_CODE(
1165 (data
->vddgfx_voltage_table
.count
<= (SMU72_MAX_LEVELS_VDDGFX
)),
1166 "Too many voltage values for VDDGFX. Trimming to fit state table.",
1167 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1168 SMU72_MAX_LEVELS_VDDGFX
, &(data
->vddgfx_voltage_table
));
1171 PP_ASSERT_WITH_CODE(
1172 (data
->vddci_voltage_table
.count
<= (SMU72_MAX_LEVELS_VDDCI
)),
1173 "Too many voltage values for VDDCI. Trimming to fit state table.",
1174 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1175 SMU72_MAX_LEVELS_VDDCI
, &(data
->vddci_voltage_table
));
1178 PP_ASSERT_WITH_CODE(
1179 (data
->mvdd_voltage_table
.count
<= (SMU72_MAX_LEVELS_MVDD
)),
1180 "Too many voltage values for MVDD. Trimming to fit state table.",
1181 tonga_trim_voltage_table_to_fit_state_table(hwmgr
,
1182 SMU72_MAX_LEVELS_MVDD
, &(data
->mvdd_voltage_table
));
1189 * Vddc table preparation for SMC.
1191 * @param hwmgr the address of the hardware manager
1192 * @param table the SMC DPM table structure to be populated
1195 static int tonga_populate_smc_vddc_table(struct pp_hwmgr
*hwmgr
,
1196 SMU72_Discrete_DpmTable
*table
)
1199 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1201 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1202 table
->VddcLevelCount
= data
->vddc_voltage_table
.count
;
1203 for (count
= 0; count
< table
->VddcLevelCount
; count
++) {
1204 table
->VddcTable
[count
] =
1205 PP_HOST_TO_SMC_US(data
->vddc_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1207 CONVERT_FROM_HOST_TO_SMC_UL(table
->VddcLevelCount
);
1213 * VddGfx table preparation for SMC.
1215 * @param hwmgr the address of the hardware manager
1216 * @param table the SMC DPM table structure to be populated
1219 static int tonga_populate_smc_vdd_gfx_table(struct pp_hwmgr
*hwmgr
,
1220 SMU72_Discrete_DpmTable
*table
)
1223 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1225 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_gfx_control
) {
1226 table
->VddGfxLevelCount
= data
->vddgfx_voltage_table
.count
;
1227 for (count
= 0; count
< data
->vddgfx_voltage_table
.count
; count
++) {
1228 table
->VddGfxTable
[count
] =
1229 PP_HOST_TO_SMC_US(data
->vddgfx_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1231 CONVERT_FROM_HOST_TO_SMC_UL(table
->VddGfxLevelCount
);
1237 * Vddci table preparation for SMC.
1239 * @param *hwmgr The address of the hardware manager.
1240 * @param *table The SMC DPM table structure to be populated.
1243 static int tonga_populate_smc_vdd_ci_table(struct pp_hwmgr
*hwmgr
,
1244 SMU72_Discrete_DpmTable
*table
)
1246 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1249 table
->VddciLevelCount
= data
->vddci_voltage_table
.count
;
1250 for (count
= 0; count
< table
->VddciLevelCount
; count
++) {
1251 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_ci_control
) {
1252 table
->VddciTable
[count
] =
1253 PP_HOST_TO_SMC_US(data
->vddci_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1254 } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->vdd_ci_control
) {
1255 table
->SmioTable1
.Pattern
[count
].Voltage
=
1256 PP_HOST_TO_SMC_US(data
->vddci_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1257 /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level. */
1258 table
->SmioTable1
.Pattern
[count
].Smio
=
1260 table
->Smio
[count
] |=
1261 data
->vddci_voltage_table
.entries
[count
].smio_low
;
1262 table
->VddciTable
[count
] =
1263 PP_HOST_TO_SMC_US(data
->vddci_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1267 table
->SmioMask1
= data
->vddci_voltage_table
.mask_low
;
1268 CONVERT_FROM_HOST_TO_SMC_UL(table
->VddciLevelCount
);
1274 * Mvdd table preparation for SMC.
1276 * @param *hwmgr The address of the hardware manager.
1277 * @param *table The SMC DPM table structure to be populated.
1280 static int tonga_populate_smc_mvdd_table(struct pp_hwmgr
*hwmgr
,
1281 SMU72_Discrete_DpmTable
*table
)
1283 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1286 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1287 table
->MvddLevelCount
= data
->mvdd_voltage_table
.count
;
1288 for (count
= 0; count
< table
->MvddLevelCount
; count
++) {
1289 table
->SmioTable2
.Pattern
[count
].Voltage
=
1290 PP_HOST_TO_SMC_US(data
->mvdd_voltage_table
.entries
[count
].value
* VOLTAGE_SCALE
);
1291 /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/
1292 table
->SmioTable2
.Pattern
[count
].Smio
=
1294 table
->Smio
[count
] |=
1295 data
->mvdd_voltage_table
.entries
[count
].smio_low
;
1297 table
->SmioMask2
= data
->vddci_voltage_table
.mask_low
;
1299 CONVERT_FROM_HOST_TO_SMC_UL(table
->MvddLevelCount
);
1306 * Convert a voltage value in mv unit to VID number required by SMU firmware
1308 static uint8_t convert_to_vid(uint16_t vddc
)
1310 return (uint8_t) ((6200 - (vddc
* VOLTAGE_SCALE
)) / 25);
1315 * Preparation of vddc and vddgfx CAC tables for SMC.
1317 * @param hwmgr the address of the hardware manager
1318 * @param table the SMC DPM table structure to be populated
1321 static int tonga_populate_cac_tables(struct pp_hwmgr
*hwmgr
,
1322 SMU72_Discrete_DpmTable
*table
)
1327 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1328 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1329 struct phm_ppt_v1_voltage_lookup_table
*vddgfx_lookup_table
= pptable_info
->vddgfx_lookup_table
;
1330 struct phm_ppt_v1_voltage_lookup_table
*vddc_lookup_table
= pptable_info
->vddc_lookup_table
;
1332 /* pTables is already swapped, so in order to use the value from it, we need to swap it back. */
1333 uint32_t vddcLevelCount
= PP_SMC_TO_HOST_UL(table
->VddcLevelCount
);
1334 uint32_t vddgfxLevelCount
= PP_SMC_TO_HOST_UL(table
->VddGfxLevelCount
);
1336 for (count
= 0; count
< vddcLevelCount
; count
++) {
1337 /* We are populating vddc CAC data to BapmVddc table in split and merged mode */
1338 index
= tonga_get_voltage_index(vddc_lookup_table
,
1339 data
->vddc_voltage_table
.entries
[count
].value
);
1340 table
->BapmVddcVidLoSidd
[count
] =
1341 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_low
);
1342 table
->BapmVddcVidHiSidd
[count
] =
1343 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_mid
);
1344 table
->BapmVddcVidHiSidd2
[count
] =
1345 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_high
);
1348 if ((data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
)) {
1349 /* We are populating vddgfx CAC data to BapmVddgfx table in split mode */
1350 for (count
= 0; count
< vddgfxLevelCount
; count
++) {
1351 index
= tonga_get_voltage_index(vddgfx_lookup_table
,
1352 data
->vddgfx_voltage_table
.entries
[count
].value
);
1353 table
->BapmVddGfxVidLoSidd
[count
] =
1354 convert_to_vid(vddgfx_lookup_table
->entries
[index
].us_cac_low
);
1355 table
->BapmVddGfxVidHiSidd
[count
] =
1356 convert_to_vid(vddgfx_lookup_table
->entries
[index
].us_cac_mid
);
1357 table
->BapmVddGfxVidHiSidd2
[count
] =
1358 convert_to_vid(vddgfx_lookup_table
->entries
[index
].us_cac_high
);
1361 for (count
= 0; count
< vddcLevelCount
; count
++) {
1362 index
= tonga_get_voltage_index(vddc_lookup_table
,
1363 data
->vddc_voltage_table
.entries
[count
].value
);
1364 table
->BapmVddGfxVidLoSidd
[count
] =
1365 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_low
);
1366 table
->BapmVddGfxVidHiSidd
[count
] =
1367 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_mid
);
1368 table
->BapmVddGfxVidHiSidd2
[count
] =
1369 convert_to_vid(vddc_lookup_table
->entries
[index
].us_cac_high
);
1378 * Preparation of voltage tables for SMC.
1380 * @param hwmgr the address of the hardware manager
1381 * @param table the SMC DPM table structure to be populated
1385 int tonga_populate_smc_voltage_tables(struct pp_hwmgr
*hwmgr
,
1386 SMU72_Discrete_DpmTable
*table
)
1390 result
= tonga_populate_smc_vddc_table(hwmgr
, table
);
1391 PP_ASSERT_WITH_CODE(0 == result
,
1392 "can not populate VDDC voltage table to SMC", return -1);
1394 result
= tonga_populate_smc_vdd_ci_table(hwmgr
, table
);
1395 PP_ASSERT_WITH_CODE(0 == result
,
1396 "can not populate VDDCI voltage table to SMC", return -1);
1398 result
= tonga_populate_smc_vdd_gfx_table(hwmgr
, table
);
1399 PP_ASSERT_WITH_CODE(0 == result
,
1400 "can not populate VDDGFX voltage table to SMC", return -1);
1402 result
= tonga_populate_smc_mvdd_table(hwmgr
, table
);
1403 PP_ASSERT_WITH_CODE(0 == result
,
1404 "can not populate MVDD voltage table to SMC", return -1);
1406 result
= tonga_populate_cac_tables(hwmgr
, table
);
1407 PP_ASSERT_WITH_CODE(0 == result
,
1408 "can not populate CAC voltage tables to SMC", return -1);
1414 * Populates the SMC VRConfig field in DPM table.
1416 * @param hwmgr the address of the hardware manager
1417 * @param table the SMC DPM table structure to be populated
1420 static int tonga_populate_vr_config(struct pp_hwmgr
*hwmgr
,
1421 SMU72_Discrete_DpmTable
*table
)
1423 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1426 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_gfx_control
) {
1428 config
= VR_SVI2_PLANE_1
;
1429 table
->VRConfig
|= (config
<<VRCONF_VDDGFX_SHIFT
);
1431 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1432 config
= VR_SVI2_PLANE_2
;
1433 table
->VRConfig
|= config
;
1435 printk(KERN_ERR
"[ powerplay ] VDDC and VDDGFX should be both on SVI2 control in splitted mode! \n");
1439 config
= VR_MERGED_WITH_VDDC
;
1440 table
->VRConfig
|= (config
<<VRCONF_VDDGFX_SHIFT
);
1442 /* Set Vddc Voltage Controller */
1443 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1444 config
= VR_SVI2_PLANE_1
;
1445 table
->VRConfig
|= config
;
1447 printk(KERN_ERR
"[ powerplay ] VDDC should be on SVI2 control in merged mode! \n");
1451 /* Set Vddci Voltage Controller */
1452 if (TONGA_VOLTAGE_CONTROL_BY_SVID2
== data
->vdd_ci_control
) {
1453 config
= VR_SVI2_PLANE_2
; /* only in merged mode */
1454 table
->VRConfig
|= (config
<<VRCONF_VDDCI_SHIFT
);
1455 } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->vdd_ci_control
) {
1456 config
= VR_SMIO_PATTERN_1
;
1457 table
->VRConfig
|= (config
<<VRCONF_VDDCI_SHIFT
);
1460 /* Set Mvdd Voltage Controller */
1461 if (TONGA_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1462 config
= VR_SMIO_PATTERN_2
;
1463 table
->VRConfig
|= (config
<<VRCONF_MVDD_SHIFT
);
1469 static int tonga_get_dependecy_volt_by_clk(struct pp_hwmgr
*hwmgr
,
1470 phm_ppt_v1_clock_voltage_dependency_table
*allowed_clock_voltage_table
,
1471 uint32_t clock
, SMU_VoltageLevel
*voltage
, uint32_t *mvdd
)
1474 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1475 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1477 /* clock - voltage dependency table is empty table */
1478 if (allowed_clock_voltage_table
->count
== 0)
1481 for (i
= 0; i
< allowed_clock_voltage_table
->count
; i
++) {
1482 /* find first sclk bigger than request */
1483 if (allowed_clock_voltage_table
->entries
[i
].clk
>= clock
) {
1484 voltage
->VddGfx
= tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1485 allowed_clock_voltage_table
->entries
[i
].vddgfx
);
1487 voltage
->Vddc
= tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1488 allowed_clock_voltage_table
->entries
[i
].vddc
);
1490 if (allowed_clock_voltage_table
->entries
[i
].vddci
) {
1491 voltage
->Vddci
= tonga_get_voltage_id(&data
->vddci_voltage_table
,
1492 allowed_clock_voltage_table
->entries
[i
].vddci
);
1494 voltage
->Vddci
= tonga_get_voltage_id(&data
->vddci_voltage_table
,
1495 allowed_clock_voltage_table
->entries
[i
].vddc
- data
->vddc_vddci_delta
);
1498 if (allowed_clock_voltage_table
->entries
[i
].mvdd
) {
1499 *mvdd
= (uint32_t) allowed_clock_voltage_table
->entries
[i
].mvdd
;
1502 voltage
->Phases
= 1;
1507 /* sclk is bigger than max sclk in the dependence table */
1508 voltage
->VddGfx
= tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1509 allowed_clock_voltage_table
->entries
[i
-1].vddgfx
);
1510 voltage
->Vddc
= tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1511 allowed_clock_voltage_table
->entries
[i
-1].vddc
);
1513 if (allowed_clock_voltage_table
->entries
[i
-1].vddci
) {
1514 voltage
->Vddci
= tonga_get_voltage_id(&data
->vddci_voltage_table
,
1515 allowed_clock_voltage_table
->entries
[i
-1].vddci
);
1517 if (allowed_clock_voltage_table
->entries
[i
-1].mvdd
) {
1518 *mvdd
= (uint32_t) allowed_clock_voltage_table
->entries
[i
-1].mvdd
;
1525 * Call SMC to reset S0/S1 to S1 and Reset SMIO to initial value
1527 * @param hwmgr the address of the powerplay hardware manager.
1530 int tonga_reset_to_default(struct pp_hwmgr
*hwmgr
)
1532 return (smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_ResetToDefaults
) == 0) ? 0 : 1;
1535 int tonga_populate_memory_timing_parameters(
1536 struct pp_hwmgr
*hwmgr
,
1537 uint32_t engine_clock
,
1538 uint32_t memory_clock
,
1539 struct SMU72_Discrete_MCArbDramTimingTableEntry
*arb_regs
1542 uint32_t dramTiming
;
1543 uint32_t dramTiming2
;
1547 result
= atomctrl_set_engine_dram_timings_rv770(hwmgr
,
1548 engine_clock
, memory_clock
);
1550 PP_ASSERT_WITH_CODE(result
== 0,
1551 "Error calling VBIOS to set DRAM_TIMING.", return result
);
1553 dramTiming
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
1554 dramTiming2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
1555 burstTime
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
);
1557 arb_regs
->McArbDramTiming
= PP_HOST_TO_SMC_UL(dramTiming
);
1558 arb_regs
->McArbDramTiming2
= PP_HOST_TO_SMC_UL(dramTiming2
);
1559 arb_regs
->McArbBurstTime
= (uint8_t)burstTime
;
1565 * Setup parameters for the MC ARB.
1567 * @param hwmgr the address of the powerplay hardware manager.
1569 * This function is to be called from the SetPowerState table.
1571 int tonga_program_memory_timing_parameters(struct pp_hwmgr
*hwmgr
)
1573 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1575 SMU72_Discrete_MCArbDramTimingTable arb_regs
;
1578 memset(&arb_regs
, 0x00, sizeof(SMU72_Discrete_MCArbDramTimingTable
));
1580 for (i
= 0; i
< data
->dpm_table
.sclk_table
.count
; i
++) {
1581 for (j
= 0; j
< data
->dpm_table
.mclk_table
.count
; j
++) {
1582 result
= tonga_populate_memory_timing_parameters
1583 (hwmgr
, data
->dpm_table
.sclk_table
.dpm_levels
[i
].value
,
1584 data
->dpm_table
.mclk_table
.dpm_levels
[j
].value
,
1585 &arb_regs
.entries
[i
][j
]);
1594 result
= tonga_copy_bytes_to_smc(
1596 data
->arb_table_start
,
1597 (uint8_t *)&arb_regs
,
1598 sizeof(SMU72_Discrete_MCArbDramTimingTable
),
1606 static int tonga_populate_smc_link_level(struct pp_hwmgr
*hwmgr
, SMU72_Discrete_DpmTable
*table
)
1608 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1609 struct tonga_dpm_table
*dpm_table
= &data
->dpm_table
;
1612 /* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */
1613 for (i
= 0; i
<= dpm_table
->pcie_speed_table
.count
; i
++) {
1614 table
->LinkLevel
[i
].PcieGenSpeed
=
1615 (uint8_t)dpm_table
->pcie_speed_table
.dpm_levels
[i
].value
;
1616 table
->LinkLevel
[i
].PcieLaneCount
=
1617 (uint8_t)encode_pcie_lane_width(dpm_table
->pcie_speed_table
.dpm_levels
[i
].param1
);
1618 table
->LinkLevel
[i
].EnabledForActivity
=
1620 table
->LinkLevel
[i
].SPC
=
1621 (uint8_t)(data
->pcie_spc_cap
& 0xff);
1622 table
->LinkLevel
[i
].DownThreshold
=
1623 PP_HOST_TO_SMC_UL(5);
1624 table
->LinkLevel
[i
].UpThreshold
=
1625 PP_HOST_TO_SMC_UL(30);
1628 data
->smc_state_table
.LinkLevelCount
=
1629 (uint8_t)dpm_table
->pcie_speed_table
.count
;
1630 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
=
1631 tonga_get_dpm_level_enable_mask_value(&dpm_table
->pcie_speed_table
);
1637 static int tonga_populate_smc_vce_level(struct pp_hwmgr
*hwmgr
,
1638 SMU72_Discrete_DpmTable
*table
)
1643 pp_atomctrl_clock_dividers_vi dividers
;
1644 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1645 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1646 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1648 table
->VceLevelCount
= (uint8_t) (mm_table
->count
);
1649 table
->VceBootLevel
= 0;
1651 for (count
= 0; count
< table
->VceLevelCount
; count
++) {
1652 table
->VceLevel
[count
].Frequency
=
1653 mm_table
->entries
[count
].eclk
;
1654 table
->VceLevel
[count
].MinVoltage
.Vddc
=
1655 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1656 mm_table
->entries
[count
].vddc
);
1657 table
->VceLevel
[count
].MinVoltage
.VddGfx
=
1658 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1659 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1660 mm_table
->entries
[count
].vddgfx
) : 0;
1661 table
->VceLevel
[count
].MinVoltage
.Vddci
=
1662 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1663 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1664 table
->VceLevel
[count
].MinVoltage
.Phases
= 1;
1666 /* retrieve divider value for VBIOS */
1667 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1668 table
->VceLevel
[count
].Frequency
, ÷rs
);
1669 PP_ASSERT_WITH_CODE((0 == result
),
1670 "can not find divide id for VCE engine clock", return result
);
1672 table
->VceLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1674 CONVERT_FROM_HOST_TO_SMC_UL(table
->VceLevel
[count
].Frequency
);
1680 static int tonga_populate_smc_acp_level(struct pp_hwmgr
*hwmgr
,
1681 SMU72_Discrete_DpmTable
*table
)
1685 pp_atomctrl_clock_dividers_vi dividers
;
1686 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1687 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1688 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1690 table
->AcpLevelCount
= (uint8_t) (mm_table
->count
);
1691 table
->AcpBootLevel
= 0;
1693 for (count
= 0; count
< table
->AcpLevelCount
; count
++) {
1694 table
->AcpLevel
[count
].Frequency
=
1695 pptable_info
->mm_dep_table
->entries
[count
].aclk
;
1696 table
->AcpLevel
[count
].MinVoltage
.Vddc
=
1697 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1698 mm_table
->entries
[count
].vddc
);
1699 table
->AcpLevel
[count
].MinVoltage
.VddGfx
=
1700 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1701 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1702 mm_table
->entries
[count
].vddgfx
) : 0;
1703 table
->AcpLevel
[count
].MinVoltage
.Vddci
=
1704 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1705 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1706 table
->AcpLevel
[count
].MinVoltage
.Phases
= 1;
1708 /* retrieve divider value for VBIOS */
1709 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1710 table
->AcpLevel
[count
].Frequency
, ÷rs
);
1711 PP_ASSERT_WITH_CODE((0 == result
),
1712 "can not find divide id for engine clock", return result
);
1714 table
->AcpLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1716 CONVERT_FROM_HOST_TO_SMC_UL(table
->AcpLevel
[count
].Frequency
);
1722 static int tonga_populate_smc_samu_level(struct pp_hwmgr
*hwmgr
,
1723 SMU72_Discrete_DpmTable
*table
)
1727 pp_atomctrl_clock_dividers_vi dividers
;
1728 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1729 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1730 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
1732 table
->SamuBootLevel
= 0;
1733 table
->SamuLevelCount
= (uint8_t) (mm_table
->count
);
1735 for (count
= 0; count
< table
->SamuLevelCount
; count
++) {
1736 /* not sure whether we need evclk or not */
1737 table
->SamuLevel
[count
].Frequency
=
1738 pptable_info
->mm_dep_table
->entries
[count
].samclock
;
1739 table
->SamuLevel
[count
].MinVoltage
.Vddc
=
1740 tonga_get_voltage_index(pptable_info
->vddc_lookup_table
,
1741 mm_table
->entries
[count
].vddc
);
1742 table
->SamuLevel
[count
].MinVoltage
.VddGfx
=
1743 (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) ?
1744 tonga_get_voltage_index(pptable_info
->vddgfx_lookup_table
,
1745 mm_table
->entries
[count
].vddgfx
) : 0;
1746 table
->SamuLevel
[count
].MinVoltage
.Vddci
=
1747 tonga_get_voltage_id(&data
->vddci_voltage_table
,
1748 mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
);
1749 table
->SamuLevel
[count
].MinVoltage
.Phases
= 1;
1751 /* retrieve divider value for VBIOS */
1752 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1753 table
->SamuLevel
[count
].Frequency
, ÷rs
);
1754 PP_ASSERT_WITH_CODE((0 == result
),
1755 "can not find divide id for samu clock", return result
);
1757 table
->SamuLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1759 CONVERT_FROM_HOST_TO_SMC_UL(table
->SamuLevel
[count
].Frequency
);
1766 * Populates the SMC MCLK structure using the provided memory clock
1768 * @param hwmgr the address of the hardware manager
1769 * @param memory_clock the memory clock to use to populate the structure
1770 * @param sclk the SMC SCLK structure to be populated
1772 static int tonga_calculate_mclk_params(
1773 struct pp_hwmgr
*hwmgr
,
1774 uint32_t memory_clock
,
1775 SMU72_Discrete_MemoryLevel
*mclk
,
1780 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1781 uint32_t dll_cntl
= data
->clock_registers
.vDLL_CNTL
;
1782 uint32_t mclk_pwrmgt_cntl
= data
->clock_registers
.vMCLK_PWRMGT_CNTL
;
1783 uint32_t mpll_ad_func_cntl
= data
->clock_registers
.vMPLL_AD_FUNC_CNTL
;
1784 uint32_t mpll_dq_func_cntl
= data
->clock_registers
.vMPLL_DQ_FUNC_CNTL
;
1785 uint32_t mpll_func_cntl
= data
->clock_registers
.vMPLL_FUNC_CNTL
;
1786 uint32_t mpll_func_cntl_1
= data
->clock_registers
.vMPLL_FUNC_CNTL_1
;
1787 uint32_t mpll_func_cntl_2
= data
->clock_registers
.vMPLL_FUNC_CNTL_2
;
1788 uint32_t mpll_ss1
= data
->clock_registers
.vMPLL_SS1
;
1789 uint32_t mpll_ss2
= data
->clock_registers
.vMPLL_SS2
;
1791 pp_atomctrl_memory_clock_param mpll_param
;
1794 result
= atomctrl_get_memory_pll_dividers_si(hwmgr
,
1795 memory_clock
, &mpll_param
, strobe_mode
);
1796 PP_ASSERT_WITH_CODE(0 == result
,
1797 "Error retrieving Memory Clock Parameters from VBIOS.", return result
);
1799 /* MPLL_FUNC_CNTL setup*/
1800 mpll_func_cntl
= PHM_SET_FIELD(mpll_func_cntl
, MPLL_FUNC_CNTL
, BWCTRL
, mpll_param
.bw_ctrl
);
1802 /* MPLL_FUNC_CNTL_1 setup*/
1803 mpll_func_cntl_1
= PHM_SET_FIELD(mpll_func_cntl_1
,
1804 MPLL_FUNC_CNTL_1
, CLKF
, mpll_param
.mpll_fb_divider
.cl_kf
);
1805 mpll_func_cntl_1
= PHM_SET_FIELD(mpll_func_cntl_1
,
1806 MPLL_FUNC_CNTL_1
, CLKFRAC
, mpll_param
.mpll_fb_divider
.clk_frac
);
1807 mpll_func_cntl_1
= PHM_SET_FIELD(mpll_func_cntl_1
,
1808 MPLL_FUNC_CNTL_1
, VCO_MODE
, mpll_param
.vco_mode
);
1810 /* MPLL_AD_FUNC_CNTL setup*/
1811 mpll_ad_func_cntl
= PHM_SET_FIELD(mpll_ad_func_cntl
,
1812 MPLL_AD_FUNC_CNTL
, YCLK_POST_DIV
, mpll_param
.mpll_post_divider
);
1814 if (data
->is_memory_GDDR5
) {
1815 /* MPLL_DQ_FUNC_CNTL setup*/
1816 mpll_dq_func_cntl
= PHM_SET_FIELD(mpll_dq_func_cntl
,
1817 MPLL_DQ_FUNC_CNTL
, YCLK_SEL
, mpll_param
.yclk_sel
);
1818 mpll_dq_func_cntl
= PHM_SET_FIELD(mpll_dq_func_cntl
,
1819 MPLL_DQ_FUNC_CNTL
, YCLK_POST_DIV
, mpll_param
.mpll_post_divider
);
1822 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
1823 PHM_PlatformCaps_MemorySpreadSpectrumSupport
)) {
1825 ************************************
1826 Fref = Reference Frequency
1827 NF = Feedback divider ratio
1828 NR = Reference divider ratio
1829 Fnom = Nominal VCO output frequency = Fref * NF / NR
1831 D = Percentage down-spread / 2
1832 Fint = Reference input frequency to PFD = Fref / NR
1833 NS = Spreading rate divider ratio = int(Fint / (2 * Fs))
1834 CLKS = NS - 1 = ISS_STEP_NUM[11:0]
1835 NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2)
1836 CLKV = 65536 * NV = ISS_STEP_SIZE[25:0]
1837 *************************************
1839 pp_atomctrl_internal_ss_info ss_info
;
1842 uint32_t reference_clock
= atomctrl_get_mpll_reference_clock(hwmgr
);
1844 /* for GDDR5 for all modes and DDR3 */
1845 if (1 == mpll_param
.qdr
)
1846 freq_nom
= memory_clock
* 4 * (1 << mpll_param
.mpll_post_divider
);
1848 freq_nom
= memory_clock
* 2 * (1 << mpll_param
.mpll_post_divider
);
1850 /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2 Note: S.I. reference_divider = 1*/
1851 tmp
= (freq_nom
/ reference_clock
);
1854 if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr
, freq_nom
, &ss_info
)) {
1855 /* ss_info.speed_spectrum_percentage -- in unit of 0.01% */
1856 /* ss.Info.speed_spectrum_rate -- in unit of khz */
1857 /* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */
1858 /* = reference_clock * 5 / speed_spectrum_rate */
1859 uint32_t clks
= reference_clock
* 5 / ss_info
.speed_spectrum_rate
;
1861 /* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */
1862 /* = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */
1864 (uint32_t)((((131 * ss_info
.speed_spectrum_percentage
*
1865 ss_info
.speed_spectrum_rate
) / 100) * tmp
) / freq_nom
);
1867 mpll_ss1
= PHM_SET_FIELD(mpll_ss1
, MPLL_SS1
, CLKV
, clkv
);
1868 mpll_ss2
= PHM_SET_FIELD(mpll_ss2
, MPLL_SS2
, CLKS
, clks
);
1872 /* MCLK_PWRMGT_CNTL setup */
1873 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
1874 MCLK_PWRMGT_CNTL
, DLL_SPEED
, mpll_param
.dll_speed
);
1875 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
1876 MCLK_PWRMGT_CNTL
, MRDCK0_PDNB
, dllStateOn
);
1877 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
1878 MCLK_PWRMGT_CNTL
, MRDCK1_PDNB
, dllStateOn
);
1881 /* Save the result data to outpupt memory level structure */
1882 mclk
->MclkFrequency
= memory_clock
;
1883 mclk
->MpllFuncCntl
= mpll_func_cntl
;
1884 mclk
->MpllFuncCntl_1
= mpll_func_cntl_1
;
1885 mclk
->MpllFuncCntl_2
= mpll_func_cntl_2
;
1886 mclk
->MpllAdFuncCntl
= mpll_ad_func_cntl
;
1887 mclk
->MpllDqFuncCntl
= mpll_dq_func_cntl
;
1888 mclk
->MclkPwrmgtCntl
= mclk_pwrmgt_cntl
;
1889 mclk
->DllCntl
= dll_cntl
;
1890 mclk
->MpllSs1
= mpll_ss1
;
1891 mclk
->MpllSs2
= mpll_ss2
;
1896 static uint8_t tonga_get_mclk_frequency_ratio(uint32_t memory_clock
,
1899 uint8_t mc_para_index
;
1902 if (memory_clock
< 12500) {
1903 mc_para_index
= 0x00;
1904 } else if (memory_clock
> 47500) {
1905 mc_para_index
= 0x0f;
1907 mc_para_index
= (uint8_t)((memory_clock
- 10000) / 2500);
1910 if (memory_clock
< 65000) {
1911 mc_para_index
= 0x00;
1912 } else if (memory_clock
> 135000) {
1913 mc_para_index
= 0x0f;
1915 mc_para_index
= (uint8_t)((memory_clock
- 60000) / 5000);
1919 return mc_para_index
;
1922 static uint8_t tonga_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock
)
1924 uint8_t mc_para_index
;
1926 if (memory_clock
< 10000) {
1928 } else if (memory_clock
>= 80000) {
1929 mc_para_index
= 0x0f;
1931 mc_para_index
= (uint8_t)((memory_clock
- 10000) / 5000 + 1);
1934 return mc_para_index
;
1937 static int tonga_populate_single_memory_level(
1938 struct pp_hwmgr
*hwmgr
,
1939 uint32_t memory_clock
,
1940 SMU72_Discrete_MemoryLevel
*memory_level
1943 uint32_t minMvdd
= 0;
1944 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
1945 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1948 struct cgs_display_info info
= {0};
1951 if (NULL
!= pptable_info
->vdd_dep_on_mclk
) {
1952 result
= tonga_get_dependecy_volt_by_clk(hwmgr
,
1953 pptable_info
->vdd_dep_on_mclk
, memory_clock
, &memory_level
->MinVoltage
, &minMvdd
);
1954 PP_ASSERT_WITH_CODE((0 == result
),
1955 "can not find MinVddc voltage value from memory VDDC voltage dependency table", return result
);
1958 if (data
->mvdd_control
== TONGA_VOLTAGE_CONTROL_NONE
) {
1959 memory_level
->MinMvdd
= data
->vbios_boot_state
.mvdd_bootup_value
;
1961 memory_level
->MinMvdd
= minMvdd
;
1963 memory_level
->EnabledForThrottle
= 1;
1964 memory_level
->EnabledForActivity
= 0;
1965 memory_level
->UpHyst
= 0;
1966 memory_level
->DownHyst
= 100;
1967 memory_level
->VoltageDownHyst
= 0;
1969 /* Indicates maximum activity level for this performance level.*/
1970 memory_level
->ActivityLevel
= (uint16_t)data
->mclk_activity_target
;
1971 memory_level
->StutterEnable
= 0;
1972 memory_level
->StrobeEnable
= 0;
1973 memory_level
->EdcReadEnable
= 0;
1974 memory_level
->EdcWriteEnable
= 0;
1975 memory_level
->RttEnable
= 0;
1977 /* default set to low watermark. Highest level will be set to high later.*/
1978 memory_level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
1980 cgs_get_active_displays_info(hwmgr
->device
, &info
);
1981 data
->display_timing
.num_existing_displays
= info
.display_count
;
1983 if ((data
->mclk_stutter_mode_threshold
!= 0) &&
1984 (memory_clock
<= data
->mclk_stutter_mode_threshold
) &&
1985 (data
->is_uvd_enabled
== 0)
1987 && (PHM_READ_FIELD(hwmgr
->device
, DPG_PIPE_STUTTER_CONTROL
, STUTTER_ENABLE
) & 0x1)
1988 && (data
->display_timing
.num_existing_displays
<= 2)
1989 && (data
->display_timing
.num_existing_displays
!= 0)
1992 memory_level
->StutterEnable
= 1;
1994 /* decide strobe mode*/
1995 memory_level
->StrobeEnable
= (data
->mclk_strobe_mode_threshold
!= 0) &&
1996 (memory_clock
<= data
->mclk_strobe_mode_threshold
);
1998 /* decide EDC mode and memory clock ratio*/
1999 if (data
->is_memory_GDDR5
) {
2000 memory_level
->StrobeRatio
= tonga_get_mclk_frequency_ratio(memory_clock
,
2001 memory_level
->StrobeEnable
);
2003 if ((data
->mclk_edc_enable_threshold
!= 0) &&
2004 (memory_clock
> data
->mclk_edc_enable_threshold
)) {
2005 memory_level
->EdcReadEnable
= 1;
2008 if ((data
->mclk_edc_wr_enable_threshold
!= 0) &&
2009 (memory_clock
> data
->mclk_edc_wr_enable_threshold
)) {
2010 memory_level
->EdcWriteEnable
= 1;
2013 if (memory_level
->StrobeEnable
) {
2014 if (tonga_get_mclk_frequency_ratio(memory_clock
, 1) >=
2015 ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC7
) >> 16) & 0xf)) {
2016 dllStateOn
= ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC5
) >> 1) & 0x1) ? 1 : 0;
2018 dllStateOn
= ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC6
) >> 1) & 0x1) ? 1 : 0;
2022 dllStateOn
= data
->dll_defaule_on
;
2025 memory_level
->StrobeRatio
=
2026 tonga_get_ddr3_mclk_frequency_ratio(memory_clock
);
2027 dllStateOn
= ((cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC5
) >> 1) & 0x1) ? 1 : 0;
2030 result
= tonga_calculate_mclk_params(hwmgr
,
2031 memory_clock
, memory_level
, memory_level
->StrobeEnable
, dllStateOn
);
2034 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MinMvdd
);
2035 /* MCLK frequency in units of 10KHz*/
2036 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MclkFrequency
);
2037 /* Indicates maximum activity level for this performance level.*/
2038 CONVERT_FROM_HOST_TO_SMC_US(memory_level
->ActivityLevel
);
2039 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllFuncCntl
);
2040 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllFuncCntl_1
);
2041 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllFuncCntl_2
);
2042 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllAdFuncCntl
);
2043 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllDqFuncCntl
);
2044 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MclkPwrmgtCntl
);
2045 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->DllCntl
);
2046 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllSs1
);
2047 CONVERT_FROM_HOST_TO_SMC_UL(memory_level
->MpllSs2
);
2054 * Populates the SMC MVDD structure using the provided memory clock.
2056 * @param hwmgr the address of the hardware manager
2057 * @param mclk the MCLK value to be used in the decision if MVDD should be high or low.
2058 * @param voltage the SMC VOLTAGE structure to be populated
2060 int tonga_populate_mvdd_value(struct pp_hwmgr
*hwmgr
, uint32_t mclk
, SMIO_Pattern
*smio_pattern
)
2062 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2063 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2066 if (TONGA_VOLTAGE_CONTROL_NONE
!= data
->mvdd_control
) {
2067 /* find mvdd value which clock is more than request */
2068 for (i
= 0; i
< pptable_info
->vdd_dep_on_mclk
->count
; i
++) {
2069 if (mclk
<= pptable_info
->vdd_dep_on_mclk
->entries
[i
].clk
) {
2070 /* Always round to higher voltage. */
2071 smio_pattern
->Voltage
= data
->mvdd_voltage_table
.entries
[i
].value
;
2076 PP_ASSERT_WITH_CODE(i
< pptable_info
->vdd_dep_on_mclk
->count
,
2077 "MVDD Voltage is outside the supported range.", return -1);
2087 static int tonga_populate_smv_acpi_level(struct pp_hwmgr
*hwmgr
,
2088 SMU72_Discrete_DpmTable
*table
)
2091 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2092 pp_atomctrl_clock_dividers_vi dividers
;
2093 SMIO_Pattern voltage_level
;
2094 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
2095 uint32_t spll_func_cntl_2
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
;
2096 uint32_t dll_cntl
= data
->clock_registers
.vDLL_CNTL
;
2097 uint32_t mclk_pwrmgt_cntl
= data
->clock_registers
.vMCLK_PWRMGT_CNTL
;
2099 /* The ACPI state should not do DPM on DC (or ever).*/
2100 table
->ACPILevel
.Flags
&= ~PPSMC_SWSTATE_FLAG_DC
;
2102 table
->ACPILevel
.MinVoltage
= data
->smc_state_table
.GraphicsLevel
[0].MinVoltage
;
2104 /* assign zero for now*/
2105 table
->ACPILevel
.SclkFrequency
= atomctrl_get_reference_clock(hwmgr
);
2107 /* get the engine clock dividers for this clock value*/
2108 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
,
2109 table
->ACPILevel
.SclkFrequency
, ÷rs
);
2111 PP_ASSERT_WITH_CODE(result
== 0,
2112 "Error retrieving Engine Clock dividers from VBIOS.", return result
);
2114 /* divider ID for required SCLK*/
2115 table
->ACPILevel
.SclkDid
= (uint8_t)dividers
.pll_post_divider
;
2116 table
->ACPILevel
.DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2117 table
->ACPILevel
.DeepSleepDivId
= 0;
2119 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2120 CG_SPLL_FUNC_CNTL
, SPLL_PWRON
, 0);
2121 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2122 CG_SPLL_FUNC_CNTL
, SPLL_RESET
, 1);
2123 spll_func_cntl_2
= PHM_SET_FIELD(spll_func_cntl_2
,
2124 CG_SPLL_FUNC_CNTL_2
, SCLK_MUX_SEL
, 4);
2126 table
->ACPILevel
.CgSpllFuncCntl
= spll_func_cntl
;
2127 table
->ACPILevel
.CgSpllFuncCntl2
= spll_func_cntl_2
;
2128 table
->ACPILevel
.CgSpllFuncCntl3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
2129 table
->ACPILevel
.CgSpllFuncCntl4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
2130 table
->ACPILevel
.SpllSpreadSpectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
2131 table
->ACPILevel
.SpllSpreadSpectrum2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
2132 table
->ACPILevel
.CcPwrDynRm
= 0;
2133 table
->ACPILevel
.CcPwrDynRm1
= 0;
2136 /* For various features to be enabled/disabled while this level is active.*/
2137 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.Flags
);
2138 /* SCLK frequency in units of 10KHz*/
2139 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SclkFrequency
);
2140 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl
);
2141 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl2
);
2142 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl3
);
2143 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl4
);
2144 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum
);
2145 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum2
);
2146 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm
);
2147 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm1
);
2149 /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
2150 table
->MemoryACPILevel
.MinVoltage
= data
->smc_state_table
.MemoryLevel
[0].MinVoltage
;
2152 /* CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);*/
2154 if (0 == tonga_populate_mvdd_value(hwmgr
, 0, &voltage_level
))
2155 table
->MemoryACPILevel
.MinMvdd
=
2156 PP_HOST_TO_SMC_UL(voltage_level
.Voltage
* VOLTAGE_SCALE
);
2158 table
->MemoryACPILevel
.MinMvdd
= 0;
2160 /* Force reset on DLL*/
2161 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2162 MCLK_PWRMGT_CNTL
, MRDCK0_RESET
, 0x1);
2163 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2164 MCLK_PWRMGT_CNTL
, MRDCK1_RESET
, 0x1);
2166 /* Disable DLL in ACPIState*/
2167 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2168 MCLK_PWRMGT_CNTL
, MRDCK0_PDNB
, 0);
2169 mclk_pwrmgt_cntl
= PHM_SET_FIELD(mclk_pwrmgt_cntl
,
2170 MCLK_PWRMGT_CNTL
, MRDCK1_PDNB
, 0);
2172 /* Enable DLL bypass signal*/
2173 dll_cntl
= PHM_SET_FIELD(dll_cntl
,
2174 DLL_CNTL
, MRDCK0_BYPASS
, 0);
2175 dll_cntl
= PHM_SET_FIELD(dll_cntl
,
2176 DLL_CNTL
, MRDCK1_BYPASS
, 0);
2178 table
->MemoryACPILevel
.DllCntl
=
2179 PP_HOST_TO_SMC_UL(dll_cntl
);
2180 table
->MemoryACPILevel
.MclkPwrmgtCntl
=
2181 PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl
);
2182 table
->MemoryACPILevel
.MpllAdFuncCntl
=
2183 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_AD_FUNC_CNTL
);
2184 table
->MemoryACPILevel
.MpllDqFuncCntl
=
2185 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_DQ_FUNC_CNTL
);
2186 table
->MemoryACPILevel
.MpllFuncCntl
=
2187 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_FUNC_CNTL
);
2188 table
->MemoryACPILevel
.MpllFuncCntl_1
=
2189 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_FUNC_CNTL_1
);
2190 table
->MemoryACPILevel
.MpllFuncCntl_2
=
2191 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_FUNC_CNTL_2
);
2192 table
->MemoryACPILevel
.MpllSs1
=
2193 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_SS1
);
2194 table
->MemoryACPILevel
.MpllSs2
=
2195 PP_HOST_TO_SMC_UL(data
->clock_registers
.vMPLL_SS2
);
2197 table
->MemoryACPILevel
.EnabledForThrottle
= 0;
2198 table
->MemoryACPILevel
.EnabledForActivity
= 0;
2199 table
->MemoryACPILevel
.UpHyst
= 0;
2200 table
->MemoryACPILevel
.DownHyst
= 100;
2201 table
->MemoryACPILevel
.VoltageDownHyst
= 0;
2202 /* Indicates maximum activity level for this performance level.*/
2203 table
->MemoryACPILevel
.ActivityLevel
= PP_HOST_TO_SMC_US((uint16_t)data
->mclk_activity_target
);
2205 table
->MemoryACPILevel
.StutterEnable
= 0;
2206 table
->MemoryACPILevel
.StrobeEnable
= 0;
2207 table
->MemoryACPILevel
.EdcReadEnable
= 0;
2208 table
->MemoryACPILevel
.EdcWriteEnable
= 0;
2209 table
->MemoryACPILevel
.RttEnable
= 0;
2214 static int tonga_find_boot_level(struct tonga_single_dpm_table
*table
, uint32_t value
, uint32_t *boot_level
)
2219 for (i
= 0; i
< table
->count
; i
++) {
2220 if (value
== table
->dpm_levels
[i
].value
) {
2228 static int tonga_populate_smc_boot_level(struct pp_hwmgr
*hwmgr
,
2229 SMU72_Discrete_DpmTable
*table
)
2232 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2234 table
->GraphicsBootLevel
= 0; /* 0 == DPM[0] (low), etc. */
2235 table
->MemoryBootLevel
= 0; /* 0 == DPM[0] (low), etc. */
2237 /* find boot level from dpm table*/
2238 result
= tonga_find_boot_level(&(data
->dpm_table
.sclk_table
),
2239 data
->vbios_boot_state
.sclk_bootup_value
,
2240 (uint32_t *)&(data
->smc_state_table
.GraphicsBootLevel
));
2243 data
->smc_state_table
.GraphicsBootLevel
= 0;
2244 printk(KERN_ERR
"[ powerplay ] VBIOS did not find boot engine clock value \
2245 in dependency table. Using Graphics DPM level 0!");
2249 result
= tonga_find_boot_level(&(data
->dpm_table
.mclk_table
),
2250 data
->vbios_boot_state
.mclk_bootup_value
,
2251 (uint32_t *)&(data
->smc_state_table
.MemoryBootLevel
));
2254 data
->smc_state_table
.MemoryBootLevel
= 0;
2255 printk(KERN_ERR
"[ powerplay ] VBIOS did not find boot engine clock value \
2256 in dependency table. Using Memory DPM level 0!");
2260 table
->BootVoltage
.Vddc
=
2261 tonga_get_voltage_id(&(data
->vddc_voltage_table
),
2262 data
->vbios_boot_state
.vddc_bootup_value
);
2263 table
->BootVoltage
.VddGfx
=
2264 tonga_get_voltage_id(&(data
->vddgfx_voltage_table
),
2265 data
->vbios_boot_state
.vddgfx_bootup_value
);
2266 table
->BootVoltage
.Vddci
=
2267 tonga_get_voltage_id(&(data
->vddci_voltage_table
),
2268 data
->vbios_boot_state
.vddci_bootup_value
);
2269 table
->BootMVdd
= data
->vbios_boot_state
.mvdd_bootup_value
;
2271 CONVERT_FROM_HOST_TO_SMC_US(table
->BootMVdd
);
2278 * Calculates the SCLK dividers using the provided engine clock
2280 * @param hwmgr the address of the hardware manager
2281 * @param engine_clock the engine clock to use to populate the structure
2282 * @param sclk the SMC SCLK structure to be populated
2284 int tonga_calculate_sclk_params(struct pp_hwmgr
*hwmgr
,
2285 uint32_t engine_clock
, SMU72_Discrete_GraphicsLevel
*sclk
)
2287 const tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2288 pp_atomctrl_clock_dividers_vi dividers
;
2289 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
2290 uint32_t spll_func_cntl_3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
2291 uint32_t spll_func_cntl_4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
2292 uint32_t cg_spll_spread_spectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
2293 uint32_t cg_spll_spread_spectrum_2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
2294 uint32_t reference_clock
;
2295 uint32_t reference_divider
;
2299 /* get the engine clock dividers for this clock value*/
2300 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
, engine_clock
, ÷rs
);
2302 PP_ASSERT_WITH_CODE(result
== 0,
2303 "Error retrieving Engine Clock dividers from VBIOS.", return result
);
2305 /* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/
2306 reference_clock
= atomctrl_get_reference_clock(hwmgr
);
2308 reference_divider
= 1 + dividers
.uc_pll_ref_div
;
2310 /* low 14 bits is fraction and high 12 bits is divider*/
2311 fbdiv
= dividers
.ul_fb_div
.ul_fb_divider
& 0x3FFFFFF;
2313 /* SPLL_FUNC_CNTL setup*/
2314 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2315 CG_SPLL_FUNC_CNTL
, SPLL_REF_DIV
, dividers
.uc_pll_ref_div
);
2316 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
,
2317 CG_SPLL_FUNC_CNTL
, SPLL_PDIV_A
, dividers
.uc_pll_post_div
);
2319 /* SPLL_FUNC_CNTL_3 setup*/
2320 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
,
2321 CG_SPLL_FUNC_CNTL_3
, SPLL_FB_DIV
, fbdiv
);
2323 /* set to use fractional accumulation*/
2324 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
,
2325 CG_SPLL_FUNC_CNTL_3
, SPLL_DITHEN
, 1);
2327 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2328 PHM_PlatformCaps_EngineSpreadSpectrumSupport
)) {
2329 pp_atomctrl_internal_ss_info ss_info
;
2331 uint32_t vcoFreq
= engine_clock
* dividers
.uc_pll_post_div
;
2332 if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr
, vcoFreq
, &ss_info
)) {
2334 * ss_info.speed_spectrum_percentage -- in unit of 0.01%
2335 * ss_info.speed_spectrum_rate -- in unit of khz
2337 /* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */
2338 uint32_t clkS
= reference_clock
* 5 / (reference_divider
* ss_info
.speed_spectrum_rate
);
2340 /* clkv = 2 * D * fbdiv / NS */
2341 uint32_t clkV
= 4 * ss_info
.speed_spectrum_percentage
* fbdiv
/ (clkS
* 10000);
2343 cg_spll_spread_spectrum
=
2344 PHM_SET_FIELD(cg_spll_spread_spectrum
, CG_SPLL_SPREAD_SPECTRUM
, CLKS
, clkS
);
2345 cg_spll_spread_spectrum
=
2346 PHM_SET_FIELD(cg_spll_spread_spectrum
, CG_SPLL_SPREAD_SPECTRUM
, SSEN
, 1);
2347 cg_spll_spread_spectrum_2
=
2348 PHM_SET_FIELD(cg_spll_spread_spectrum_2
, CG_SPLL_SPREAD_SPECTRUM_2
, CLKV
, clkV
);
2352 sclk
->SclkFrequency
= engine_clock
;
2353 sclk
->CgSpllFuncCntl3
= spll_func_cntl_3
;
2354 sclk
->CgSpllFuncCntl4
= spll_func_cntl_4
;
2355 sclk
->SpllSpreadSpectrum
= cg_spll_spread_spectrum
;
2356 sclk
->SpllSpreadSpectrum2
= cg_spll_spread_spectrum_2
;
2357 sclk
->SclkDid
= (uint8_t)dividers
.pll_post_divider
;
2363 * Populates single SMC SCLK structure using the provided engine clock
2365 * @param hwmgr the address of the hardware manager
2366 * @param engine_clock the engine clock to use to populate the structure
2367 * @param sclk the SMC SCLK structure to be populated
2369 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
)
2374 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2375 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2377 result
= tonga_calculate_sclk_params(hwmgr
, engine_clock
, graphic_level
);
2380 /* populate graphics levels*/
2381 result
= tonga_get_dependecy_volt_by_clk(hwmgr
,
2382 pptable_info
->vdd_dep_on_sclk
, engine_clock
,
2383 &graphic_level
->MinVoltage
, &mvdd
);
2384 PP_ASSERT_WITH_CODE((0 == result
),
2385 "can not find VDDC voltage value for VDDC \
2386 engine clock dependency table", return result
);
2388 /* SCLK frequency in units of 10KHz*/
2389 graphic_level
->SclkFrequency
= engine_clock
;
2391 /* Indicates maximum activity level for this performance level. 50% for now*/
2392 graphic_level
->ActivityLevel
= sclk_activity_level_threshold
;
2394 graphic_level
->CcPwrDynRm
= 0;
2395 graphic_level
->CcPwrDynRm1
= 0;
2396 /* this level can be used if activity is high enough.*/
2397 graphic_level
->EnabledForActivity
= 0;
2398 /* this level can be used for throttling.*/
2399 graphic_level
->EnabledForThrottle
= 1;
2400 graphic_level
->UpHyst
= 0;
2401 graphic_level
->DownHyst
= 0;
2402 graphic_level
->VoltageDownHyst
= 0;
2403 graphic_level
->PowerThrottle
= 0;
2405 threshold
= engine_clock
* data
->fast_watemark_threshold
/ 100;
2407 *get the DAL clock. do it in funture.
2408 PECI_GetMinClockSettings(hwmgr->peci, &minClocks);
2409 data->display_timing.min_clock_insr = minClocks.engineClockInSR;
2411 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
2413 graphic_level->DeepSleepDivId = PhwTonga_GetSleepDividerIdFromClock(hwmgr, engine_clock, minClocks.engineClockInSR);
2417 /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
2418 graphic_level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2421 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVoltage);*/
2422 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases);*/
2423 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->SclkFrequency
);
2424 CONVERT_FROM_HOST_TO_SMC_US(graphic_level
->ActivityLevel
);
2425 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CgSpllFuncCntl3
);
2426 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CgSpllFuncCntl4
);
2427 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->SpllSpreadSpectrum
);
2428 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->SpllSpreadSpectrum2
);
2429 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CcPwrDynRm
);
2430 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level
->CcPwrDynRm1
);
2437 * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
2439 * @param hwmgr the address of the hardware manager
2441 static int tonga_populate_all_graphic_levels(struct pp_hwmgr
*hwmgr
)
2443 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2444 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2445 struct tonga_dpm_table
*dpm_table
= &data
->dpm_table
;
2446 phm_ppt_v1_pcie_table
*pcie_table
= pptable_info
->pcie_table
;
2447 uint8_t pcie_entry_count
= (uint8_t) data
->dpm_table
.pcie_speed_table
.count
;
2449 uint32_t level_array_adress
= data
->dpm_table_start
+
2450 offsetof(SMU72_Discrete_DpmTable
, GraphicsLevel
);
2451 uint32_t level_array_size
= sizeof(SMU72_Discrete_GraphicsLevel
) *
2452 SMU72_MAX_LEVELS_GRAPHICS
; /* 64 -> long; 32 -> int*/
2453 SMU72_Discrete_GraphicsLevel
*levels
= data
->smc_state_table
.GraphicsLevel
;
2454 uint32_t i
, maxEntry
;
2455 uint8_t highest_pcie_level_enabled
= 0, lowest_pcie_level_enabled
= 0, mid_pcie_level_enabled
= 0, count
= 0;
2456 PECI_RegistryValue reg_value
;
2457 memset(levels
, 0x00, level_array_size
);
2459 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
2460 result
= tonga_populate_single_graphic_level(hwmgr
,
2461 dpm_table
->sclk_table
.dpm_levels
[i
].value
,
2462 (uint16_t)data
->activity_target
[i
],
2463 &(data
->smc_state_table
.GraphicsLevel
[i
]));
2468 /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
2470 data
->smc_state_table
.GraphicsLevel
[i
].DeepSleepDivId
= 0;
2475 data
->smc_state_table
.GraphicsLevel
[0].UpHyst
= (uint8_t)reg_value
;
2481 data
->smc_state_table
.GraphicsLevel
[1].UpHyst
= (uint8_t)reg_value
;
2485 /* Only enable level 0 for now. */
2486 data
->smc_state_table
.GraphicsLevel
[0].EnabledForActivity
= 1;
2488 /* set highest level watermark to high */
2489 if (dpm_table
->sclk_table
.count
> 1)
2490 data
->smc_state_table
.GraphicsLevel
[dpm_table
->sclk_table
.count
-1].DisplayWatermark
=
2491 PPSMC_DISPLAY_WATERMARK_HIGH
;
2493 data
->smc_state_table
.GraphicsDpmLevelCount
=
2494 (uint8_t)dpm_table
->sclk_table
.count
;
2495 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
=
2496 tonga_get_dpm_level_enable_mask_value(&dpm_table
->sclk_table
);
2498 if (pcie_table
!= NULL
) {
2499 PP_ASSERT_WITH_CODE((pcie_entry_count
>= 1),
2500 "There must be 1 or more PCIE levels defined in PPTable.", return -1);
2501 maxEntry
= pcie_entry_count
- 1; /* for indexing, we need to decrement by 1.*/
2502 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
2503 data
->smc_state_table
.GraphicsLevel
[i
].pcieDpmLevel
=
2504 (uint8_t) ((i
< maxEntry
) ? i
: maxEntry
);
2507 if (0 == data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
)
2508 printk(KERN_ERR
"[ powerplay ] Pcie Dpm Enablemask is 0!");
2510 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
2511 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2512 (1<<(highest_pcie_level_enabled
+1))) != 0)) {
2513 highest_pcie_level_enabled
++;
2516 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
2517 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2518 (1<<lowest_pcie_level_enabled
)) == 0)) {
2519 lowest_pcie_level_enabled
++;
2522 while ((count
< highest_pcie_level_enabled
) &&
2523 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2524 (1<<(lowest_pcie_level_enabled
+1+count
))) == 0)) {
2527 mid_pcie_level_enabled
= (lowest_pcie_level_enabled
+1+count
) < highest_pcie_level_enabled
?
2528 (lowest_pcie_level_enabled
+1+count
) : highest_pcie_level_enabled
;
2531 /* set pcieDpmLevel to highest_pcie_level_enabled*/
2532 for (i
= 2; i
< dpm_table
->sclk_table
.count
; i
++) {
2533 data
->smc_state_table
.GraphicsLevel
[i
].pcieDpmLevel
= highest_pcie_level_enabled
;
2536 /* set pcieDpmLevel to lowest_pcie_level_enabled*/
2537 data
->smc_state_table
.GraphicsLevel
[0].pcieDpmLevel
= lowest_pcie_level_enabled
;
2539 /* set pcieDpmLevel to mid_pcie_level_enabled*/
2540 data
->smc_state_table
.GraphicsLevel
[1].pcieDpmLevel
= mid_pcie_level_enabled
;
2542 /* level count will send to smc once at init smc table and never change*/
2543 result
= tonga_copy_bytes_to_smc(hwmgr
->smumgr
, level_array_adress
, (uint8_t *)levels
, (uint32_t)level_array_size
, data
->sram_end
);
2552 * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
2554 * @param hwmgr the address of the hardware manager
2557 static int tonga_populate_all_memory_levels(struct pp_hwmgr
*hwmgr
)
2559 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2560 struct tonga_dpm_table
*dpm_table
= &data
->dpm_table
;
2562 /* populate MCLK dpm table to SMU7 */
2563 uint32_t level_array_adress
= data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
, MemoryLevel
);
2564 uint32_t level_array_size
= sizeof(SMU72_Discrete_MemoryLevel
) * SMU72_MAX_LEVELS_MEMORY
;
2565 SMU72_Discrete_MemoryLevel
*levels
= data
->smc_state_table
.MemoryLevel
;
2568 memset(levels
, 0x00, level_array_size
);
2570 for (i
= 0; i
< dpm_table
->mclk_table
.count
; i
++) {
2571 PP_ASSERT_WITH_CODE((0 != dpm_table
->mclk_table
.dpm_levels
[i
].value
),
2572 "can not populate memory level as memory clock is zero", return -1);
2573 result
= tonga_populate_single_memory_level(hwmgr
, dpm_table
->mclk_table
.dpm_levels
[i
].value
,
2574 &(data
->smc_state_table
.MemoryLevel
[i
]));
2580 /* Only enable level 0 for now.*/
2581 data
->smc_state_table
.MemoryLevel
[0].EnabledForActivity
= 1;
2584 * in order to prevent MC activity from stutter mode to push DPM up.
2585 * the UVD change complements this by putting the MCLK in a higher state
2586 * by default such that we are not effected by up threshold or and MCLK DPM latency.
2588 data
->smc_state_table
.MemoryLevel
[0].ActivityLevel
= 0x1F;
2589 CONVERT_FROM_HOST_TO_SMC_US(data
->smc_state_table
.MemoryLevel
[0].ActivityLevel
);
2591 data
->smc_state_table
.MemoryDpmLevelCount
= (uint8_t)dpm_table
->mclk_table
.count
;
2592 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&dpm_table
->mclk_table
);
2593 /* set highest level watermark to high*/
2594 data
->smc_state_table
.MemoryLevel
[dpm_table
->mclk_table
.count
-1].DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_HIGH
;
2596 /* level count will send to smc once at init smc table and never change*/
2597 result
= tonga_copy_bytes_to_smc(hwmgr
->smumgr
,
2598 level_array_adress
, (uint8_t *)levels
, (uint32_t)level_array_size
, data
->sram_end
);
2607 struct TONGA_DLL_SPEED_SETTING
{
2608 uint16_t Min
; /* Minimum Data Rate*/
2609 uint16_t Max
; /* Maximum Data Rate*/
2610 uint32_t dll_speed
; /* The desired DLL_SPEED setting*/
2613 static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr
*hwmgr
)
2618 /* ---------------------------------------- ULV related functions ----------------------------------------------------*/
2621 static int tonga_reset_single_dpm_table(
2622 struct pp_hwmgr
*hwmgr
,
2623 struct tonga_single_dpm_table
*dpm_table
,
2627 if (!(count
<= MAX_REGULAR_DPM_NUMBER
))
2628 printk(KERN_ERR
"[ powerplay ] Fatal error, can not set up single DPM \
2629 table entries to exceed max number! \n");
2631 dpm_table
->count
= count
;
2632 for (i
= 0; i
< MAX_REGULAR_DPM_NUMBER
; i
++) {
2633 dpm_table
->dpm_levels
[i
].enabled
= 0;
2639 static void tonga_setup_pcie_table_entry(
2640 struct tonga_single_dpm_table
*dpm_table
,
2641 uint32_t index
, uint32_t pcie_gen
,
2642 uint32_t pcie_lanes
)
2644 dpm_table
->dpm_levels
[index
].value
= pcie_gen
;
2645 dpm_table
->dpm_levels
[index
].param1
= pcie_lanes
;
2646 dpm_table
->dpm_levels
[index
].enabled
= 1;
2649 bool is_pcie_gen3_supported(uint32_t pcie_link_speed_cap
)
2651 if (pcie_link_speed_cap
& CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3
)
2657 bool is_pcie_gen2_supported(uint32_t pcie_link_speed_cap
)
2659 if (pcie_link_speed_cap
& CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2
)
2665 /* Get the new PCIE speed given the ASIC PCIE Cap and the NewState's requested PCIE speed*/
2666 uint16_t get_pcie_gen_support(uint32_t pcie_link_speed_cap
, uint16_t ns_pcie_gen
)
2668 uint32_t asic_pcie_link_speed_cap
= (pcie_link_speed_cap
&
2669 CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_MASK
);
2670 uint32_t sys_pcie_link_speed_cap
= (pcie_link_speed_cap
&
2671 CAIL_PCIE_LINK_SPEED_SUPPORT_MASK
);
2673 switch (asic_pcie_link_speed_cap
) {
2674 case CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1
:
2677 case CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2
:
2680 case CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3
:
2684 if (is_pcie_gen3_supported(sys_pcie_link_speed_cap
) &&
2685 (ns_pcie_gen
== PP_PCIEGen3
)) {
2687 } else if (is_pcie_gen2_supported(sys_pcie_link_speed_cap
) &&
2688 ((ns_pcie_gen
== PP_PCIEGen3
) || (ns_pcie_gen
== PP_PCIEGen2
))) {
2696 uint16_t get_pcie_lane_support(uint32_t pcie_lane_width_cap
, uint16_t ns_pcie_lanes
)
2699 uint16_t new_pcie_lanes
= ns_pcie_lanes
;
2700 uint16_t pcie_lanes
[7] = {1, 2, 4, 8, 12, 16, 32};
2702 switch (pcie_lane_width_cap
) {
2704 printk(KERN_ERR
"[ powerplay ] No valid PCIE lane width reported by CAIL!");
2706 case CAIL_PCIE_LINK_WIDTH_SUPPORT_X1
:
2709 case CAIL_PCIE_LINK_WIDTH_SUPPORT_X2
:
2712 case CAIL_PCIE_LINK_WIDTH_SUPPORT_X4
:
2715 case CAIL_PCIE_LINK_WIDTH_SUPPORT_X8
:
2718 case CAIL_PCIE_LINK_WIDTH_SUPPORT_X12
:
2719 new_pcie_lanes
= 12;
2721 case CAIL_PCIE_LINK_WIDTH_SUPPORT_X16
:
2722 new_pcie_lanes
= 16;
2724 case CAIL_PCIE_LINK_WIDTH_SUPPORT_X32
:
2725 new_pcie_lanes
= 32;
2728 for (i
= 0; i
< 7; i
++) {
2729 if (ns_pcie_lanes
== pcie_lanes
[i
]) {
2730 if (pcie_lane_width_cap
& (0x10000 << i
)) {
2733 for (j
= i
- 1; j
>= 0; j
--) {
2734 if (pcie_lane_width_cap
& (0x10000 << j
)) {
2735 new_pcie_lanes
= pcie_lanes
[j
];
2741 for (j
= i
+ 1; j
< 7; j
++) {
2742 if (pcie_lane_width_cap
& (0x10000 << j
)) {
2743 new_pcie_lanes
= pcie_lanes
[j
];
2748 printk(KERN_ERR
"[ powerplay ] Cannot find a valid PCIE lane width!");
2757 return new_pcie_lanes
;
2760 static int tonga_setup_default_pcie_tables(struct pp_hwmgr
*hwmgr
)
2762 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2763 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2764 phm_ppt_v1_pcie_table
*pcie_table
= pptable_info
->pcie_table
;
2765 uint32_t i
, maxEntry
;
2767 if (data
->use_pcie_performance_levels
&& !data
->use_pcie_power_saving_levels
) {
2768 data
->pcie_gen_power_saving
= data
->pcie_gen_performance
;
2769 data
->pcie_lane_power_saving
= data
->pcie_lane_performance
;
2770 } else if (!data
->use_pcie_performance_levels
&& data
->use_pcie_power_saving_levels
) {
2771 data
->pcie_gen_performance
= data
->pcie_gen_power_saving
;
2772 data
->pcie_lane_performance
= data
->pcie_lane_power_saving
;
2775 tonga_reset_single_dpm_table(hwmgr
, &data
->dpm_table
.pcie_speed_table
, SMU72_MAX_LEVELS_LINK
);
2777 if (pcie_table
!= NULL
) {
2779 * maxEntry is used to make sure we reserve one PCIE level for boot level (fix for A+A PSPP issue).
2780 * If PCIE table from PPTable have ULV entry + 8 entries, then ignore the last entry.
2782 maxEntry
= (SMU72_MAX_LEVELS_LINK
< pcie_table
->count
) ?
2783 SMU72_MAX_LEVELS_LINK
: pcie_table
->count
;
2784 for (i
= 1; i
< maxEntry
; i
++) {
2785 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, i
-1,
2786 get_pcie_gen_support(data
->pcie_gen_cap
, pcie_table
->entries
[i
].gen_speed
),
2787 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2789 data
->dpm_table
.pcie_speed_table
.count
= maxEntry
- 1;
2791 /* Hardcode Pcie Table */
2792 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 0,
2793 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Min_PCIEGen
),
2794 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2795 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 1,
2796 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Min_PCIEGen
),
2797 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2798 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 2,
2799 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2800 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2801 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 3,
2802 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2803 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2804 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 4,
2805 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2806 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2807 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 5,
2808 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Max_PCIEGen
),
2809 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2810 data
->dpm_table
.pcie_speed_table
.count
= 6;
2812 /* Populate last level for boot PCIE level, but do not increment count. */
2813 tonga_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
,
2814 data
->dpm_table
.pcie_speed_table
.count
,
2815 get_pcie_gen_support(data
->pcie_gen_cap
, PP_Min_PCIEGen
),
2816 get_pcie_lane_support(data
->pcie_lane_cap
, PP_Max_PCIELane
));
2823 * This function is to initalize all DPM state tables for SMU7 based on the dependency table.
2824 * Dynamic state patching function will then trim these state tables to the allowed range based
2825 * on the power policy or external client requests, such as UVD request, etc.
2827 static int tonga_setup_default_dpm_tables(struct pp_hwmgr
*hwmgr
)
2829 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2830 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2833 phm_ppt_v1_clock_voltage_dependency_table
*allowed_vdd_sclk_table
=
2834 pptable_info
->vdd_dep_on_sclk
;
2835 phm_ppt_v1_clock_voltage_dependency_table
*allowed_vdd_mclk_table
=
2836 pptable_info
->vdd_dep_on_mclk
;
2838 PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table
!= NULL
,
2839 "SCLK dependency table is missing. This table is mandatory", return -1);
2840 PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table
->count
>= 1,
2841 "SCLK dependency table has to have is missing. This table is mandatory", return -1);
2843 PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table
!= NULL
,
2844 "MCLK dependency table is missing. This table is mandatory", return -1);
2845 PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table
->count
>= 1,
2846 "VMCLK dependency table has to have is missing. This table is mandatory", return -1);
2848 /* clear the state table to reset everything to default */
2849 memset(&(data
->dpm_table
), 0x00, sizeof(data
->dpm_table
));
2850 tonga_reset_single_dpm_table(hwmgr
, &data
->dpm_table
.sclk_table
, SMU72_MAX_LEVELS_GRAPHICS
);
2851 tonga_reset_single_dpm_table(hwmgr
, &data
->dpm_table
.mclk_table
, SMU72_MAX_LEVELS_MEMORY
);
2852 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.VddcTable, SMU72_MAX_LEVELS_VDDC); */
2853 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_gfx_table, SMU72_MAX_LEVELS_VDDGFX);*/
2854 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_ci_table, SMU72_MAX_LEVELS_VDDCI);*/
2855 /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.mvdd_table, SMU72_MAX_LEVELS_MVDD);*/
2857 PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table
!= NULL
,
2858 "SCLK dependency table is missing. This table is mandatory", return -1);
2859 /* Initialize Sclk DPM table based on allow Sclk values*/
2860 data
->dpm_table
.sclk_table
.count
= 0;
2862 for (i
= 0; i
< allowed_vdd_sclk_table
->count
; i
++) {
2863 if (i
== 0 || data
->dpm_table
.sclk_table
.dpm_levels
[data
->dpm_table
.sclk_table
.count
-1].value
!=
2864 allowed_vdd_sclk_table
->entries
[i
].clk
) {
2865 data
->dpm_table
.sclk_table
.dpm_levels
[data
->dpm_table
.sclk_table
.count
].value
=
2866 allowed_vdd_sclk_table
->entries
[i
].clk
;
2867 data
->dpm_table
.sclk_table
.dpm_levels
[data
->dpm_table
.sclk_table
.count
].enabled
= 1; /*(i==0) ? 1 : 0; to do */
2868 data
->dpm_table
.sclk_table
.count
++;
2872 PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table
!= NULL
,
2873 "MCLK dependency table is missing. This table is mandatory", return -1);
2874 /* Initialize Mclk DPM table based on allow Mclk values */
2875 data
->dpm_table
.mclk_table
.count
= 0;
2876 for (i
= 0; i
< allowed_vdd_mclk_table
->count
; i
++) {
2877 if (i
== 0 || data
->dpm_table
.mclk_table
.dpm_levels
[data
->dpm_table
.mclk_table
.count
-1].value
!=
2878 allowed_vdd_mclk_table
->entries
[i
].clk
) {
2879 data
->dpm_table
.mclk_table
.dpm_levels
[data
->dpm_table
.mclk_table
.count
].value
=
2880 allowed_vdd_mclk_table
->entries
[i
].clk
;
2881 data
->dpm_table
.mclk_table
.dpm_levels
[data
->dpm_table
.mclk_table
.count
].enabled
= 1; /*(i==0) ? 1 : 0; */
2882 data
->dpm_table
.mclk_table
.count
++;
2886 /* Initialize Vddc DPM table based on allow Vddc values. And populate corresponding std values. */
2887 for (i
= 0; i
< allowed_vdd_sclk_table
->count
; i
++) {
2888 data
->dpm_table
.vddc_table
.dpm_levels
[i
].value
= allowed_vdd_mclk_table
->entries
[i
].vddc
;
2889 /* tonga_hwmgr->dpm_table.VddcTable.dpm_levels[i].param1 = stdVoltageTable->entries[i].Leakage; */
2890 /* param1 is for corresponding std voltage */
2891 data
->dpm_table
.vddc_table
.dpm_levels
[i
].enabled
= 1;
2893 data
->dpm_table
.vddc_table
.count
= allowed_vdd_sclk_table
->count
;
2895 if (NULL
!= allowed_vdd_mclk_table
) {
2896 /* Initialize Vddci DPM table based on allow Mclk values */
2897 for (i
= 0; i
< allowed_vdd_mclk_table
->count
; i
++) {
2898 data
->dpm_table
.vdd_ci_table
.dpm_levels
[i
].value
= allowed_vdd_mclk_table
->entries
[i
].vddci
;
2899 data
->dpm_table
.vdd_ci_table
.dpm_levels
[i
].enabled
= 1;
2900 data
->dpm_table
.mvdd_table
.dpm_levels
[i
].value
= allowed_vdd_mclk_table
->entries
[i
].mvdd
;
2901 data
->dpm_table
.mvdd_table
.dpm_levels
[i
].enabled
= 1;
2903 data
->dpm_table
.vdd_ci_table
.count
= allowed_vdd_mclk_table
->count
;
2904 data
->dpm_table
.mvdd_table
.count
= allowed_vdd_mclk_table
->count
;
2907 /* setup PCIE gen speed levels*/
2908 tonga_setup_default_pcie_tables(hwmgr
);
2910 /* save a copy of the default DPM table*/
2911 memcpy(&(data
->golden_dpm_table
), &(data
->dpm_table
), sizeof(struct tonga_dpm_table
));
2916 int tonga_populate_smc_initial_state(struct pp_hwmgr
*hwmgr
,
2917 const struct tonga_power_state
*bootState
)
2919 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2920 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2921 uint8_t count
, level
;
2923 count
= (uint8_t) (pptable_info
->vdd_dep_on_sclk
->count
);
2924 for (level
= 0; level
< count
; level
++) {
2925 if (pptable_info
->vdd_dep_on_sclk
->entries
[level
].clk
>=
2926 bootState
->performance_levels
[0].engine_clock
) {
2927 data
->smc_state_table
.GraphicsBootLevel
= level
;
2932 count
= (uint8_t) (pptable_info
->vdd_dep_on_mclk
->count
);
2933 for (level
= 0; level
< count
; level
++) {
2934 if (pptable_info
->vdd_dep_on_mclk
->entries
[level
].clk
>=
2935 bootState
->performance_levels
[0].memory_clock
) {
2936 data
->smc_state_table
.MemoryBootLevel
= level
;
2945 * Initializes the SMC table and uploads it
2947 * @param hwmgr the address of the powerplay hardware manager.
2948 * @param pInput the pointer to input data (PowerState)
2951 int tonga_init_smc_table(struct pp_hwmgr
*hwmgr
)
2954 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
2955 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2956 SMU72_Discrete_DpmTable
*table
= &(data
->smc_state_table
);
2957 const phw_tonga_ulv_parm
*ulv
= &(data
->ulv
);
2959 PECI_RegistryValue reg_value
;
2960 pp_atomctrl_gpio_pin_assignment gpio_pin_assignment
;
2962 result
= tonga_setup_default_dpm_tables(hwmgr
);
2963 PP_ASSERT_WITH_CODE(0 == result
,
2964 "Failed to setup default DPM tables!", return result
;);
2965 memset(&(data
->smc_state_table
), 0x00, sizeof(data
->smc_state_table
));
2966 if (TONGA_VOLTAGE_CONTROL_NONE
!= data
->voltage_control
) {
2967 tonga_populate_smc_voltage_tables(hwmgr
, table
);
2970 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2971 PHM_PlatformCaps_AutomaticDCTransition
)) {
2972 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GPIO_DC
;
2975 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2976 PHM_PlatformCaps_StepVddc
)) {
2977 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_STEPVDDC
;
2980 if (data
->is_memory_GDDR5
) {
2981 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GDDR5
;
2984 i
= PHM_READ_FIELD(hwmgr
->device
, CC_MC_MAX_CHANNEL
, NOOFCHAN
);
2986 if (i
== 1 || i
== 0) {
2987 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_12CHANNEL
;
2990 if (ulv
->ulv_supported
&& pptable_info
->us_ulv_voltage_offset
) {
2991 PP_ASSERT_WITH_CODE(0 == result
,
2992 "Failed to initialize ULV state!", return result
;);
2994 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
2995 ixCG_ULV_PARAMETER
, ulv
->ch_ulv_parameter
);
2998 result
= tonga_populate_smc_link_level(hwmgr
, table
);
2999 PP_ASSERT_WITH_CODE(0 == result
,
3000 "Failed to initialize Link Level!", return result
;);
3002 result
= tonga_populate_all_graphic_levels(hwmgr
);
3003 PP_ASSERT_WITH_CODE(0 == result
,
3004 "Failed to initialize Graphics Level!", return result
;);
3006 result
= tonga_populate_all_memory_levels(hwmgr
);
3007 PP_ASSERT_WITH_CODE(0 == result
,
3008 "Failed to initialize Memory Level!", return result
;);
3010 result
= tonga_populate_smv_acpi_level(hwmgr
, table
);
3011 PP_ASSERT_WITH_CODE(0 == result
,
3012 "Failed to initialize ACPI Level!", return result
;);
3014 result
= tonga_populate_smc_vce_level(hwmgr
, table
);
3015 PP_ASSERT_WITH_CODE(0 == result
,
3016 "Failed to initialize VCE Level!", return result
;);
3018 result
= tonga_populate_smc_acp_level(hwmgr
, table
);
3019 PP_ASSERT_WITH_CODE(0 == result
,
3020 "Failed to initialize ACP Level!", return result
;);
3022 result
= tonga_populate_smc_samu_level(hwmgr
, table
);
3023 PP_ASSERT_WITH_CODE(0 == result
,
3024 "Failed to initialize SAMU Level!", return result
;);
3026 /* Since only the initial state is completely set up at this point (the other states are just copies of the boot state) we only */
3027 /* need to populate the ARB settings for the initial state. */
3028 result
= tonga_program_memory_timing_parameters(hwmgr
);
3029 PP_ASSERT_WITH_CODE(0 == result
,
3030 "Failed to Write ARB settings for the initial state.", return result
;);
3032 result
= tonga_populate_smc_boot_level(hwmgr
, table
);
3033 PP_ASSERT_WITH_CODE(0 == result
,
3034 "Failed to initialize Boot Level!", return result
;);
3036 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3037 PHM_PlatformCaps_ClockStretcher
)) {
3038 result
= tonga_populate_clock_stretcher_data_table(hwmgr
);
3039 PP_ASSERT_WITH_CODE(0 == result
,
3040 "Failed to populate Clock Stretcher Data Table!", return result
;);
3042 table
->GraphicsVoltageChangeEnable
= 1;
3043 table
->GraphicsThermThrottleEnable
= 1;
3044 table
->GraphicsInterval
= 1;
3045 table
->VoltageInterval
= 1;
3046 table
->ThermalInterval
= 1;
3047 table
->TemperatureLimitHigh
=
3048 pptable_info
->cac_dtp_table
->usTargetOperatingTemp
*
3049 TONGA_Q88_FORMAT_CONVERSION_UNIT
;
3050 table
->TemperatureLimitLow
=
3051 (pptable_info
->cac_dtp_table
->usTargetOperatingTemp
- 1) *
3052 TONGA_Q88_FORMAT_CONVERSION_UNIT
;
3053 table
->MemoryVoltageChangeEnable
= 1;
3054 table
->MemoryInterval
= 1;
3055 table
->VoltageResponseTime
= 0;
3056 table
->PhaseResponseTime
= 0;
3057 table
->MemoryThermThrottleEnable
= 1;
3060 * Cail reads current link status and reports it as cap (we cannot change this due to some previous issues we had)
3061 * SMC drops the link status to lowest level after enabling DPM by PowerPlay. After pnp or toggling CF, driver gets reloaded again
3062 * but this time Cail reads current link status which was set to low by SMC and reports it as cap to powerplay
3063 * To avoid it, we set PCIeBootLinkLevel to highest dpm level
3065 PP_ASSERT_WITH_CODE((1 <= data
->dpm_table
.pcie_speed_table
.count
),
3066 "There must be 1 or more PCIE levels defined in PPTable.",
3069 table
->PCIeBootLinkLevel
= (uint8_t) (data
->dpm_table
.pcie_speed_table
.count
);
3071 table
->PCIeGenInterval
= 1;
3073 result
= tonga_populate_vr_config(hwmgr
, table
);
3074 PP_ASSERT_WITH_CODE(0 == result
,
3075 "Failed to populate VRConfig setting!", return result
);
3077 table
->ThermGpio
= 17;
3078 table
->SclkStepSize
= 0x4000;
3081 if ((0 == reg_value
) &&
3082 (0 == atomctrl_get_pp_assign_pin(hwmgr
,
3083 VDDC_VRHOT_GPIO_PINID
, &gpio_pin_assignment
))) {
3084 table
->VRHotGpio
= gpio_pin_assignment
.uc_gpio_pin_bit_shift
;
3085 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3086 PHM_PlatformCaps_RegulatorHot
);
3088 table
->VRHotGpio
= TONGA_UNUSED_GPIO_PIN
;
3089 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3090 PHM_PlatformCaps_RegulatorHot
);
3093 /* ACDC Switch GPIO */
3095 if ((0 == reg_value
) &&
3096 (0 == atomctrl_get_pp_assign_pin(hwmgr
,
3097 PP_AC_DC_SWITCH_GPIO_PINID
, &gpio_pin_assignment
))) {
3098 table
->AcDcGpio
= gpio_pin_assignment
.uc_gpio_pin_bit_shift
;
3099 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3100 PHM_PlatformCaps_AutomaticDCTransition
);
3102 table
->AcDcGpio
= TONGA_UNUSED_GPIO_PIN
;
3103 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3104 PHM_PlatformCaps_AutomaticDCTransition
);
3107 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3108 PHM_PlatformCaps_Falcon_QuickTransition
);
3111 if (1 == reg_value
) {
3112 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3113 PHM_PlatformCaps_AutomaticDCTransition
);
3114 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3115 PHM_PlatformCaps_Falcon_QuickTransition
);
3119 if ((0 == reg_value
) &&
3120 (0 == atomctrl_get_pp_assign_pin(hwmgr
,
3121 THERMAL_INT_OUTPUT_GPIO_PINID
, &gpio_pin_assignment
))) {
3122 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3123 PHM_PlatformCaps_ThermalOutGPIO
);
3125 table
->ThermOutGpio
= gpio_pin_assignment
.uc_gpio_pin_bit_shift
;
3127 table
->ThermOutPolarity
=
3128 (0 == (cgs_read_register(hwmgr
->device
, mmGPIOPAD_A
) &
3129 (1 << gpio_pin_assignment
.uc_gpio_pin_bit_shift
))) ? 1:0;
3131 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_ONLY
;
3133 /* if required, combine VRHot/PCC with thermal out GPIO*/
3134 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3135 PHM_PlatformCaps_RegulatorHot
) &&
3136 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3137 PHM_PlatformCaps_CombinePCCWithThermalSignal
)){
3138 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_VRHOT
;
3141 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3142 PHM_PlatformCaps_ThermalOutGPIO
);
3144 table
->ThermOutGpio
= 17;
3145 table
->ThermOutPolarity
= 1;
3146 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_DISABLE
;
3149 for (i
= 0; i
< SMU72_MAX_ENTRIES_SMIO
; i
++) {
3150 table
->Smio
[i
] = PP_HOST_TO_SMC_UL(table
->Smio
[i
]);
3152 CONVERT_FROM_HOST_TO_SMC_UL(table
->SystemFlags
);
3153 CONVERT_FROM_HOST_TO_SMC_UL(table
->VRConfig
);
3154 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask1
);
3155 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask2
);
3156 CONVERT_FROM_HOST_TO_SMC_UL(table
->SclkStepSize
);
3157 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitHigh
);
3158 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitLow
);
3159 CONVERT_FROM_HOST_TO_SMC_US(table
->VoltageResponseTime
);
3160 CONVERT_FROM_HOST_TO_SMC_US(table
->PhaseResponseTime
);
3162 /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
3163 result
= tonga_copy_bytes_to_smc(hwmgr
->smumgr
, data
->dpm_table_start
+
3164 offsetof(SMU72_Discrete_DpmTable
, SystemFlags
),
3165 (uint8_t *)&(table
->SystemFlags
),
3166 sizeof(SMU72_Discrete_DpmTable
)-3 * sizeof(SMU72_PIDController
),
3169 PP_ASSERT_WITH_CODE(0 == result
,
3170 "Failed to upload dpm data to SMC memory!", return result
;);
3175 /* Look up the voltaged based on DAL's requested level. and then send the requested VDDC voltage to SMC*/
3176 static void tonga_apply_dal_minimum_voltage_request(struct pp_hwmgr
*hwmgr
)
3181 int tonga_upload_dpm_level_enable_mask(struct pp_hwmgr
*hwmgr
)
3183 PPSMC_Result result
;
3184 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3186 /* Apply minimum voltage based on DAL's request level */
3187 tonga_apply_dal_minimum_voltage_request(hwmgr
);
3189 if (0 == data
->sclk_dpm_key_disabled
) {
3190 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
3191 if (0 != tonga_is_dpm_running(hwmgr
))
3192 printk(KERN_ERR
"[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
3194 if (0 != data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
3195 result
= smum_send_msg_to_smc_with_parameter(
3197 (PPSMC_Msg
)PPSMC_MSG_SCLKDPM_SetEnabledMask
,
3198 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
3199 PP_ASSERT_WITH_CODE((0 == result
),
3200 "Set Sclk Dpm enable Mask failed", return -1);
3204 if (0 == data
->mclk_dpm_key_disabled
) {
3205 /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
3206 if (0 != tonga_is_dpm_running(hwmgr
))
3207 printk(KERN_ERR
"[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
3209 if (0 != data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
) {
3210 result
= smum_send_msg_to_smc_with_parameter(
3212 (PPSMC_Msg
)PPSMC_MSG_MCLKDPM_SetEnabledMask
,
3213 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
);
3214 PP_ASSERT_WITH_CODE((0 == result
),
3215 "Set Mclk Dpm enable Mask failed", return -1);
3223 int tonga_force_dpm_highest(struct pp_hwmgr
*hwmgr
)
3225 uint32_t level
, tmp
;
3226 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3228 if (0 == data
->pcie_dpm_key_disabled
) {
3230 if (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
!= 0) {
3232 tmp
= data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
;
3237 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr
, level
)),
3238 "force highest pcie dpm state failed!", return -1);
3243 if (0 == data
->sclk_dpm_key_disabled
) {
3245 if (data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
!= 0) {
3247 tmp
= data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
;
3252 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr
, level
)),
3253 "force highest sclk dpm state failed!", return -1);
3254 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
,
3255 CGS_IND_REG__SMC
, TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_SCLK_INDEX
) != level
)
3256 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3257 Curr_Sclk_Index does not match the level \n");
3263 if (0 == data
->mclk_dpm_key_disabled
) {
3265 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
!= 0) {
3267 tmp
= data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
;
3272 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr
, level
)),
3273 "force highest mclk dpm state failed!", return -1);
3274 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3275 TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_MCLK_INDEX
) != level
)
3276 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3277 Curr_Sclk_Index does not match the level \n");
3286 * Find the MC microcode version and store it in the HwMgr struct
3288 * @param hwmgr the address of the powerplay hardware manager.
3291 int tonga_get_mc_microcode_version (struct pp_hwmgr
*hwmgr
)
3293 cgs_write_register(hwmgr
->device
, mmMC_SEQ_IO_DEBUG_INDEX
, 0x9F);
3295 hwmgr
->microcode_version_info
.MC
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_IO_DEBUG_DATA
);
3301 * Initialize Dynamic State Adjustment Rule Settings
3303 * @param hwmgr the address of the powerplay hardware manager.
3305 int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr
*hwmgr
)
3307 uint32_t table_size
;
3308 struct phm_clock_voltage_dependency_table
*table_clk_vlt
;
3309 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3311 hwmgr
->dyn_state
.mclk_sclk_ratio
= 4;
3312 hwmgr
->dyn_state
.sclk_mclk_delta
= 15000; /* 150 MHz */
3313 hwmgr
->dyn_state
.vddc_vddci_delta
= 200; /* 200mV */
3315 /* initialize vddc_dep_on_dal_pwrl table */
3316 table_size
= sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record
);
3317 table_clk_vlt
= (struct phm_clock_voltage_dependency_table
*)kzalloc(table_size
, GFP_KERNEL
);
3319 if (NULL
== table_clk_vlt
) {
3320 printk(KERN_ERR
"[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
3323 table_clk_vlt
->count
= 4;
3324 table_clk_vlt
->entries
[0].clk
= PP_DAL_POWERLEVEL_ULTRALOW
;
3325 table_clk_vlt
->entries
[0].v
= 0;
3326 table_clk_vlt
->entries
[1].clk
= PP_DAL_POWERLEVEL_LOW
;
3327 table_clk_vlt
->entries
[1].v
= 720;
3328 table_clk_vlt
->entries
[2].clk
= PP_DAL_POWERLEVEL_NOMINAL
;
3329 table_clk_vlt
->entries
[2].v
= 810;
3330 table_clk_vlt
->entries
[3].clk
= PP_DAL_POWERLEVEL_PERFORMANCE
;
3331 table_clk_vlt
->entries
[3].v
= 900;
3332 pptable_info
->vddc_dep_on_dal_pwrl
= table_clk_vlt
;
3333 hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
= table_clk_vlt
;
3339 static int tonga_set_private_var_based_on_pptale(struct pp_hwmgr
*hwmgr
)
3341 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3342 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3344 phm_ppt_v1_clock_voltage_dependency_table
*allowed_sclk_vdd_table
=
3345 pptable_info
->vdd_dep_on_sclk
;
3346 phm_ppt_v1_clock_voltage_dependency_table
*allowed_mclk_vdd_table
=
3347 pptable_info
->vdd_dep_on_mclk
;
3349 PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table
!= NULL
,
3350 "VDD dependency on SCLK table is missing. \
3351 This table is mandatory", return -1);
3352 PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table
->count
>= 1,
3353 "VDD dependency on SCLK table has to have is missing. \
3354 This table is mandatory", return -1);
3356 PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table
!= NULL
,
3357 "VDD dependency on MCLK table is missing. \
3358 This table is mandatory", return -1);
3359 PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table
->count
>= 1,
3360 "VDD dependency on MCLK table has to have is missing. \
3361 This table is mandatory", return -1);
3363 data
->min_vddc_in_pp_table
= (uint16_t)allowed_sclk_vdd_table
->entries
[0].vddc
;
3364 data
->max_vddc_in_pp_table
= (uint16_t)allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].vddc
;
3366 pptable_info
->max_clock_voltage_on_ac
.sclk
=
3367 allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].clk
;
3368 pptable_info
->max_clock_voltage_on_ac
.mclk
=
3369 allowed_mclk_vdd_table
->entries
[allowed_mclk_vdd_table
->count
- 1].clk
;
3370 pptable_info
->max_clock_voltage_on_ac
.vddc
=
3371 allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].vddc
;
3372 pptable_info
->max_clock_voltage_on_ac
.vddci
=
3373 allowed_mclk_vdd_table
->entries
[allowed_mclk_vdd_table
->count
- 1].vddci
;
3375 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.sclk
=
3376 pptable_info
->max_clock_voltage_on_ac
.sclk
;
3377 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.mclk
=
3378 pptable_info
->max_clock_voltage_on_ac
.mclk
;
3379 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.vddc
=
3380 pptable_info
->max_clock_voltage_on_ac
.vddc
;
3381 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.vddci
=
3382 pptable_info
->max_clock_voltage_on_ac
.vddci
;
3387 int tonga_unforce_dpm_levels(struct pp_hwmgr
*hwmgr
)
3389 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3392 PP_ASSERT_WITH_CODE (0 == tonga_is_dpm_running(hwmgr
),
3393 "Trying to Unforce DPM when DPM is disabled. Returning without sending SMC message.",
3396 if (0 == data
->pcie_dpm_key_disabled
) {
3397 PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(
3399 PPSMC_MSG_PCIeDPM_UnForceLevel
)),
3400 "unforce pcie level failed!",
3404 result
= tonga_upload_dpm_level_enable_mask(hwmgr
);
3409 static uint32_t tonga_get_lowest_enable_level(
3410 struct pp_hwmgr
*hwmgr
, uint32_t level_mask
)
3414 while (0 == (level_mask
& (1 << level
)))
3420 static int tonga_force_dpm_lowest(struct pp_hwmgr
*hwmgr
)
3423 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3425 /* for now force only sclk */
3426 if (0 != data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
3427 level
= tonga_get_lowest_enable_level(hwmgr
,
3428 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
3430 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr
, level
)),
3431 "force sclk dpm state failed!", return -1);
3433 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
,
3434 CGS_IND_REG__SMC
, TARGET_AND_CURRENT_PROFILE_INDEX
, CURR_SCLK_INDEX
) != level
)
3435 printk(KERN_ERR
"[ powerplay ] Target_and_current_Profile_Index. \
3436 Curr_Sclk_Index does not match the level \n");
3442 static int tonga_patch_voltage_dependency_tables_with_lookup_table(struct pp_hwmgr
*hwmgr
)
3446 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3447 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3449 phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
= pptable_info
->vdd_dep_on_sclk
;
3450 phm_ppt_v1_clock_voltage_dependency_table
*mclk_table
= pptable_info
->vdd_dep_on_mclk
;
3451 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
3453 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3454 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
3455 voltageId
= sclk_table
->entries
[entryId
].vddInd
;
3456 sclk_table
->entries
[entryId
].vddgfx
=
3457 pptable_info
->vddgfx_lookup_table
->entries
[voltageId
].us_vdd
;
3460 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
3461 voltageId
= sclk_table
->entries
[entryId
].vddInd
;
3462 sclk_table
->entries
[entryId
].vddc
=
3463 pptable_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
3467 for (entryId
= 0; entryId
< mclk_table
->count
; ++entryId
) {
3468 voltageId
= mclk_table
->entries
[entryId
].vddInd
;
3469 mclk_table
->entries
[entryId
].vddc
=
3470 pptable_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
3473 for (entryId
= 0; entryId
< mm_table
->count
; ++entryId
) {
3474 voltageId
= mm_table
->entries
[entryId
].vddcInd
;
3475 mm_table
->entries
[entryId
].vddc
=
3476 pptable_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
3483 static int tonga_calc_voltage_dependency_tables(struct pp_hwmgr
*hwmgr
)
3486 phm_ppt_v1_voltage_lookup_record v_record
;
3487 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3488 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3490 phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
= pptable_info
->vdd_dep_on_sclk
;
3491 phm_ppt_v1_clock_voltage_dependency_table
*mclk_table
= pptable_info
->vdd_dep_on_mclk
;
3493 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3494 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
3495 if (sclk_table
->entries
[entryId
].vdd_offset
& (1 << 15))
3496 v_record
.us_vdd
= sclk_table
->entries
[entryId
].vddgfx
+
3497 sclk_table
->entries
[entryId
].vdd_offset
- 0xFFFF;
3499 v_record
.us_vdd
= sclk_table
->entries
[entryId
].vddgfx
+
3500 sclk_table
->entries
[entryId
].vdd_offset
;
3502 sclk_table
->entries
[entryId
].vddc
=
3503 v_record
.us_cac_low
= v_record
.us_cac_mid
=
3504 v_record
.us_cac_high
= v_record
.us_vdd
;
3506 tonga_add_voltage(hwmgr
, pptable_info
->vddc_lookup_table
, &v_record
);
3509 for (entryId
= 0; entryId
< mclk_table
->count
; ++entryId
) {
3510 if (mclk_table
->entries
[entryId
].vdd_offset
& (1 << 15))
3511 v_record
.us_vdd
= mclk_table
->entries
[entryId
].vddc
+
3512 mclk_table
->entries
[entryId
].vdd_offset
- 0xFFFF;
3514 v_record
.us_vdd
= mclk_table
->entries
[entryId
].vddc
+
3515 mclk_table
->entries
[entryId
].vdd_offset
;
3517 mclk_table
->entries
[entryId
].vddgfx
= v_record
.us_cac_low
=
3518 v_record
.us_cac_mid
= v_record
.us_cac_high
= v_record
.us_vdd
;
3519 tonga_add_voltage(hwmgr
, pptable_info
->vddgfx_lookup_table
, &v_record
);
3527 static int tonga_calc_mm_voltage_dependency_table(struct pp_hwmgr
*hwmgr
)
3530 phm_ppt_v1_voltage_lookup_record v_record
;
3531 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3532 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3533 phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
= pptable_info
->mm_dep_table
;
3535 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3536 for (entryId
= 0; entryId
< mm_table
->count
; entryId
++) {
3537 if (mm_table
->entries
[entryId
].vddgfx_offset
& (1 << 15))
3538 v_record
.us_vdd
= mm_table
->entries
[entryId
].vddc
+
3539 mm_table
->entries
[entryId
].vddgfx_offset
- 0xFFFF;
3541 v_record
.us_vdd
= mm_table
->entries
[entryId
].vddc
+
3542 mm_table
->entries
[entryId
].vddgfx_offset
;
3544 /* Add the calculated VDDGFX to the VDDGFX lookup table */
3545 mm_table
->entries
[entryId
].vddgfx
= v_record
.us_cac_low
=
3546 v_record
.us_cac_mid
= v_record
.us_cac_high
= v_record
.us_vdd
;
3547 tonga_add_voltage(hwmgr
, pptable_info
->vddgfx_lookup_table
, &v_record
);
3555 * Change virtual leakage voltage to actual value.
3557 * @param hwmgr the address of the powerplay hardware manager.
3558 * @param pointer to changing voltage
3559 * @param pointer to leakage table
3561 static void tonga_patch_with_vdd_leakage(struct pp_hwmgr
*hwmgr
,
3562 uint16_t *voltage
, phw_tonga_leakage_voltage
*pLeakageTable
)
3564 uint32_t leakage_index
;
3566 /* search for leakage voltage ID 0xff01 ~ 0xff08 */
3567 for (leakage_index
= 0; leakage_index
< pLeakageTable
->count
; leakage_index
++) {
3568 /* if this voltage matches a leakage voltage ID */
3569 /* patch with actual leakage voltage */
3570 if (pLeakageTable
->leakage_id
[leakage_index
] == *voltage
) {
3571 *voltage
= pLeakageTable
->actual_voltage
[leakage_index
];
3576 if (*voltage
> ATOM_VIRTUAL_VOLTAGE_ID0
)
3577 printk(KERN_ERR
"[ powerplay ] Voltage value looks like a Leakage ID but it's not patched \n");
3581 * Patch voltage lookup table by EVV leakages.
3583 * @param hwmgr the address of the powerplay hardware manager.
3584 * @param pointer to voltage lookup table
3585 * @param pointer to leakage table
3588 static int tonga_patch_lookup_table_with_leakage(struct pp_hwmgr
*hwmgr
,
3589 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
3590 phw_tonga_leakage_voltage
*pLeakageTable
)
3594 for (i
= 0; i
< lookup_table
->count
; i
++) {
3595 tonga_patch_with_vdd_leakage(hwmgr
,
3596 &lookup_table
->entries
[i
].us_vdd
, pLeakageTable
);
3602 static int tonga_patch_clock_voltage_lomits_with_vddc_leakage(struct pp_hwmgr
*hwmgr
,
3603 phw_tonga_leakage_voltage
*pLeakageTable
, uint16_t *Vddc
)
3605 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3607 tonga_patch_with_vdd_leakage(hwmgr
, (uint16_t *)Vddc
, pLeakageTable
);
3608 hwmgr
->dyn_state
.max_clock_voltage_on_dc
.vddc
=
3609 pptable_info
->max_clock_voltage_on_dc
.vddc
;
3614 static int tonga_patch_clock_voltage_limits_with_vddgfx_leakage(
3615 struct pp_hwmgr
*hwmgr
, phw_tonga_leakage_voltage
*pLeakageTable
,
3618 tonga_patch_with_vdd_leakage(hwmgr
, (uint16_t *)Vddgfx
, pLeakageTable
);
3622 int tonga_sort_lookup_table(struct pp_hwmgr
*hwmgr
,
3623 phm_ppt_v1_voltage_lookup_table
*lookup_table
)
3625 uint32_t table_size
, i
, j
;
3626 phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record
;
3627 table_size
= lookup_table
->count
;
3629 PP_ASSERT_WITH_CODE(0 != lookup_table
->count
,
3630 "Lookup table is empty", return -1);
3632 /* Sorting voltages */
3633 for (i
= 0; i
< table_size
- 1; i
++) {
3634 for (j
= i
+ 1; j
> 0; j
--) {
3635 if (lookup_table
->entries
[j
].us_vdd
< lookup_table
->entries
[j
-1].us_vdd
) {
3636 tmp_voltage_lookup_record
= lookup_table
->entries
[j
-1];
3637 lookup_table
->entries
[j
-1] = lookup_table
->entries
[j
];
3638 lookup_table
->entries
[j
] = tmp_voltage_lookup_record
;
3646 static int tonga_complete_dependency_tables(struct pp_hwmgr
*hwmgr
)
3650 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
3651 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
3653 if (data
->vdd_gfx_control
== TONGA_VOLTAGE_CONTROL_BY_SVID2
) {
3654 tmp_result
= tonga_patch_lookup_table_with_leakage(hwmgr
,
3655 pptable_info
->vddgfx_lookup_table
, &(data
->vddcgfx_leakage
));
3656 if (tmp_result
!= 0)
3657 result
= tmp_result
;
3659 tmp_result
= tonga_patch_clock_voltage_limits_with_vddgfx_leakage(hwmgr
,
3660 &(data
->vddcgfx_leakage
), &pptable_info
->max_clock_voltage_on_dc
.vddgfx
);
3661 if (tmp_result
!= 0)
3662 result
= tmp_result
;
3664 tmp_result
= tonga_patch_lookup_table_with_leakage(hwmgr
,
3665 pptable_info
->vddc_lookup_table
, &(data
->vddc_leakage
));
3666 if (tmp_result
!= 0)
3667 result
= tmp_result
;
3669 tmp_result
= tonga_patch_clock_voltage_lomits_with_vddc_leakage(hwmgr
,
3670 &(data
->vddc_leakage
), &pptable_info
->max_clock_voltage_on_dc
.vddc
);
3671 if (tmp_result
!= 0)
3672 result
= tmp_result
;
3675 tmp_result
= tonga_patch_voltage_dependency_tables_with_lookup_table(hwmgr
);
3676 if (tmp_result
!= 0)
3677 result
= tmp_result
;
3679 tmp_result
= tonga_calc_voltage_dependency_tables(hwmgr
);
3680 if (tmp_result
!= 0)
3681 result
= tmp_result
;
3683 tmp_result
= tonga_calc_mm_voltage_dependency_table(hwmgr
);
3684 if (tmp_result
!= 0)
3685 result
= tmp_result
;
3687 tmp_result
= tonga_sort_lookup_table(hwmgr
, pptable_info
->vddgfx_lookup_table
);
3688 if (tmp_result
!= 0)
3689 result
= tmp_result
;
3691 tmp_result
= tonga_sort_lookup_table(hwmgr
, pptable_info
->vddc_lookup_table
);
3692 if (tmp_result
!= 0)
3693 result
= tmp_result
;
3698 int tonga_init_sclk_threshold(struct pp_hwmgr
*hwmgr
)
3700 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
3701 data
->low_sclk_interrupt_threshold
= 0;
3706 int tonga_setup_asic_task(struct pp_hwmgr
*hwmgr
)
3708 int tmp_result
, result
= 0;
3710 tmp_result
= tonga_read_clock_registers(hwmgr
);
3711 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3712 "Failed to read clock registers!", result
= tmp_result
);
3714 tmp_result
= tonga_get_memory_type(hwmgr
);
3715 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3716 "Failed to get memory type!", result
= tmp_result
);
3718 tmp_result
= tonga_enable_acpi_power_management(hwmgr
);
3719 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3720 "Failed to enable ACPI power management!", result
= tmp_result
);
3722 tmp_result
= tonga_init_power_gate_state(hwmgr
);
3723 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3724 "Failed to init power gate state!", result
= tmp_result
);
3726 tmp_result
= tonga_get_mc_microcode_version(hwmgr
);
3727 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3728 "Failed to get MC microcode version!", result
= tmp_result
);
3730 tmp_result
= tonga_init_sclk_threshold(hwmgr
);
3731 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3732 "Failed to init sclk threshold!", result
= tmp_result
);
3738 * Enable voltage control
3740 * @param hwmgr the address of the powerplay hardware manager.
3743 int tonga_enable_voltage_control(struct pp_hwmgr
*hwmgr
)
3745 /* enable voltage control */
3746 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
, VOLT_PWRMGT_EN
, 1);
3752 * Checks if we want to support voltage control
3754 * @param hwmgr the address of the powerplay hardware manager.
3756 bool cf_tonga_voltage_control(const struct pp_hwmgr
*hwmgr
)
3758 const struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
3760 return(TONGA_VOLTAGE_CONTROL_NONE
!= data
->voltage_control
);
3763 /*---------------------------MC----------------------------*/
3765 uint8_t tonga_get_memory_modile_index(struct pp_hwmgr
*hwmgr
)
3767 return (uint8_t) (0xFF & (cgs_read_register(hwmgr
->device
, mmBIOS_SCRATCH_4
) >> 16));
3770 bool tonga_check_s0_mc_reg_index(uint16_t inReg
, uint16_t *outReg
)
3775 case mmMC_SEQ_RAS_TIMING
:
3776 *outReg
= mmMC_SEQ_RAS_TIMING_LP
;
3779 case mmMC_SEQ_DLL_STBY
:
3780 *outReg
= mmMC_SEQ_DLL_STBY_LP
;
3783 case mmMC_SEQ_G5PDX_CMD0
:
3784 *outReg
= mmMC_SEQ_G5PDX_CMD0_LP
;
3787 case mmMC_SEQ_G5PDX_CMD1
:
3788 *outReg
= mmMC_SEQ_G5PDX_CMD1_LP
;
3791 case mmMC_SEQ_G5PDX_CTRL
:
3792 *outReg
= mmMC_SEQ_G5PDX_CTRL_LP
;
3795 case mmMC_SEQ_CAS_TIMING
:
3796 *outReg
= mmMC_SEQ_CAS_TIMING_LP
;
3799 case mmMC_SEQ_MISC_TIMING
:
3800 *outReg
= mmMC_SEQ_MISC_TIMING_LP
;
3803 case mmMC_SEQ_MISC_TIMING2
:
3804 *outReg
= mmMC_SEQ_MISC_TIMING2_LP
;
3807 case mmMC_SEQ_PMG_DVS_CMD
:
3808 *outReg
= mmMC_SEQ_PMG_DVS_CMD_LP
;
3811 case mmMC_SEQ_PMG_DVS_CTL
:
3812 *outReg
= mmMC_SEQ_PMG_DVS_CTL_LP
;
3815 case mmMC_SEQ_RD_CTL_D0
:
3816 *outReg
= mmMC_SEQ_RD_CTL_D0_LP
;
3819 case mmMC_SEQ_RD_CTL_D1
:
3820 *outReg
= mmMC_SEQ_RD_CTL_D1_LP
;
3823 case mmMC_SEQ_WR_CTL_D0
:
3824 *outReg
= mmMC_SEQ_WR_CTL_D0_LP
;
3827 case mmMC_SEQ_WR_CTL_D1
:
3828 *outReg
= mmMC_SEQ_WR_CTL_D1_LP
;
3831 case mmMC_PMG_CMD_EMRS
:
3832 *outReg
= mmMC_SEQ_PMG_CMD_EMRS_LP
;
3835 case mmMC_PMG_CMD_MRS
:
3836 *outReg
= mmMC_SEQ_PMG_CMD_MRS_LP
;
3839 case mmMC_PMG_CMD_MRS1
:
3840 *outReg
= mmMC_SEQ_PMG_CMD_MRS1_LP
;
3843 case mmMC_SEQ_PMG_TIMING
:
3844 *outReg
= mmMC_SEQ_PMG_TIMING_LP
;
3847 case mmMC_PMG_CMD_MRS2
:
3848 *outReg
= mmMC_SEQ_PMG_CMD_MRS2_LP
;
3851 case mmMC_SEQ_WR_CTL_2
:
3852 *outReg
= mmMC_SEQ_WR_CTL_2_LP
;
3863 int tonga_set_s0_mc_reg_index(phw_tonga_mc_reg_table
*table
)
3868 for (i
= 0; i
< table
->last
; i
++) {
3869 table
->mc_reg_address
[i
].s0
=
3870 tonga_check_s0_mc_reg_index(table
->mc_reg_address
[i
].s1
, &address
)
3871 ? address
: table
->mc_reg_address
[i
].s1
;
3876 int tonga_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table
*table
, phw_tonga_mc_reg_table
*ni_table
)
3880 PP_ASSERT_WITH_CODE((table
->last
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3881 "Invalid VramInfo table.", return -1);
3882 PP_ASSERT_WITH_CODE((table
->num_entries
<= MAX_AC_TIMING_ENTRIES
),
3883 "Invalid VramInfo table.", return -1);
3885 for (i
= 0; i
< table
->last
; i
++) {
3886 ni_table
->mc_reg_address
[i
].s1
= table
->mc_reg_address
[i
].s1
;
3888 ni_table
->last
= table
->last
;
3890 for (i
= 0; i
< table
->num_entries
; i
++) {
3891 ni_table
->mc_reg_table_entry
[i
].mclk_max
=
3892 table
->mc_reg_table_entry
[i
].mclk_max
;
3893 for (j
= 0; j
< table
->last
; j
++) {
3894 ni_table
->mc_reg_table_entry
[i
].mc_data
[j
] =
3895 table
->mc_reg_table_entry
[i
].mc_data
[j
];
3898 ni_table
->num_entries
= table
->num_entries
;
3904 * VBIOS omits some information to reduce size, we need to recover them here.
3905 * 1. when we see 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]
3907 * 2. when we see mmMC_SEQ_RESERVE_M, bit[15:0] EMRS2, need to be write to mmMC_PMG_CMD_MRS1/_LP[15:0].
3908 * 3. need to set these data for each clock range
3910 * @param hwmgr the address of the powerplay hardware manager.
3911 * @param table the address of MCRegTable
3914 int tonga_set_mc_special_registers(struct pp_hwmgr
*hwmgr
, phw_tonga_mc_reg_table
*table
)
3918 const tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
3920 for (i
= 0, j
= table
->last
; i
< table
->last
; i
++) {
3921 PP_ASSERT_WITH_CODE((j
< SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3922 "Invalid VramInfo table.", return -1);
3923 switch (table
->mc_reg_address
[i
].s1
) {
3925 * mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to mmMC_PMG_CMD_EMRS /_LP[15:0].
3926 * Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
3928 case mmMC_SEQ_MISC1
:
3929 temp_reg
= cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_EMRS
);
3930 table
->mc_reg_address
[j
].s1
= mmMC_PMG_CMD_EMRS
;
3931 table
->mc_reg_address
[j
].s0
= mmMC_SEQ_PMG_CMD_EMRS_LP
;
3932 for (k
= 0; k
< table
->num_entries
; k
++) {
3933 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3934 ((temp_reg
& 0xffff0000)) |
3935 ((table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0xffff0000) >> 16);
3938 PP_ASSERT_WITH_CODE((j
< SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3939 "Invalid VramInfo table.", return -1);
3941 temp_reg
= cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS
);
3942 table
->mc_reg_address
[j
].s1
= mmMC_PMG_CMD_MRS
;
3943 table
->mc_reg_address
[j
].s0
= mmMC_SEQ_PMG_CMD_MRS_LP
;
3944 for (k
= 0; k
< table
->num_entries
; k
++) {
3945 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3946 (temp_reg
& 0xffff0000) |
3947 (table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0x0000ffff);
3949 if (!data
->is_memory_GDDR5
) {
3950 table
->mc_reg_table_entry
[k
].mc_data
[j
] |= 0x100;
3954 PP_ASSERT_WITH_CODE((j
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3955 "Invalid VramInfo table.", return -1);
3957 if (!data
->is_memory_GDDR5
) {
3958 table
->mc_reg_address
[j
].s1
= mmMC_PMG_AUTO_CMD
;
3959 table
->mc_reg_address
[j
].s0
= mmMC_PMG_AUTO_CMD
;
3960 for (k
= 0; k
< table
->num_entries
; k
++) {
3961 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3962 (table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0xffff0000) >> 16;
3965 PP_ASSERT_WITH_CODE((j
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3966 "Invalid VramInfo table.", return -1);
3971 case mmMC_SEQ_RESERVE_M
:
3972 temp_reg
= cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS1
);
3973 table
->mc_reg_address
[j
].s1
= mmMC_PMG_CMD_MRS1
;
3974 table
->mc_reg_address
[j
].s0
= mmMC_SEQ_PMG_CMD_MRS1_LP
;
3975 for (k
= 0; k
< table
->num_entries
; k
++) {
3976 table
->mc_reg_table_entry
[k
].mc_data
[j
] =
3977 (temp_reg
& 0xffff0000) |
3978 (table
->mc_reg_table_entry
[k
].mc_data
[i
] & 0x0000ffff);
3981 PP_ASSERT_WITH_CODE((j
<= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
),
3982 "Invalid VramInfo table.", return -1);
3996 int tonga_set_valid_flag(phw_tonga_mc_reg_table
*table
)
3999 for (i
= 0; i
< table
->last
; i
++) {
4000 for (j
= 1; j
< table
->num_entries
; j
++) {
4001 if (table
->mc_reg_table_entry
[j
-1].mc_data
[i
] !=
4002 table
->mc_reg_table_entry
[j
].mc_data
[i
]) {
4003 table
->validflag
|= (1<<i
);
4012 int tonga_initialize_mc_reg_table(struct pp_hwmgr
*hwmgr
)
4015 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
4016 pp_atomctrl_mc_reg_table
*table
;
4017 phw_tonga_mc_reg_table
*ni_table
= &data
->tonga_mc_reg_table
;
4018 uint8_t module_index
= tonga_get_memory_modile_index(hwmgr
);
4020 table
= kzalloc(sizeof(pp_atomctrl_mc_reg_table
), GFP_KERNEL
);
4025 /* Program additional LP registers that are no longer programmed by VBIOS */
4026 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING
));
4027 cgs_write_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING
));
4028 cgs_write_register(hwmgr
->device
, mmMC_SEQ_DLL_STBY_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_DLL_STBY
));
4029 cgs_write_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD0_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD0
));
4030 cgs_write_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD1_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CMD1
));
4031 cgs_write_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CTRL_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_G5PDX_CTRL
));
4032 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CMD_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CMD
));
4033 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CTL_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_DVS_CTL
));
4034 cgs_write_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING
));
4035 cgs_write_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2
));
4036 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_EMRS_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_EMRS
));
4037 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_MRS_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS
));
4038 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_MRS1_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS1
));
4039 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D0_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D0
));
4040 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1
));
4041 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0
));
4042 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1
));
4043 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING
));
4044 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_CMD_MRS2_LP
, cgs_read_register(hwmgr
->device
, mmMC_PMG_CMD_MRS2
));
4045 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_2_LP
, cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_2
));
4047 memset(table
, 0x00, sizeof(pp_atomctrl_mc_reg_table
));
4049 result
= atomctrl_initialize_mc_reg_table(hwmgr
, module_index
, table
);
4052 result
= tonga_copy_vbios_smc_reg_table(table
, ni_table
);
4055 tonga_set_s0_mc_reg_index(ni_table
);
4056 result
= tonga_set_mc_special_registers(hwmgr
, ni_table
);
4060 tonga_set_valid_flag(ni_table
);
4067 * Copy one arb setting to another and then switch the active set.
4068 * arbFreqSrc and arbFreqDest is one of the MC_CG_ARB_FREQ_Fx constants.
4070 int tonga_copy_and_switch_arb_sets(struct pp_hwmgr
*hwmgr
,
4071 uint32_t arbFreqSrc
, uint32_t arbFreqDest
)
4073 uint32_t mc_arb_dram_timing
;
4074 uint32_t mc_arb_dram_timing2
;
4075 uint32_t burst_time
;
4076 uint32_t mc_cg_config
;
4078 switch (arbFreqSrc
) {
4079 case MC_CG_ARB_FREQ_F0
:
4080 mc_arb_dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
4081 mc_arb_dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
4082 burst_time
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
);
4085 case MC_CG_ARB_FREQ_F1
:
4086 mc_arb_dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING_1
);
4087 mc_arb_dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2_1
);
4088 burst_time
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE1
);
4095 switch (arbFreqDest
) {
4096 case MC_CG_ARB_FREQ_F0
:
4097 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
, mc_arb_dram_timing
);
4098 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
, mc_arb_dram_timing2
);
4099 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
, burst_time
);
4102 case MC_CG_ARB_FREQ_F1
:
4103 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING_1
, mc_arb_dram_timing
);
4104 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2_1
, mc_arb_dram_timing2
);
4105 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE1
, burst_time
);
4112 mc_cg_config
= cgs_read_register(hwmgr
->device
, mmMC_CG_CONFIG
);
4113 mc_cg_config
|= 0x0000000F;
4114 cgs_write_register(hwmgr
->device
, mmMC_CG_CONFIG
, mc_cg_config
);
4115 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_CG
, CG_ARB_REQ
, arbFreqDest
);
4121 * Initial switch from ARB F0->F1
4123 * @param hwmgr the address of the powerplay hardware manager.
4125 * This function is to be called from the SetPowerState table.
4127 int tonga_initial_switch_from_arb_f0_to_f1(struct pp_hwmgr
*hwmgr
)
4129 return tonga_copy_and_switch_arb_sets(hwmgr
, MC_CG_ARB_FREQ_F0
, MC_CG_ARB_FREQ_F1
);
4133 * Initialize the ARB DRAM timing table's index field.
4135 * @param hwmgr the address of the powerplay hardware manager.
4138 int tonga_init_arb_table_index(struct pp_hwmgr
*hwmgr
)
4140 const tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4145 * This is a read-modify-write on the first byte of the ARB table.
4146 * The first byte in the SMU72_Discrete_MCArbDramTimingTable structure is the field 'current'.
4147 * This solution is ugly, but we never write the whole table only individual fields in it.
4148 * In reality this field should not be in that structure but in a soft register.
4150 result
= tonga_read_smc_sram_dword(hwmgr
->smumgr
,
4151 data
->arb_table_start
, &tmp
, data
->sram_end
);
4157 tmp
|= ((uint32_t)MC_CG_ARB_FREQ_F1
) << 24;
4159 return tonga_write_smc_sram_dword(hwmgr
->smumgr
,
4160 data
->arb_table_start
, tmp
, data
->sram_end
);
4163 int tonga_populate_mc_reg_address(struct pp_hwmgr
*hwmgr
, SMU72_Discrete_MCRegisters
*mc_reg_table
)
4165 const struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4169 for (i
= 0, j
= 0; j
< data
->tonga_mc_reg_table
.last
; j
++) {
4170 if (data
->tonga_mc_reg_table
.validflag
& 1<<j
) {
4171 PP_ASSERT_WITH_CODE(i
< SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE
,
4172 "Index of mc_reg_table->address[] array out of boundary", return -1);
4173 mc_reg_table
->address
[i
].s0
=
4174 PP_HOST_TO_SMC_US(data
->tonga_mc_reg_table
.mc_reg_address
[j
].s0
);
4175 mc_reg_table
->address
[i
].s1
=
4176 PP_HOST_TO_SMC_US(data
->tonga_mc_reg_table
.mc_reg_address
[j
].s1
);
4181 mc_reg_table
->last
= (uint8_t)i
;
4186 /*convert register values from driver to SMC format */
4187 void tonga_convert_mc_registers(
4188 const phw_tonga_mc_reg_entry
* pEntry
,
4189 SMU72_Discrete_MCRegisterSet
*pData
,
4190 uint32_t numEntries
, uint32_t validflag
)
4194 for (i
= 0, j
= 0; j
< numEntries
; j
++) {
4195 if (validflag
& 1<<j
) {
4196 pData
->value
[i
] = PP_HOST_TO_SMC_UL(pEntry
->mc_data
[j
]);
4202 /* find the entry in the memory range table, then populate the value to SMC's tonga_mc_reg_table */
4203 int tonga_convert_mc_reg_table_entry_to_smc(
4204 struct pp_hwmgr
*hwmgr
,
4205 const uint32_t memory_clock
,
4206 SMU72_Discrete_MCRegisterSet
*mc_reg_table_data
4209 const tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4212 for (i
= 0; i
< data
->tonga_mc_reg_table
.num_entries
; i
++) {
4214 data
->tonga_mc_reg_table
.mc_reg_table_entry
[i
].mclk_max
) {
4219 if ((i
== data
->tonga_mc_reg_table
.num_entries
) && (i
> 0))
4222 tonga_convert_mc_registers(&data
->tonga_mc_reg_table
.mc_reg_table_entry
[i
],
4223 mc_reg_table_data
, data
->tonga_mc_reg_table
.last
, data
->tonga_mc_reg_table
.validflag
);
4228 int tonga_convert_mc_reg_table_to_smc(struct pp_hwmgr
*hwmgr
,
4229 SMU72_Discrete_MCRegisters
*mc_reg_table
)
4232 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4236 for (i
= 0; i
< data
->dpm_table
.mclk_table
.count
; i
++) {
4237 res
= tonga_convert_mc_reg_table_entry_to_smc(
4239 data
->dpm_table
.mclk_table
.dpm_levels
[i
].value
,
4240 &mc_reg_table
->data
[i
]
4250 int tonga_populate_initial_mc_reg_table(struct pp_hwmgr
*hwmgr
)
4253 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4255 memset(&data
->mc_reg_table
, 0x00, sizeof(SMU72_Discrete_MCRegisters
));
4256 result
= tonga_populate_mc_reg_address(hwmgr
, &(data
->mc_reg_table
));
4257 PP_ASSERT_WITH_CODE(0 == result
,
4258 "Failed to initialize MCRegTable for the MC register addresses!", return result
;);
4260 result
= tonga_convert_mc_reg_table_to_smc(hwmgr
, &data
->mc_reg_table
);
4261 PP_ASSERT_WITH_CODE(0 == result
,
4262 "Failed to initialize MCRegTable for driver state!", return result
;);
4264 return tonga_copy_bytes_to_smc(hwmgr
->smumgr
, data
->mc_reg_table_start
,
4265 (uint8_t *)&data
->mc_reg_table
, sizeof(SMU72_Discrete_MCRegisters
), data
->sram_end
);
4269 * Programs static screed detection parameters
4271 * @param hwmgr the address of the powerplay hardware manager.
4274 int tonga_program_static_screen_threshold_parameters(struct pp_hwmgr
*hwmgr
)
4276 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
4278 /* Set static screen threshold unit*/
4279 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
,
4280 CGS_IND_REG__SMC
, CG_STATIC_SCREEN_PARAMETER
, STATIC_SCREEN_THRESHOLD_UNIT
,
4281 data
->static_screen_threshold_unit
);
4282 /* Set static screen threshold*/
4283 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
,
4284 CGS_IND_REG__SMC
, CG_STATIC_SCREEN_PARAMETER
, STATIC_SCREEN_THRESHOLD
,
4285 data
->static_screen_threshold
);
4291 * Setup display gap for glitch free memory clock switching.
4293 * @param hwmgr the address of the powerplay hardware manager.
4296 int tonga_enable_display_gap(struct pp_hwmgr
*hwmgr
)
4298 uint32_t display_gap
= cgs_read_ind_register(hwmgr
->device
,
4299 CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
);
4301 display_gap
= PHM_SET_FIELD(display_gap
,
4302 CG_DISPLAY_GAP_CNTL
, DISP_GAP
, DISPLAY_GAP_IGNORE
);
4304 display_gap
= PHM_SET_FIELD(display_gap
,
4305 CG_DISPLAY_GAP_CNTL
, DISP_GAP_MCHG
, DISPLAY_GAP_VBLANK
);
4307 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4308 ixCG_DISPLAY_GAP_CNTL
, display_gap
);
4314 * Programs activity state transition voting clients
4316 * @param hwmgr the address of the powerplay hardware manager.
4319 int tonga_program_voting_clients(struct pp_hwmgr
*hwmgr
)
4321 tonga_hwmgr
*data
= (tonga_hwmgr
*)(hwmgr
->backend
);
4323 /* Clear reset for voting clients before enabling DPM */
4324 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
4325 SCLK_PWRMGT_CNTL
, RESET_SCLK_CNT
, 0);
4326 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
4327 SCLK_PWRMGT_CNTL
, RESET_BUSY_CNT
, 0);
4329 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4330 ixCG_FREQ_TRAN_VOTING_0
, data
->voting_rights_clients0
);
4331 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4332 ixCG_FREQ_TRAN_VOTING_1
, data
->voting_rights_clients1
);
4333 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4334 ixCG_FREQ_TRAN_VOTING_2
, data
->voting_rights_clients2
);
4335 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4336 ixCG_FREQ_TRAN_VOTING_3
, data
->voting_rights_clients3
);
4337 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4338 ixCG_FREQ_TRAN_VOTING_4
, data
->voting_rights_clients4
);
4339 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4340 ixCG_FREQ_TRAN_VOTING_5
, data
->voting_rights_clients5
);
4341 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4342 ixCG_FREQ_TRAN_VOTING_6
, data
->voting_rights_clients6
);
4343 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4344 ixCG_FREQ_TRAN_VOTING_7
, data
->voting_rights_clients7
);
4350 int tonga_enable_dpm_tasks(struct pp_hwmgr
*hwmgr
)
4352 int tmp_result
, result
= 0;
4354 tmp_result
= tonga_check_for_dpm_stopped(hwmgr
);
4356 if (cf_tonga_voltage_control(hwmgr
)) {
4357 tmp_result
= tonga_enable_voltage_control(hwmgr
);
4358 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4359 "Failed to enable voltage control!", result
= tmp_result
);
4361 tmp_result
= tonga_construct_voltage_tables(hwmgr
);
4362 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4363 "Failed to contruct voltage tables!", result
= tmp_result
);
4366 tmp_result
= tonga_initialize_mc_reg_table(hwmgr
);
4367 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4368 "Failed to initialize MC reg table!", result
= tmp_result
);
4370 tmp_result
= tonga_program_static_screen_threshold_parameters(hwmgr
);
4371 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4372 "Failed to program static screen threshold parameters!", result
= tmp_result
);
4374 tmp_result
= tonga_enable_display_gap(hwmgr
);
4375 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4376 "Failed to enable display gap!", result
= tmp_result
);
4378 tmp_result
= tonga_program_voting_clients(hwmgr
);
4379 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4380 "Failed to program voting clients!", result
= tmp_result
);
4382 tmp_result
= tonga_process_firmware_header(hwmgr
);
4383 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4384 "Failed to process firmware header!", result
= tmp_result
);
4386 tmp_result
= tonga_initial_switch_from_arb_f0_to_f1(hwmgr
);
4387 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4388 "Failed to initialize switch from ArbF0 to F1!", result
= tmp_result
);
4390 tmp_result
= tonga_init_smc_table(hwmgr
);
4391 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4392 "Failed to initialize SMC table!", result
= tmp_result
);
4394 tmp_result
= tonga_init_arb_table_index(hwmgr
);
4395 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4396 "Failed to initialize ARB table index!", result
= tmp_result
);
4398 tmp_result
= tonga_populate_initial_mc_reg_table(hwmgr
);
4399 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4400 "Failed to populate initialize MC Reg table!", result
= tmp_result
);
4402 tmp_result
= tonga_notify_smc_display_change(hwmgr
, false);
4403 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4404 "Failed to notify no display!", result
= tmp_result
);
4406 /* enable SCLK control */
4407 tmp_result
= tonga_enable_sclk_control(hwmgr
);
4408 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4409 "Failed to enable SCLK control!", result
= tmp_result
);
4412 tmp_result
= tonga_start_dpm(hwmgr
);
4413 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4414 "Failed to start DPM!", result
= tmp_result
);
4419 int tonga_disable_dpm_tasks(struct pp_hwmgr
*hwmgr
)
4421 int tmp_result
, result
= 0;
4423 tmp_result
= tonga_check_for_dpm_running(hwmgr
);
4424 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4425 "SMC is still running!", return 0);
4427 tmp_result
= tonga_stop_dpm(hwmgr
);
4428 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4429 "Failed to stop DPM!", result
= tmp_result
);
4431 tmp_result
= tonga_reset_to_default(hwmgr
);
4432 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4433 "Failed to reset to default!", result
= tmp_result
);
4438 int tonga_reset_asic_tasks(struct pp_hwmgr
*hwmgr
)
4442 result
= tonga_set_boot_state(hwmgr
);
4444 printk(KERN_ERR
"[ powerplay ] Failed to reset asic via set boot state! \n");
4449 int tonga_hwmgr_backend_fini(struct pp_hwmgr
*hwmgr
)
4451 if (NULL
!= hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
) {
4452 kfree(hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
);
4453 hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
= NULL
;
4456 if (NULL
!= hwmgr
->backend
) {
4457 kfree(hwmgr
->backend
);
4458 hwmgr
->backend
= NULL
;
4465 * Initializes the Volcanic Islands Hardware Manager
4467 * @param hwmgr the address of the powerplay hardware manager.
4468 * @return 1 if success; otherwise appropriate error code.
4470 int tonga_hwmgr_backend_init(struct pp_hwmgr
*hwmgr
)
4473 SMU72_Discrete_DpmTable
*table
= NULL
;
4474 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4475 pp_atomctrl_gpio_pin_assignment gpio_pin_assignment
;
4476 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4477 phw_tonga_ulv_parm
*ulv
;
4479 PP_ASSERT_WITH_CODE((NULL
!= hwmgr
),
4480 "Invalid Parameter!", return -1;);
4482 data
->dll_defaule_on
= 0;
4483 data
->sram_end
= SMC_RAM_END
;
4485 data
->activity_target
[0] = PPTONGA_TARGETACTIVITY_DFLT
;
4486 data
->activity_target
[1] = PPTONGA_TARGETACTIVITY_DFLT
;
4487 data
->activity_target
[2] = PPTONGA_TARGETACTIVITY_DFLT
;
4488 data
->activity_target
[3] = PPTONGA_TARGETACTIVITY_DFLT
;
4489 data
->activity_target
[4] = PPTONGA_TARGETACTIVITY_DFLT
;
4490 data
->activity_target
[5] = PPTONGA_TARGETACTIVITY_DFLT
;
4491 data
->activity_target
[6] = PPTONGA_TARGETACTIVITY_DFLT
;
4492 data
->activity_target
[7] = PPTONGA_TARGETACTIVITY_DFLT
;
4494 data
->vddc_vddci_delta
= VDDC_VDDCI_DELTA
;
4495 data
->vddc_vddgfx_delta
= VDDC_VDDGFX_DELTA
;
4496 data
->mclk_activity_target
= PPTONGA_MCLK_TARGETACTIVITY_DFLT
;
4498 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4499 PHM_PlatformCaps_DisableVoltageIsland
);
4501 data
->sclk_dpm_key_disabled
= 0;
4502 data
->mclk_dpm_key_disabled
= 0;
4503 data
->pcie_dpm_key_disabled
= 0;
4504 data
->pcc_monitor_enabled
= 0;
4506 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4507 PHM_PlatformCaps_UnTabledHardwareInterface
);
4509 data
->gpio_debug
= 0;
4510 data
->engine_clock_data
= 0;
4511 data
->memory_clock_data
= 0;
4512 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4513 PHM_PlatformCaps_DynamicPatchPowerState
);
4515 /* need to set voltage control types before EVV patching*/
4516 data
->voltage_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4517 data
->vdd_ci_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4518 data
->vdd_gfx_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4519 data
->mvdd_control
= TONGA_VOLTAGE_CONTROL_NONE
;
4521 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4522 VOLTAGE_TYPE_VDDC
, VOLTAGE_OBJ_SVID2
)) {
4523 data
->voltage_control
= TONGA_VOLTAGE_CONTROL_BY_SVID2
;
4526 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4527 PHM_PlatformCaps_ControlVDDGFX
)) {
4528 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4529 VOLTAGE_TYPE_VDDGFX
, VOLTAGE_OBJ_SVID2
)) {
4530 data
->vdd_gfx_control
= TONGA_VOLTAGE_CONTROL_BY_SVID2
;
4534 if (TONGA_VOLTAGE_CONTROL_NONE
== data
->vdd_gfx_control
) {
4535 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4536 PHM_PlatformCaps_ControlVDDGFX
);
4539 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4540 PHM_PlatformCaps_EnableMVDDControl
)) {
4541 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4542 VOLTAGE_TYPE_MVDDC
, VOLTAGE_OBJ_GPIO_LUT
)) {
4543 data
->mvdd_control
= TONGA_VOLTAGE_CONTROL_BY_GPIO
;
4547 if (TONGA_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
) {
4548 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4549 PHM_PlatformCaps_EnableMVDDControl
);
4552 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4553 PHM_PlatformCaps_ControlVDDCI
)) {
4554 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4555 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_GPIO_LUT
))
4556 data
->vdd_ci_control
= TONGA_VOLTAGE_CONTROL_BY_GPIO
;
4557 else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
4558 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_SVID2
))
4559 data
->vdd_ci_control
= TONGA_VOLTAGE_CONTROL_BY_SVID2
;
4562 if (TONGA_VOLTAGE_CONTROL_NONE
== data
->vdd_ci_control
)
4563 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
4564 PHM_PlatformCaps_ControlVDDCI
);
4566 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4567 PHM_PlatformCaps_TablelessHardwareInterface
);
4569 if (pptable_info
->cac_dtp_table
->usClockStretchAmount
!= 0)
4570 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4571 PHM_PlatformCaps_ClockStretcher
);
4573 /* Initializes DPM default values*/
4574 tonga_initialize_dpm_defaults(hwmgr
);
4576 /* Get leakage voltage based on leakage ID.*/
4577 PP_ASSERT_WITH_CODE((0 == tonga_get_evv_voltage(hwmgr
)),
4578 "Get EVV Voltage Failed. Abort Driver loading!", return -1);
4580 tonga_complete_dependency_tables(hwmgr
);
4582 /* Parse pptable data read from VBIOS*/
4583 tonga_set_private_var_based_on_pptale(hwmgr
);
4587 ulv
->ulv_supported
= 0;
4589 /* Initalize Dynamic State Adjustment Rule Settings*/
4590 result
= tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr
);
4591 data
->uvd_enabled
= 0;
4593 table
= &(data
->smc_state_table
);
4596 * if ucGPIO_ID=VDDC_PCC_GPIO_PINID in GPIO_LUTable,
4597 * Peak Current Control feature is enabled and we should program PCC HW register
4599 if (0 == atomctrl_get_pp_assign_pin(hwmgr
, VDDC_PCC_GPIO_PINID
, &gpio_pin_assignment
)) {
4600 uint32_t temp_reg
= cgs_read_ind_register(hwmgr
->device
,
4601 CGS_IND_REG__SMC
, ixCNB_PWRMGT_CNTL
);
4603 switch (gpio_pin_assignment
.uc_gpio_pin_bit_shift
) {
4605 temp_reg
= PHM_SET_FIELD(temp_reg
,
4606 CNB_PWRMGT_CNTL
, GNB_SLOW_MODE
, 0x1);
4609 temp_reg
= PHM_SET_FIELD(temp_reg
,
4610 CNB_PWRMGT_CNTL
, GNB_SLOW_MODE
, 0x2);
4613 temp_reg
= PHM_SET_FIELD(temp_reg
,
4614 CNB_PWRMGT_CNTL
, GNB_SLOW
, 0x1);
4617 temp_reg
= PHM_SET_FIELD(temp_reg
,
4618 CNB_PWRMGT_CNTL
, FORCE_NB_PS1
, 0x1);
4621 temp_reg
= PHM_SET_FIELD(temp_reg
,
4622 CNB_PWRMGT_CNTL
, DPM_ENABLED
, 0x1);
4625 printk(KERN_ERR
"[ powerplay ] Failed to setup PCC HW register! \
4626 Wrong GPIO assigned for VDDC_PCC_GPIO_PINID! \n");
4629 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
4630 ixCNB_PWRMGT_CNTL
, temp_reg
);
4633 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4634 PHM_PlatformCaps_EnableSMU7ThermalManagement
);
4635 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
4636 PHM_PlatformCaps_SMU7
);
4638 data
->vddc_phase_shed_control
= 0;
4641 data
->is_tlu_enabled
= 0;
4642 hwmgr
->platform_descriptor
.hardwareActivityPerformanceLevels
=
4643 TONGA_MAX_HARDWARE_POWERLEVELS
;
4644 hwmgr
->platform_descriptor
.hardwarePerformanceLevels
= 2;
4645 hwmgr
->platform_descriptor
.minimumClocksReductionPercentage
= 50;
4647 data
->pcie_gen_cap
= 0x30007;
4648 data
->pcie_lane_cap
= 0x2f0000;
4650 /* Ignore return value in here, we are cleaning up a mess. */
4651 tonga_hwmgr_backend_fini(hwmgr
);
4657 static int tonga_force_dpm_level(struct pp_hwmgr
*hwmgr
,
4658 enum amd_dpm_forced_level level
)
4663 case AMD_DPM_FORCED_LEVEL_HIGH
:
4664 ret
= tonga_force_dpm_highest(hwmgr
);
4668 case AMD_DPM_FORCED_LEVEL_LOW
:
4669 ret
= tonga_force_dpm_lowest(hwmgr
);
4673 case AMD_DPM_FORCED_LEVEL_AUTO
:
4674 ret
= tonga_unforce_dpm_levels(hwmgr
);
4682 hwmgr
->dpm_level
= level
;
4686 static int tonga_apply_state_adjust_rules(struct pp_hwmgr
*hwmgr
,
4687 struct pp_power_state
*prequest_ps
,
4688 const struct pp_power_state
*pcurrent_ps
)
4690 struct tonga_power_state
*tonga_ps
=
4691 cast_phw_tonga_power_state(&prequest_ps
->hardware
);
4695 struct PP_Clocks minimum_clocks
= {0};
4696 bool disable_mclk_switching
;
4697 bool disable_mclk_switching_for_frame_lock
;
4698 struct cgs_display_info info
= {0};
4699 const struct phm_clock_and_voltage_limits
*max_limits
;
4701 tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4702 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4705 int32_t stable_pstate_sclk
= 0, stable_pstate_mclk
= 0;
4707 data
->battery_state
= (PP_StateUILabel_Battery
== prequest_ps
->classification
.ui_label
);
4709 PP_ASSERT_WITH_CODE(tonga_ps
->performance_level_count
== 2,
4710 "VI should always have 2 performance levels",
4713 max_limits
= (PP_PowerSource_AC
== hwmgr
->power_source
) ?
4714 &(hwmgr
->dyn_state
.max_clock_voltage_on_ac
) :
4715 &(hwmgr
->dyn_state
.max_clock_voltage_on_dc
);
4717 if (PP_PowerSource_DC
== hwmgr
->power_source
) {
4718 for (i
= 0; i
< tonga_ps
->performance_level_count
; i
++) {
4719 if (tonga_ps
->performance_levels
[i
].memory_clock
> max_limits
->mclk
)
4720 tonga_ps
->performance_levels
[i
].memory_clock
= max_limits
->mclk
;
4721 if (tonga_ps
->performance_levels
[i
].engine_clock
> max_limits
->sclk
)
4722 tonga_ps
->performance_levels
[i
].engine_clock
= max_limits
->sclk
;
4726 tonga_ps
->vce_clocks
.EVCLK
= hwmgr
->vce_arbiter
.evclk
;
4727 tonga_ps
->vce_clocks
.ECCLK
= hwmgr
->vce_arbiter
.ecclk
;
4729 tonga_ps
->acp_clk
= hwmgr
->acp_arbiter
.acpclk
;
4731 cgs_get_active_displays_info(hwmgr
->device
, &info
);
4733 /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
4735 /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
4737 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
)) {
4739 max_limits
= &(hwmgr
->dyn_state
.max_clock_voltage_on_ac
);
4740 stable_pstate_sclk
= (max_limits
->sclk
* 75) / 100;
4742 for (count
= pptable_info
->vdd_dep_on_sclk
->count
-1; count
>= 0; count
--) {
4743 if (stable_pstate_sclk
>= pptable_info
->vdd_dep_on_sclk
->entries
[count
].clk
) {
4744 stable_pstate_sclk
= pptable_info
->vdd_dep_on_sclk
->entries
[count
].clk
;
4750 stable_pstate_sclk
= pptable_info
->vdd_dep_on_sclk
->entries
[0].clk
;
4752 stable_pstate_mclk
= max_limits
->mclk
;
4754 minimum_clocks
.engineClock
= stable_pstate_sclk
;
4755 minimum_clocks
.memoryClock
= stable_pstate_mclk
;
4758 if (minimum_clocks
.engineClock
< hwmgr
->gfx_arbiter
.sclk
)
4759 minimum_clocks
.engineClock
= hwmgr
->gfx_arbiter
.sclk
;
4761 if (minimum_clocks
.memoryClock
< hwmgr
->gfx_arbiter
.mclk
)
4762 minimum_clocks
.memoryClock
= hwmgr
->gfx_arbiter
.mclk
;
4764 tonga_ps
->sclk_threshold
= hwmgr
->gfx_arbiter
.sclk_threshold
;
4766 if (0 != hwmgr
->gfx_arbiter
.sclk_over_drive
) {
4767 PP_ASSERT_WITH_CODE((hwmgr
->gfx_arbiter
.sclk_over_drive
<= hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
),
4768 "Overdrive sclk exceeds limit",
4769 hwmgr
->gfx_arbiter
.sclk_over_drive
= hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
);
4771 if (hwmgr
->gfx_arbiter
.sclk_over_drive
>= hwmgr
->gfx_arbiter
.sclk
)
4772 tonga_ps
->performance_levels
[1].engine_clock
= hwmgr
->gfx_arbiter
.sclk_over_drive
;
4775 if (0 != hwmgr
->gfx_arbiter
.mclk_over_drive
) {
4776 PP_ASSERT_WITH_CODE((hwmgr
->gfx_arbiter
.mclk_over_drive
<= hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
),
4777 "Overdrive mclk exceeds limit",
4778 hwmgr
->gfx_arbiter
.mclk_over_drive
= hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
);
4780 if (hwmgr
->gfx_arbiter
.mclk_over_drive
>= hwmgr
->gfx_arbiter
.mclk
)
4781 tonga_ps
->performance_levels
[1].memory_clock
= hwmgr
->gfx_arbiter
.mclk_over_drive
;
4784 disable_mclk_switching_for_frame_lock
= phm_cap_enabled(
4785 hwmgr
->platform_descriptor
.platformCaps
,
4786 PHM_PlatformCaps_DisableMclkSwitchingForFrameLock
);
4788 disable_mclk_switching
= (1 < info
.display_count
) ||
4789 disable_mclk_switching_for_frame_lock
;
4791 sclk
= tonga_ps
->performance_levels
[0].engine_clock
;
4792 mclk
= tonga_ps
->performance_levels
[0].memory_clock
;
4794 if (disable_mclk_switching
)
4795 mclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
- 1].memory_clock
;
4797 if (sclk
< minimum_clocks
.engineClock
)
4798 sclk
= (minimum_clocks
.engineClock
> max_limits
->sclk
) ? max_limits
->sclk
: minimum_clocks
.engineClock
;
4800 if (mclk
< minimum_clocks
.memoryClock
)
4801 mclk
= (minimum_clocks
.memoryClock
> max_limits
->mclk
) ? max_limits
->mclk
: minimum_clocks
.memoryClock
;
4803 tonga_ps
->performance_levels
[0].engine_clock
= sclk
;
4804 tonga_ps
->performance_levels
[0].memory_clock
= mclk
;
4806 tonga_ps
->performance_levels
[1].engine_clock
=
4807 (tonga_ps
->performance_levels
[1].engine_clock
>= tonga_ps
->performance_levels
[0].engine_clock
) ?
4808 tonga_ps
->performance_levels
[1].engine_clock
:
4809 tonga_ps
->performance_levels
[0].engine_clock
;
4811 if (disable_mclk_switching
) {
4812 if (mclk
< tonga_ps
->performance_levels
[1].memory_clock
)
4813 mclk
= tonga_ps
->performance_levels
[1].memory_clock
;
4815 tonga_ps
->performance_levels
[0].memory_clock
= mclk
;
4816 tonga_ps
->performance_levels
[1].memory_clock
= mclk
;
4818 if (tonga_ps
->performance_levels
[1].memory_clock
< tonga_ps
->performance_levels
[0].memory_clock
)
4819 tonga_ps
->performance_levels
[1].memory_clock
= tonga_ps
->performance_levels
[0].memory_clock
;
4822 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
)) {
4823 for (i
=0; i
< tonga_ps
->performance_level_count
; i
++) {
4824 tonga_ps
->performance_levels
[i
].engine_clock
= stable_pstate_sclk
;
4825 tonga_ps
->performance_levels
[i
].memory_clock
= stable_pstate_mclk
;
4826 tonga_ps
->performance_levels
[i
].pcie_gen
= data
->pcie_gen_performance
.max
;
4827 tonga_ps
->performance_levels
[i
].pcie_lane
= data
->pcie_gen_performance
.max
;
4834 int tonga_get_power_state_size(struct pp_hwmgr
*hwmgr
)
4836 return sizeof(struct tonga_power_state
);
4839 static int tonga_dpm_get_mclk(struct pp_hwmgr
*hwmgr
, bool low
)
4841 struct pp_power_state
*ps
;
4842 struct tonga_power_state
*tonga_ps
;
4847 ps
= hwmgr
->request_ps
;
4852 tonga_ps
= cast_phw_tonga_power_state(&ps
->hardware
);
4855 return tonga_ps
->performance_levels
[0].memory_clock
;
4857 return tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].memory_clock
;
4860 static int tonga_dpm_get_sclk(struct pp_hwmgr
*hwmgr
, bool low
)
4862 struct pp_power_state
*ps
;
4863 struct tonga_power_state
*tonga_ps
;
4868 ps
= hwmgr
->request_ps
;
4873 tonga_ps
= cast_phw_tonga_power_state(&ps
->hardware
);
4876 return tonga_ps
->performance_levels
[0].engine_clock
;
4878 return tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].engine_clock
;
4881 static uint16_t tonga_get_current_pcie_speed(
4882 struct pp_hwmgr
*hwmgr
)
4884 uint32_t speed_cntl
= 0;
4886 speed_cntl
= cgs_read_ind_register(hwmgr
->device
,
4888 ixPCIE_LC_SPEED_CNTL
);
4889 return((uint16_t)PHM_GET_FIELD(speed_cntl
,
4890 PCIE_LC_SPEED_CNTL
, LC_CURRENT_DATA_RATE
));
4893 static int tonga_get_current_pcie_lane_number(
4894 struct pp_hwmgr
*hwmgr
)
4896 uint32_t link_width
;
4898 link_width
= PHM_READ_INDIRECT_FIELD(hwmgr
->device
,
4900 PCIE_LC_LINK_WIDTH_CNTL
,
4903 PP_ASSERT_WITH_CODE((7 >= link_width
),
4904 "Invalid PCIe lane width!", return 0);
4906 return decode_pcie_lane_width(link_width
);
4909 static int tonga_dpm_patch_boot_state(struct pp_hwmgr
*hwmgr
,
4910 struct pp_hw_power_state
*hw_ps
)
4912 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4913 struct tonga_power_state
*ps
= (struct tonga_power_state
*)hw_ps
;
4914 ATOM_FIRMWARE_INFO_V2_2
*fw_info
;
4917 int index
= GetIndexIntoMasterTable(DATA
, FirmwareInfo
);
4919 /* First retrieve the Boot clocks and VDDC from the firmware info table.
4920 * We assume here that fw_info is unchanged if this call fails.
4922 fw_info
= (ATOM_FIRMWARE_INFO_V2_2
*)cgs_atom_get_data_table(
4923 hwmgr
->device
, index
,
4924 &size
, &frev
, &crev
);
4926 /* During a test, there is no firmware info table. */
4929 /* Patch the state. */
4930 data
->vbios_boot_state
.sclk_bootup_value
= le32_to_cpu(fw_info
->ulDefaultEngineClock
);
4931 data
->vbios_boot_state
.mclk_bootup_value
= le32_to_cpu(fw_info
->ulDefaultMemoryClock
);
4932 data
->vbios_boot_state
.mvdd_bootup_value
= le16_to_cpu(fw_info
->usBootUpMVDDCVoltage
);
4933 data
->vbios_boot_state
.vddc_bootup_value
= le16_to_cpu(fw_info
->usBootUpVDDCVoltage
);
4934 data
->vbios_boot_state
.vddci_bootup_value
= le16_to_cpu(fw_info
->usBootUpVDDCIVoltage
);
4935 data
->vbios_boot_state
.pcie_gen_bootup_value
= tonga_get_current_pcie_speed(hwmgr
);
4936 data
->vbios_boot_state
.pcie_lane_bootup_value
=
4937 (uint16_t)tonga_get_current_pcie_lane_number(hwmgr
);
4939 /* set boot power state */
4940 ps
->performance_levels
[0].memory_clock
= data
->vbios_boot_state
.mclk_bootup_value
;
4941 ps
->performance_levels
[0].engine_clock
= data
->vbios_boot_state
.sclk_bootup_value
;
4942 ps
->performance_levels
[0].pcie_gen
= data
->vbios_boot_state
.pcie_gen_bootup_value
;
4943 ps
->performance_levels
[0].pcie_lane
= data
->vbios_boot_state
.pcie_lane_bootup_value
;
4948 static int tonga_get_pp_table_entry_callback_func(struct pp_hwmgr
*hwmgr
,
4949 void *state
, struct pp_power_state
*power_state
,
4950 void *pp_table
, uint32_t classification_flag
)
4952 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
4954 struct tonga_power_state
*tonga_ps
=
4955 (struct tonga_power_state
*)(&(power_state
->hardware
));
4957 struct tonga_performance_level
*performance_level
;
4959 ATOM_Tonga_State
*state_entry
= (ATOM_Tonga_State
*)state
;
4961 ATOM_Tonga_POWERPLAYTABLE
*powerplay_table
=
4962 (ATOM_Tonga_POWERPLAYTABLE
*)pp_table
;
4964 ATOM_Tonga_SCLK_Dependency_Table
*sclk_dep_table
=
4965 (ATOM_Tonga_SCLK_Dependency_Table
*)
4966 (((uint64_t)powerplay_table
) +
4967 le16_to_cpu(powerplay_table
->usSclkDependencyTableOffset
));
4969 ATOM_Tonga_MCLK_Dependency_Table
*mclk_dep_table
=
4970 (ATOM_Tonga_MCLK_Dependency_Table
*)
4971 (((uint64_t)powerplay_table
) +
4972 le16_to_cpu(powerplay_table
->usMclkDependencyTableOffset
));
4974 /* The following fields are not initialized here: id orderedList allStatesList */
4975 power_state
->classification
.ui_label
=
4976 (le16_to_cpu(state_entry
->usClassification
) &
4977 ATOM_PPLIB_CLASSIFICATION_UI_MASK
) >>
4978 ATOM_PPLIB_CLASSIFICATION_UI_SHIFT
;
4979 power_state
->classification
.flags
= classification_flag
;
4980 /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
4982 power_state
->classification
.temporary_state
= false;
4983 power_state
->classification
.to_be_deleted
= false;
4985 power_state
->validation
.disallowOnDC
=
4986 (0 != (le32_to_cpu(state_entry
->ulCapsAndSettings
) & ATOM_Tonga_DISALLOW_ON_DC
));
4988 power_state
->pcie
.lanes
= 0;
4990 power_state
->display
.disableFrameModulation
= false;
4991 power_state
->display
.limitRefreshrate
= false;
4992 power_state
->display
.enableVariBright
=
4993 (0 != (le32_to_cpu(state_entry
->ulCapsAndSettings
) & ATOM_Tonga_ENABLE_VARIBRIGHT
));
4995 power_state
->validation
.supportedPowerLevels
= 0;
4996 power_state
->uvd_clocks
.VCLK
= 0;
4997 power_state
->uvd_clocks
.DCLK
= 0;
4998 power_state
->temperatures
.min
= 0;
4999 power_state
->temperatures
.max
= 0;
5001 performance_level
= &(tonga_ps
->performance_levels
5002 [tonga_ps
->performance_level_count
++]);
5004 PP_ASSERT_WITH_CODE(
5005 (tonga_ps
->performance_level_count
< SMU72_MAX_LEVELS_GRAPHICS
),
5006 "Performance levels exceeds SMC limit!",
5009 PP_ASSERT_WITH_CODE(
5010 (tonga_ps
->performance_level_count
<=
5011 hwmgr
->platform_descriptor
.hardwareActivityPerformanceLevels
),
5012 "Performance levels exceeds Driver limit!",
5015 /* Performance levels are arranged from low to high. */
5016 performance_level
->memory_clock
=
5017 le32_to_cpu(mclk_dep_table
->entries
[state_entry
->ucMemoryClockIndexLow
].ulMclk
);
5019 performance_level
->engine_clock
=
5020 le32_to_cpu(sclk_dep_table
->entries
[state_entry
->ucEngineClockIndexLow
].ulSclk
);
5022 performance_level
->pcie_gen
= get_pcie_gen_support(
5024 state_entry
->ucPCIEGenLow
);
5026 performance_level
->pcie_lane
= get_pcie_lane_support(
5027 data
->pcie_lane_cap
,
5028 state_entry
->ucPCIELaneHigh
);
5031 &(tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
++]);
5033 performance_level
->memory_clock
=
5034 le32_to_cpu(mclk_dep_table
->entries
[state_entry
->ucMemoryClockIndexHigh
].ulMclk
);
5036 performance_level
->engine_clock
=
5037 le32_to_cpu(sclk_dep_table
->entries
[state_entry
->ucEngineClockIndexHigh
].ulSclk
);
5039 performance_level
->pcie_gen
= get_pcie_gen_support(
5041 state_entry
->ucPCIEGenHigh
);
5043 performance_level
->pcie_lane
= get_pcie_lane_support(
5044 data
->pcie_lane_cap
,
5045 state_entry
->ucPCIELaneHigh
);
5050 static int tonga_get_pp_table_entry(struct pp_hwmgr
*hwmgr
,
5051 unsigned long entry_index
, struct pp_power_state
*ps
)
5054 struct tonga_power_state
*tonga_ps
;
5055 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5057 struct phm_ppt_v1_information
*table_info
=
5058 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
5060 struct phm_ppt_v1_clock_voltage_dependency_table
*dep_mclk_table
=
5061 table_info
->vdd_dep_on_mclk
;
5063 ps
->hardware
.magic
= PhwTonga_Magic
;
5065 tonga_ps
= cast_phw_tonga_power_state(&(ps
->hardware
));
5067 result
= tonga_get_powerplay_table_entry(hwmgr
, entry_index
, ps
,
5068 tonga_get_pp_table_entry_callback_func
);
5070 /* This is the earliest time we have all the dependency table and the VBIOS boot state
5071 * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
5072 * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
5074 if (dep_mclk_table
!= NULL
&& dep_mclk_table
->count
== 1) {
5075 if (dep_mclk_table
->entries
[0].clk
!=
5076 data
->vbios_boot_state
.mclk_bootup_value
)
5077 printk(KERN_ERR
"Single MCLK entry VDDCI/MCLK dependency table "
5078 "does not match VBIOS boot MCLK level");
5079 if (dep_mclk_table
->entries
[0].vddci
!=
5080 data
->vbios_boot_state
.vddci_bootup_value
)
5081 printk(KERN_ERR
"Single VDDCI entry VDDCI/MCLK dependency table "
5082 "does not match VBIOS boot VDDCI level");
5085 /* set DC compatible flag if this state supports DC */
5086 if (!ps
->validation
.disallowOnDC
)
5087 tonga_ps
->dc_compatible
= true;
5089 if (ps
->classification
.flags
& PP_StateClassificationFlag_ACPI
)
5090 data
->acpi_pcie_gen
= tonga_ps
->performance_levels
[0].pcie_gen
;
5091 else if (ps
->classification
.flags
& PP_StateClassificationFlag_Boot
) {
5092 if (data
->bacos
.best_match
== 0xffff) {
5093 /* For V.I. use boot state as base BACO state */
5094 data
->bacos
.best_match
= PP_StateClassificationFlag_Boot
;
5095 data
->bacos
.performance_level
= tonga_ps
->performance_levels
[0];
5099 tonga_ps
->uvd_clocks
.VCLK
= ps
->uvd_clocks
.VCLK
;
5100 tonga_ps
->uvd_clocks
.DCLK
= ps
->uvd_clocks
.DCLK
;
5105 switch (ps
->classification
.ui_label
) {
5106 case PP_StateUILabel_Performance
:
5107 data
->use_pcie_performance_levels
= true;
5109 for (i
= 0; i
< tonga_ps
->performance_level_count
; i
++) {
5110 if (data
->pcie_gen_performance
.max
<
5111 tonga_ps
->performance_levels
[i
].pcie_gen
)
5112 data
->pcie_gen_performance
.max
=
5113 tonga_ps
->performance_levels
[i
].pcie_gen
;
5115 if (data
->pcie_gen_performance
.min
>
5116 tonga_ps
->performance_levels
[i
].pcie_gen
)
5117 data
->pcie_gen_performance
.min
=
5118 tonga_ps
->performance_levels
[i
].pcie_gen
;
5120 if (data
->pcie_lane_performance
.max
<
5121 tonga_ps
->performance_levels
[i
].pcie_lane
)
5122 data
->pcie_lane_performance
.max
=
5123 tonga_ps
->performance_levels
[i
].pcie_lane
;
5125 if (data
->pcie_lane_performance
.min
>
5126 tonga_ps
->performance_levels
[i
].pcie_lane
)
5127 data
->pcie_lane_performance
.min
=
5128 tonga_ps
->performance_levels
[i
].pcie_lane
;
5131 case PP_StateUILabel_Battery
:
5132 data
->use_pcie_power_saving_levels
= true;
5134 for (i
= 0; i
< tonga_ps
->performance_level_count
; i
++) {
5135 if (data
->pcie_gen_power_saving
.max
<
5136 tonga_ps
->performance_levels
[i
].pcie_gen
)
5137 data
->pcie_gen_power_saving
.max
=
5138 tonga_ps
->performance_levels
[i
].pcie_gen
;
5140 if (data
->pcie_gen_power_saving
.min
>
5141 tonga_ps
->performance_levels
[i
].pcie_gen
)
5142 data
->pcie_gen_power_saving
.min
=
5143 tonga_ps
->performance_levels
[i
].pcie_gen
;
5145 if (data
->pcie_lane_power_saving
.max
<
5146 tonga_ps
->performance_levels
[i
].pcie_lane
)
5147 data
->pcie_lane_power_saving
.max
=
5148 tonga_ps
->performance_levels
[i
].pcie_lane
;
5150 if (data
->pcie_lane_power_saving
.min
>
5151 tonga_ps
->performance_levels
[i
].pcie_lane
)
5152 data
->pcie_lane_power_saving
.min
=
5153 tonga_ps
->performance_levels
[i
].pcie_lane
;
5164 tonga_print_current_perforce_level(struct pp_hwmgr
*hwmgr
, struct seq_file
*m
)
5166 uint32_t sclk
, mclk
;
5168 smum_send_msg_to_smc(hwmgr
->smumgr
, (PPSMC_Msg
)(PPSMC_MSG_API_GetSclkFrequency
));
5170 sclk
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5172 smum_send_msg_to_smc(hwmgr
->smumgr
, (PPSMC_Msg
)(PPSMC_MSG_API_GetMclkFrequency
));
5174 mclk
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5175 seq_printf(m
, "\n [ mclk ]: %u MHz\n\n [ sclk ]: %u MHz\n", mclk
/100, sclk
/100);
5178 static int tonga_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr
*hwmgr
, const void *input
)
5180 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5181 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5182 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5183 struct tonga_single_dpm_table
*psclk_table
= &(data
->dpm_table
.sclk_table
);
5184 uint32_t sclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].engine_clock
;
5185 struct tonga_single_dpm_table
*pmclk_table
= &(data
->dpm_table
.mclk_table
);
5186 uint32_t mclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].memory_clock
;
5187 struct PP_Clocks min_clocks
= {0};
5189 struct cgs_display_info info
= {0};
5191 data
->need_update_smu7_dpm_table
= 0;
5193 for (i
= 0; i
< psclk_table
->count
; i
++) {
5194 if (sclk
== psclk_table
->dpm_levels
[i
].value
)
5198 if (i
>= psclk_table
->count
)
5199 data
->need_update_smu7_dpm_table
|= DPMTABLE_OD_UPDATE_SCLK
;
5201 /* TODO: Check SCLK in DAL's minimum clocks in case DeepSleep divider update is required.*/
5202 if(data
->display_timing
.min_clock_insr
!= min_clocks
.engineClockInSR
)
5203 data
->need_update_smu7_dpm_table
|= DPMTABLE_UPDATE_SCLK
;
5206 for (i
=0; i
< pmclk_table
->count
; i
++) {
5207 if (mclk
== pmclk_table
->dpm_levels
[i
].value
)
5211 if (i
>= pmclk_table
->count
)
5212 data
->need_update_smu7_dpm_table
|= DPMTABLE_OD_UPDATE_MCLK
;
5214 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5216 if (data
->display_timing
.num_existing_displays
!= info
.display_count
)
5217 data
->need_update_smu7_dpm_table
|= DPMTABLE_UPDATE_MCLK
;
5222 static uint16_t tonga_get_maximum_link_speed(struct pp_hwmgr
*hwmgr
, const struct tonga_power_state
*hw_ps
)
5225 uint32_t sclk
, max_sclk
= 0;
5226 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5227 struct tonga_dpm_table
*pdpm_table
= &data
->dpm_table
;
5229 for (i
= 0; i
< hw_ps
->performance_level_count
; i
++) {
5230 sclk
= hw_ps
->performance_levels
[i
].engine_clock
;
5231 if (max_sclk
< sclk
)
5235 for (i
= 0; i
< pdpm_table
->sclk_table
.count
; i
++) {
5236 if (pdpm_table
->sclk_table
.dpm_levels
[i
].value
== max_sclk
)
5237 return (uint16_t) ((i
>= pdpm_table
->pcie_speed_table
.count
) ?
5238 pdpm_table
->pcie_speed_table
.dpm_levels
[pdpm_table
->pcie_speed_table
.count
-1].value
:
5239 pdpm_table
->pcie_speed_table
.dpm_levels
[i
].value
);
5245 static int tonga_request_link_speed_change_before_state_change(struct pp_hwmgr
*hwmgr
, const void *input
)
5247 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5248 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5249 const struct tonga_power_state
*tonga_nps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5250 const struct tonga_power_state
*tonga_cps
= cast_const_phw_tonga_power_state(states
->pcurrent_state
);
5252 uint16_t target_link_speed
= tonga_get_maximum_link_speed(hwmgr
, tonga_nps
);
5253 uint16_t current_link_speed
;
5255 if (data
->force_pcie_gen
== PP_PCIEGenInvalid
)
5256 current_link_speed
= tonga_get_maximum_link_speed(hwmgr
, tonga_cps
);
5258 current_link_speed
= data
->force_pcie_gen
;
5260 data
->force_pcie_gen
= PP_PCIEGenInvalid
;
5261 data
->pspp_notify_required
= false;
5262 if (target_link_speed
> current_link_speed
) {
5263 switch(target_link_speed
) {
5265 if (0 == acpi_pcie_perf_request(hwmgr
->device
, PCIE_PERF_REQ_GEN3
, false))
5267 data
->force_pcie_gen
= PP_PCIEGen2
;
5268 if (current_link_speed
== PP_PCIEGen2
)
5271 if (0 == acpi_pcie_perf_request(hwmgr
->device
, PCIE_PERF_REQ_GEN2
, false))
5274 data
->force_pcie_gen
= tonga_get_current_pcie_speed(hwmgr
);
5278 if (target_link_speed
< current_link_speed
)
5279 data
->pspp_notify_required
= true;
5285 static int tonga_freeze_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
5287 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5289 if (0 == data
->need_update_smu7_dpm_table
)
5292 if ((0 == data
->sclk_dpm_key_disabled
) &&
5293 (data
->need_update_smu7_dpm_table
&
5294 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
))) {
5295 PP_ASSERT_WITH_CODE(
5296 true == tonga_is_dpm_running(hwmgr
),
5297 "Trying to freeze SCLK DPM when DPM is disabled",
5299 PP_ASSERT_WITH_CODE(
5300 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5301 PPSMC_MSG_SCLKDPM_FreezeLevel
),
5302 "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
5306 if ((0 == data
->mclk_dpm_key_disabled
) &&
5307 (data
->need_update_smu7_dpm_table
&
5308 DPMTABLE_OD_UPDATE_MCLK
)) {
5309 PP_ASSERT_WITH_CODE(true == tonga_is_dpm_running(hwmgr
),
5310 "Trying to freeze MCLK DPM when DPM is disabled",
5312 PP_ASSERT_WITH_CODE(
5313 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5314 PPSMC_MSG_MCLKDPM_FreezeLevel
),
5315 "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
5322 static int tonga_populate_and_upload_sclk_mclk_dpm_levels(struct pp_hwmgr
*hwmgr
, const void *input
)
5326 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5327 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5328 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5329 uint32_t sclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].engine_clock
;
5330 uint32_t mclk
= tonga_ps
->performance_levels
[tonga_ps
->performance_level_count
-1].memory_clock
;
5331 struct tonga_dpm_table
*pdpm_table
= &data
->dpm_table
;
5333 struct tonga_dpm_table
*pgolden_dpm_table
= &data
->golden_dpm_table
;
5334 uint32_t dpm_count
, clock_percent
;
5337 if (0 == data
->need_update_smu7_dpm_table
)
5340 if (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_SCLK
) {
5341 pdpm_table
->sclk_table
.dpm_levels
[pdpm_table
->sclk_table
.count
-1].value
= sclk
;
5343 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinACSupport
) ||
5344 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinDCSupport
)) {
5345 /* Need to do calculation based on the golden DPM table
5346 * as the Heatmap GPU Clock axis is also based on the default values
5348 PP_ASSERT_WITH_CODE(
5349 (pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
!= 0),
5352 dpm_count
= pdpm_table
->sclk_table
.count
< 2 ? 0 : pdpm_table
->sclk_table
.count
-2;
5353 for (i
= dpm_count
; i
> 1; i
--) {
5354 if (sclk
> pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
) {
5355 clock_percent
= ((sclk
- pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
)*100) /
5356 pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
;
5358 pdpm_table
->sclk_table
.dpm_levels
[i
].value
=
5359 pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
+
5360 (pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5362 } else if (pgolden_dpm_table
->sclk_table
.dpm_levels
[pdpm_table
->sclk_table
.count
-1].value
> sclk
) {
5363 clock_percent
= ((pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
- sclk
)*100) /
5364 pgolden_dpm_table
->sclk_table
.dpm_levels
[pgolden_dpm_table
->sclk_table
.count
-1].value
;
5366 pdpm_table
->sclk_table
.dpm_levels
[i
].value
=
5367 pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
-
5368 (pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5370 pdpm_table
->sclk_table
.dpm_levels
[i
].value
=
5371 pgolden_dpm_table
->sclk_table
.dpm_levels
[i
].value
;
5376 if (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
) {
5377 pdpm_table
->mclk_table
.dpm_levels
[pdpm_table
->mclk_table
.count
-1].value
= mclk
;
5379 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinACSupport
) ||
5380 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_OD6PlusinDCSupport
)) {
5382 PP_ASSERT_WITH_CODE(
5383 (pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
!= 0),
5386 dpm_count
= pdpm_table
->mclk_table
.count
< 2? 0 : pdpm_table
->mclk_table
.count
-2;
5387 for (i
= dpm_count
; i
> 1; i
--) {
5388 if (mclk
> pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
) {
5389 clock_percent
= ((mclk
- pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
)*100) /
5390 pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
;
5392 pdpm_table
->mclk_table
.dpm_levels
[i
].value
=
5393 pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
+
5394 (pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5396 } else if (pgolden_dpm_table
->mclk_table
.dpm_levels
[pdpm_table
->mclk_table
.count
-1].value
> mclk
) {
5397 clock_percent
= ((pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
- mclk
)*100) /
5398 pgolden_dpm_table
->mclk_table
.dpm_levels
[pgolden_dpm_table
->mclk_table
.count
-1].value
;
5400 pdpm_table
->mclk_table
.dpm_levels
[i
].value
=
5401 pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
-
5402 (pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
* clock_percent
)/100;
5404 pdpm_table
->mclk_table
.dpm_levels
[i
].value
= pgolden_dpm_table
->mclk_table
.dpm_levels
[i
].value
;
5409 if (data
->need_update_smu7_dpm_table
& (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
)) {
5410 result
= tonga_populate_all_memory_levels(hwmgr
);
5411 PP_ASSERT_WITH_CODE((0 == result
),
5412 "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
5416 if (data
->need_update_smu7_dpm_table
& (DPMTABLE_OD_UPDATE_MCLK
+ DPMTABLE_UPDATE_MCLK
)) {
5417 /*populate MCLK dpm table to SMU7 */
5418 result
= tonga_populate_all_memory_levels(hwmgr
);
5419 PP_ASSERT_WITH_CODE((0 == result
),
5420 "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
5427 static int tonga_trim_single_dpm_states(struct pp_hwmgr
*hwmgr
,
5428 struct tonga_single_dpm_table
* pdpm_table
,
5429 uint32_t low_limit
, uint32_t high_limit
)
5433 for (i
= 0; i
< pdpm_table
->count
; i
++) {
5434 if ((pdpm_table
->dpm_levels
[i
].value
< low_limit
) ||
5435 (pdpm_table
->dpm_levels
[i
].value
> high_limit
))
5436 pdpm_table
->dpm_levels
[i
].enabled
= false;
5438 pdpm_table
->dpm_levels
[i
].enabled
= true;
5443 static int tonga_trim_dpm_states(struct pp_hwmgr
*hwmgr
, const struct tonga_power_state
*hw_state
)
5446 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5447 uint32_t high_limit_count
;
5449 PP_ASSERT_WITH_CODE((hw_state
->performance_level_count
>= 1),
5450 "power state did not have any performance level",
5453 high_limit_count
= (1 == hw_state
->performance_level_count
) ? 0: 1;
5455 tonga_trim_single_dpm_states(hwmgr
,
5456 &(data
->dpm_table
.sclk_table
),
5457 hw_state
->performance_levels
[0].engine_clock
,
5458 hw_state
->performance_levels
[high_limit_count
].engine_clock
);
5460 tonga_trim_single_dpm_states(hwmgr
,
5461 &(data
->dpm_table
.mclk_table
),
5462 hw_state
->performance_levels
[0].memory_clock
,
5463 hw_state
->performance_levels
[high_limit_count
].memory_clock
);
5468 static int tonga_generate_dpm_level_enable_mask(struct pp_hwmgr
*hwmgr
, const void *input
)
5471 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5472 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5473 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5476 result
= tonga_trim_dpm_states(hwmgr
, tonga_ps
);
5480 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&data
->dpm_table
.sclk_table
);
5481 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&data
->dpm_table
.mclk_table
);
5482 data
->last_mclk_dpm_enable_mask
= data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
;
5483 if (data
->uvd_enabled
)
5484 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
&= 0xFFFFFFFE;
5486 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
= tonga_get_dpm_level_enable_mask_value(&data
->dpm_table
.pcie_speed_table
);
5491 static int tonga_enable_disable_vce_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
5493 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
5494 (PPSMC_Msg
)PPSMC_MSG_VCEDPM_Enable
:
5495 (PPSMC_Msg
)PPSMC_MSG_VCEDPM_Disable
);
5498 static int tonga_update_vce_dpm(struct pp_hwmgr
*hwmgr
, const void *input
)
5500 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5501 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5502 const struct tonga_power_state
*tonga_nps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5503 const struct tonga_power_state
*tonga_cps
= cast_const_phw_tonga_power_state(states
->pcurrent_state
);
5505 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
5506 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
5508 if(tonga_nps
->vce_clocks
.EVCLK
>0 &&
5509 (tonga_cps
== NULL
|| tonga_cps
->vce_clocks
.EVCLK
== 0)) {
5510 data
->smc_state_table
.VceBootLevel
= (uint8_t) (pptable_info
->mm_dep_table
->count
- 1);
5512 mm_boot_level_offset
= data
->dpm_table_start
+ offsetof(SMU72_Discrete_DpmTable
, VceBootLevel
);
5513 mm_boot_level_offset
/= 4;
5514 mm_boot_level_offset
*= 4;
5515 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
);
5516 mm_boot_level_value
&= 0xFF00FFFF;
5517 mm_boot_level_value
|= data
->smc_state_table
.VceBootLevel
<< 16;
5518 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
5520 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
)) {
5521 smum_send_msg_to_smc_with_parameter(
5523 (PPSMC_Msg
)(PPSMC_MSG_VCEDPM_SetEnabledMask
),
5524 (uint32_t)1 << data
->smc_state_table
.VceBootLevel
);
5526 tonga_enable_disable_vce_dpm(hwmgr
, true);
5527 } else if (tonga_nps
->vce_clocks
.EVCLK
== 0 && tonga_cps
!= NULL
&& tonga_cps
->vce_clocks
.EVCLK
> 0)
5528 tonga_enable_disable_vce_dpm(hwmgr
, false);
5534 static int tonga_update_and_upload_mc_reg_table(struct pp_hwmgr
*hwmgr
)
5536 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5541 if (0 == (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
))
5545 memset(&data
->mc_reg_table
, 0, sizeof(SMU72_Discrete_MCRegisters
));
5547 result
= tonga_convert_mc_reg_table_to_smc(hwmgr
, &(data
->mc_reg_table
));
5553 address
= data
->mc_reg_table_start
+ (uint32_t)offsetof(SMU72_Discrete_MCRegisters
, data
[0]);
5555 return tonga_copy_bytes_to_smc(hwmgr
->smumgr
, address
,
5556 (uint8_t *)&data
->mc_reg_table
.data
[0],
5557 sizeof(SMU72_Discrete_MCRegisterSet
) * data
->dpm_table
.mclk_table
.count
,
5561 static int tonga_program_memory_timing_parameters_conditionally(struct pp_hwmgr
*hwmgr
)
5563 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5565 if (data
->need_update_smu7_dpm_table
&
5566 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_OD_UPDATE_MCLK
))
5567 return tonga_program_memory_timing_parameters(hwmgr
);
5572 static int tonga_unfreeze_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
5574 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5576 if (0 == data
->need_update_smu7_dpm_table
)
5579 if ((0 == data
->sclk_dpm_key_disabled
) &&
5580 (data
->need_update_smu7_dpm_table
&
5581 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
))) {
5583 PP_ASSERT_WITH_CODE(true == tonga_is_dpm_running(hwmgr
),
5584 "Trying to Unfreeze SCLK DPM when DPM is disabled",
5586 PP_ASSERT_WITH_CODE(
5587 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5588 PPSMC_MSG_SCLKDPM_UnfreezeLevel
),
5589 "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
5593 if ((0 == data
->mclk_dpm_key_disabled
) &&
5594 (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
)) {
5596 PP_ASSERT_WITH_CODE(
5597 true == tonga_is_dpm_running(hwmgr
),
5598 "Trying to Unfreeze MCLK DPM when DPM is disabled",
5600 PP_ASSERT_WITH_CODE(
5601 0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
5602 PPSMC_MSG_SCLKDPM_UnfreezeLevel
),
5603 "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
5607 data
->need_update_smu7_dpm_table
= 0;
5612 static int tonga_notify_link_speed_change_after_state_change(struct pp_hwmgr
*hwmgr
, const void *input
)
5614 const struct phm_set_power_state_input
*states
= (const struct phm_set_power_state_input
*)input
;
5615 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5616 const struct tonga_power_state
*tonga_ps
= cast_const_phw_tonga_power_state(states
->pnew_state
);
5617 uint16_t target_link_speed
= tonga_get_maximum_link_speed(hwmgr
, tonga_ps
);
5620 if (data
->pspp_notify_required
||
5621 data
->pcie_performance_request
) {
5622 if (target_link_speed
== PP_PCIEGen3
)
5623 request
= PCIE_PERF_REQ_GEN3
;
5624 else if (target_link_speed
== PP_PCIEGen2
)
5625 request
= PCIE_PERF_REQ_GEN2
;
5627 request
= PCIE_PERF_REQ_GEN1
;
5629 if(request
== PCIE_PERF_REQ_GEN1
&& tonga_get_current_pcie_speed(hwmgr
) > 0) {
5630 data
->pcie_performance_request
= false;
5634 if (0 != acpi_pcie_perf_request(hwmgr
->device
, request
, false)) {
5635 if (PP_PCIEGen2
== target_link_speed
)
5636 printk("PSPP request to switch to Gen2 from Gen3 Failed!");
5638 printk("PSPP request to switch to Gen1 from Gen2 Failed!");
5642 data
->pcie_performance_request
= false;
5646 static int tonga_set_power_state_tasks(struct pp_hwmgr
*hwmgr
, const void *input
)
5648 int tmp_result
, result
= 0;
5650 tmp_result
= tonga_find_dpm_states_clocks_in_dpm_table(hwmgr
, input
);
5651 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to find DPM states clocks in DPM table!", result
= tmp_result
);
5653 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_PCIEPerformanceRequest
)) {
5654 tmp_result
= tonga_request_link_speed_change_before_state_change(hwmgr
, input
);
5655 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to request link speed change before state change!", result
= tmp_result
);
5658 tmp_result
= tonga_freeze_sclk_mclk_dpm(hwmgr
);
5659 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to freeze SCLK MCLK DPM!", result
= tmp_result
);
5661 tmp_result
= tonga_populate_and_upload_sclk_mclk_dpm_levels(hwmgr
, input
);
5662 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to populate and upload SCLK MCLK DPM levels!", result
= tmp_result
);
5664 tmp_result
= tonga_generate_dpm_level_enable_mask(hwmgr
, input
);
5665 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to generate DPM level enabled mask!", result
= tmp_result
);
5667 tmp_result
= tonga_update_vce_dpm(hwmgr
, input
);
5668 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to update VCE DPM!", result
= tmp_result
);
5670 tmp_result
= tonga_update_sclk_threshold(hwmgr
);
5671 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to update SCLK threshold!", result
= tmp_result
);
5673 tmp_result
= tonga_update_and_upload_mc_reg_table(hwmgr
);
5674 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to upload MC reg table!", result
= tmp_result
);
5676 tmp_result
= tonga_program_memory_timing_parameters_conditionally(hwmgr
);
5677 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to program memory timing parameters!", result
= tmp_result
);
5679 tmp_result
= tonga_unfreeze_sclk_mclk_dpm(hwmgr
);
5680 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to unfreeze SCLK MCLK DPM!", result
= tmp_result
);
5682 tmp_result
= tonga_upload_dpm_level_enable_mask(hwmgr
);
5683 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to upload DPM level enabled mask!", result
= tmp_result
);
5685 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_PCIEPerformanceRequest
)) {
5686 tmp_result
= tonga_notify_link_speed_change_after_state_change(hwmgr
, input
);
5687 PP_ASSERT_WITH_CODE((0 == tmp_result
), "Failed to notify link speed change after state change!", result
= tmp_result
);
5694 int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr
*hwmgr
)
5696 uint32_t num_active_displays
= 0;
5697 struct cgs_display_info info
= {0};
5698 info
.mode_info
= NULL
;
5700 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5702 num_active_displays
= info
.display_count
;
5704 if (num_active_displays
> 1) /* to do && (pHwMgr->pPECI->displayConfiguration.bMultiMonitorInSync != TRUE)) */
5705 tonga_notify_smc_display_change(hwmgr
, false);
5707 tonga_notify_smc_display_change(hwmgr
, true);
5713 * Programs the display gap
5715 * @param hwmgr the address of the powerplay hardware manager.
5718 int tonga_program_display_gap(struct pp_hwmgr
*hwmgr
)
5720 struct tonga_hwmgr
*data
= (struct tonga_hwmgr
*)(hwmgr
->backend
);
5721 uint32_t num_active_displays
= 0;
5722 uint32_t display_gap
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
);
5723 uint32_t display_gap2
;
5724 uint32_t pre_vbi_time_in_us
;
5725 uint32_t frame_time_in_us
;
5727 uint32_t refresh_rate
= 0;
5728 struct cgs_display_info info
= {0};
5729 struct cgs_mode_info mode_info
;
5731 info
.mode_info
= &mode_info
;
5733 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5734 num_active_displays
= info
.display_count
;
5736 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
);
5737 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
, display_gap
);
5739 ref_clock
= mode_info
.ref_clock
;
5740 refresh_rate
= mode_info
.refresh_rate
;
5742 if(0 == refresh_rate
)
5745 frame_time_in_us
= 1000000 / refresh_rate
;
5747 pre_vbi_time_in_us
= frame_time_in_us
- 200 - mode_info
.vblank_time_us
;
5748 display_gap2
= pre_vbi_time_in_us
* (ref_clock
/ 100);
5750 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL2
, display_gap2
);
5752 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, data
->soft_regs_start
+ offsetof(SMU72_SoftRegisters
, PreVBlankGap
), 0x64);
5754 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
));
5756 if (num_active_displays
== 1)
5757 tonga_notify_smc_display_change(hwmgr
, true);
5762 int tonga_display_configuration_changed_task(struct pp_hwmgr
*hwmgr
)
5765 tonga_program_display_gap(hwmgr
);
5767 /* to do PhwTonga_CacUpdateDisplayConfiguration(pHwMgr); */
5771 static const struct pp_hwmgr_func tonga_hwmgr_funcs
= {
5772 .backend_init
= &tonga_hwmgr_backend_init
,
5773 .backend_fini
= &tonga_hwmgr_backend_fini
,
5774 .asic_setup
= &tonga_setup_asic_task
,
5775 .dynamic_state_management_enable
= &tonga_enable_dpm_tasks
,
5776 .apply_state_adjust_rules
= tonga_apply_state_adjust_rules
,
5777 .force_dpm_level
= &tonga_force_dpm_level
,
5778 .power_state_set
= tonga_set_power_state_tasks
,
5779 .get_power_state_size
= tonga_get_power_state_size
,
5780 .get_mclk
= tonga_dpm_get_mclk
,
5781 .get_sclk
= tonga_dpm_get_sclk
,
5782 .patch_boot_state
= tonga_dpm_patch_boot_state
,
5783 .get_pp_table_entry
= tonga_get_pp_table_entry
,
5784 .get_num_of_pp_table_entries
= tonga_get_number_of_powerplay_table_entries
,
5785 .print_current_perforce_level
= tonga_print_current_perforce_level
,
5786 .notify_smc_display_config_after_ps_adjustment
= tonga_notify_smc_display_config_after_ps_adjustment
,
5787 .display_config_changed
= tonga_display_configuration_changed_task
,
5790 int tonga_hwmgr_init(struct pp_hwmgr
*hwmgr
)
5794 data
= kzalloc (sizeof(tonga_hwmgr
), GFP_KERNEL
);
5797 memset(data
, 0x00, sizeof(tonga_hwmgr
));
5799 hwmgr
->backend
= data
;
5800 hwmgr
->hwmgr_func
= &tonga_hwmgr_funcs
;
5801 hwmgr
->pptable_func
= &tonga_pptable_funcs
;