2 * Copyright 2015 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
23 #include <linux/module.h>
24 #include <linux/slab.h>
25 #include "linux/delay.h"
28 #include "fiji_smumgr.h"
30 #include "hardwaremanager.h"
31 #include "ppatomctrl.h"
33 #include "cgs_common.h"
34 #include "fiji_dyn_defaults.h"
35 #include "fiji_powertune.h"
37 #include "smu/smu_7_1_3_d.h"
38 #include "smu/smu_7_1_3_sh_mask.h"
39 #include "gmc/gmc_8_1_d.h"
40 #include "gmc/gmc_8_1_sh_mask.h"
41 #include "bif/bif_5_0_d.h"
42 #include "bif/bif_5_0_sh_mask.h"
43 #include "dce/dce_10_0_d.h"
44 #include "dce/dce_10_0_sh_mask.h"
45 #include "pppcielanes.h"
46 #include "fiji_hwmgr.h"
47 #include "tonga_processpptables.h"
48 #include "tonga_pptable.h"
51 #include "amd_pcie_helpers.h"
52 #include "cgs_linux.h"
53 #include "ppinterrupt.h"
55 #include "fiji_clockpowergating.h"
56 #include "fiji_thermal.h"
58 #define VOLTAGE_SCALE 4
59 #define SMC_RAM_END 0x40000
60 #define VDDC_VDDCI_DELTA 300
62 #define MC_SEQ_MISC0_GDDR5_SHIFT 28
63 #define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000
64 #define MC_SEQ_MISC0_GDDR5_VALUE 5
66 #define MC_CG_ARB_FREQ_F0 0x0a /* boot-up default */
67 #define MC_CG_ARB_FREQ_F1 0x0b
68 #define MC_CG_ARB_FREQ_F2 0x0c
69 #define MC_CG_ARB_FREQ_F3 0x0d
72 #define SMC_CG_IND_START 0xc0030000
73 #define SMC_CG_IND_END 0xc0040000 /* First byte after SMC_CG_IND */
75 #define VOLTAGE_SCALE 4
76 #define VOLTAGE_VID_OFFSET_SCALE1 625
77 #define VOLTAGE_VID_OFFSET_SCALE2 100
79 #define VDDC_VDDCI_DELTA 300
81 #define ixSWRST_COMMAND_1 0x1400103
82 #define MC_SEQ_CNTL__CAC_EN_MASK 0x40000000
84 /** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
86 DPM_EVENT_SRC_ANALOG
= 0, /* Internal analog trip point */
87 DPM_EVENT_SRC_EXTERNAL
= 1, /* External (GPIO 17) signal */
88 DPM_EVENT_SRC_DIGITAL
= 2, /* Internal digital trip point (DIG_THERM_DPM) */
89 DPM_EVENT_SRC_ANALOG_OR_EXTERNAL
= 3, /* Internal analog or external */
90 DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL
= 4 /* Internal digital or external */
94 /* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs
95 * not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ]
97 static const uint16_t fiji_clock_stretcher_lookup_table
[2][4] =
98 { {600, 1050, 3, 0}, {600, 1050, 6, 1} };
100 /* [FF, SS] type, [] 4 voltage ranges, and
101 * [Floor Freq, Boundary Freq, VID min , VID max]
103 static const uint32_t fiji_clock_stretcher_ddt_table
[2][4][4] =
104 { { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
105 { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
107 /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%]
108 * (coming from PWR_CKS_CNTL.stretch_amount reg spec)
110 static const uint8_t fiji_clock_stretch_amount_conversion
[2][6] =
111 { {0, 1, 3, 2, 4, 5}, {0, 2, 4, 5, 6, 5} };
113 static const unsigned long PhwFiji_Magic
= (unsigned long)(PHM_VIslands_Magic
);
115 struct fiji_power_state
*cast_phw_fiji_power_state(
116 struct pp_hw_power_state
*hw_ps
)
118 PP_ASSERT_WITH_CODE((PhwFiji_Magic
== hw_ps
->magic
),
119 "Invalid Powerstate Type!",
122 return (struct fiji_power_state
*)hw_ps
;
125 const struct fiji_power_state
*cast_const_phw_fiji_power_state(
126 const struct pp_hw_power_state
*hw_ps
)
128 PP_ASSERT_WITH_CODE((PhwFiji_Magic
== hw_ps
->magic
),
129 "Invalid Powerstate Type!",
132 return (const struct fiji_power_state
*)hw_ps
;
135 static bool fiji_is_dpm_running(struct pp_hwmgr
*hwmgr
)
137 return (1 == PHM_READ_INDIRECT_FIELD(hwmgr
->device
,
138 CGS_IND_REG__SMC
, FEATURE_STATUS
, VOLTAGE_CONTROLLER_ON
))
142 static void fiji_init_dpm_defaults(struct pp_hwmgr
*hwmgr
)
144 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
145 struct fiji_ulv_parm
*ulv
= &data
->ulv
;
147 ulv
->cg_ulv_parameter
= PPFIJI_CGULVPARAMETER_DFLT
;
148 data
->voting_rights_clients0
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT0
;
149 data
->voting_rights_clients1
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT1
;
150 data
->voting_rights_clients2
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT2
;
151 data
->voting_rights_clients3
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT3
;
152 data
->voting_rights_clients4
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT4
;
153 data
->voting_rights_clients5
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT5
;
154 data
->voting_rights_clients6
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT6
;
155 data
->voting_rights_clients7
= PPFIJI_VOTINGRIGHTSCLIENTS_DFLT7
;
157 data
->static_screen_threshold_unit
=
158 PPFIJI_STATICSCREENTHRESHOLDUNIT_DFLT
;
159 data
->static_screen_threshold
=
160 PPFIJI_STATICSCREENTHRESHOLD_DFLT
;
162 /* Unset ABM cap as it moved to DAL.
163 * Add PHM_PlatformCaps_NonABMSupportInPPLib
164 * for re-direct ABM related request to DAL
166 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
167 PHM_PlatformCaps_ABM
);
168 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
169 PHM_PlatformCaps_NonABMSupportInPPLib
);
171 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
172 PHM_PlatformCaps_DynamicACTiming
);
174 fiji_initialize_power_tune_defaults(hwmgr
);
176 data
->mclk_stutter_mode_threshold
= 60000;
177 data
->pcie_gen_performance
.max
= PP_PCIEGen1
;
178 data
->pcie_gen_performance
.min
= PP_PCIEGen3
;
179 data
->pcie_gen_power_saving
.max
= PP_PCIEGen1
;
180 data
->pcie_gen_power_saving
.min
= PP_PCIEGen3
;
181 data
->pcie_lane_performance
.max
= 0;
182 data
->pcie_lane_performance
.min
= 16;
183 data
->pcie_lane_power_saving
.max
= 0;
184 data
->pcie_lane_power_saving
.min
= 16;
186 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
187 PHM_PlatformCaps_DynamicUVDState
);
190 static int fiji_get_sclk_for_voltage_evv(struct pp_hwmgr
*hwmgr
,
191 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
192 uint16_t virtual_voltage_id
, int32_t *sclk
)
196 struct phm_ppt_v1_information
*table_info
=
197 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
199 PP_ASSERT_WITH_CODE(lookup_table
->count
!= 0, "Lookup table is empty", return -EINVAL
);
201 /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
202 for (entryId
= 0; entryId
< table_info
->vdd_dep_on_sclk
->count
; entryId
++) {
203 voltageId
= table_info
->vdd_dep_on_sclk
->entries
[entryId
].vddInd
;
204 if (lookup_table
->entries
[voltageId
].us_vdd
== virtual_voltage_id
)
208 PP_ASSERT_WITH_CODE(entryId
< table_info
->vdd_dep_on_sclk
->count
,
209 "Can't find requested voltage id in vdd_dep_on_sclk table!",
213 *sclk
= table_info
->vdd_dep_on_sclk
->entries
[entryId
].clk
;
219 * Get Leakage VDDC based on leakage ID.
221 * @param hwmgr the address of the powerplay hardware manager.
224 static int fiji_get_evv_voltages(struct pp_hwmgr
*hwmgr
)
226 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
229 uint16_t evv_default
= 1150;
232 struct phm_ppt_v1_information
*table_info
=
233 (struct phm_ppt_v1_information
*)hwmgr
->pptable
;
234 struct phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
=
235 table_info
->vdd_dep_on_sclk
;
238 for (i
= 0; i
< FIJI_MAX_LEAKAGE_COUNT
; i
++) {
239 vv_id
= ATOM_VIRTUAL_VOLTAGE_ID0
+ i
;
240 if (!fiji_get_sclk_for_voltage_evv(hwmgr
,
241 table_info
->vddc_lookup_table
, vv_id
, &sclk
)) {
242 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
243 PHM_PlatformCaps_ClockStretcher
)) {
244 for (j
= 1; j
< sclk_table
->count
; j
++) {
245 if (sclk_table
->entries
[j
].clk
== sclk
&&
246 sclk_table
->entries
[j
].cks_enable
== 0) {
253 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
254 PHM_PlatformCaps_EnableDriverEVV
))
255 result
= atomctrl_calculate_voltage_evv_on_sclk(hwmgr
,
256 VOLTAGE_TYPE_VDDC
, sclk
, vv_id
, &vddc
, i
, true);
261 result
= atomctrl_get_voltage_evv_on_sclk(hwmgr
,
262 VOLTAGE_TYPE_VDDC
, sclk
,vv_id
, &vddc
);
264 /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
265 PP_ASSERT_WITH_CODE((vddc
< 2000),
266 "Invalid VDDC value, greater than 2v!", result
= -EINVAL
;);
269 /* 1.15V is the default safe value for Fiji */
272 /* the voltage should not be zero nor equal to leakage ID */
273 if (vddc
!= 0 && vddc
!= vv_id
) {
274 data
->vddc_leakage
.actual_voltage
275 [data
->vddc_leakage
.count
] = vddc
;
276 data
->vddc_leakage
.leakage_id
277 [data
->vddc_leakage
.count
] = vv_id
;
278 data
->vddc_leakage
.count
++;
286 * Change virtual leakage voltage to actual value.
288 * @param hwmgr the address of the powerplay hardware manager.
289 * @param pointer to changing voltage
290 * @param pointer to leakage table
292 static void fiji_patch_with_vdd_leakage(struct pp_hwmgr
*hwmgr
,
293 uint16_t *voltage
, struct fiji_leakage_voltage
*leakage_table
)
297 /* search for leakage voltage ID 0xff01 ~ 0xff08 */
298 for (index
= 0; index
< leakage_table
->count
; index
++) {
299 /* if this voltage matches a leakage voltage ID */
300 /* patch with actual leakage voltage */
301 if (leakage_table
->leakage_id
[index
] == *voltage
) {
302 *voltage
= leakage_table
->actual_voltage
[index
];
307 if (*voltage
> ATOM_VIRTUAL_VOLTAGE_ID0
)
308 printk(KERN_ERR
"Voltage value looks like a Leakage ID but it's not patched \n");
312 * Patch voltage lookup table by EVV leakages.
314 * @param hwmgr the address of the powerplay hardware manager.
315 * @param pointer to voltage lookup table
316 * @param pointer to leakage table
319 static int fiji_patch_lookup_table_with_leakage(struct pp_hwmgr
*hwmgr
,
320 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
321 struct fiji_leakage_voltage
*leakage_table
)
325 for (i
= 0; i
< lookup_table
->count
; i
++)
326 fiji_patch_with_vdd_leakage(hwmgr
,
327 &lookup_table
->entries
[i
].us_vdd
, leakage_table
);
332 static int fiji_patch_clock_voltage_limits_with_vddc_leakage(
333 struct pp_hwmgr
*hwmgr
, struct fiji_leakage_voltage
*leakage_table
,
336 struct phm_ppt_v1_information
*table_info
=
337 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
338 fiji_patch_with_vdd_leakage(hwmgr
, (uint16_t *)vddc
, leakage_table
);
339 hwmgr
->dyn_state
.max_clock_voltage_on_dc
.vddc
=
340 table_info
->max_clock_voltage_on_dc
.vddc
;
344 static int fiji_patch_voltage_dependency_tables_with_lookup_table(
345 struct pp_hwmgr
*hwmgr
)
349 struct phm_ppt_v1_information
*table_info
=
350 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
352 struct phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
=
353 table_info
->vdd_dep_on_sclk
;
354 struct phm_ppt_v1_clock_voltage_dependency_table
*mclk_table
=
355 table_info
->vdd_dep_on_mclk
;
356 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
357 table_info
->mm_dep_table
;
359 for (entryId
= 0; entryId
< sclk_table
->count
; ++entryId
) {
360 voltageId
= sclk_table
->entries
[entryId
].vddInd
;
361 sclk_table
->entries
[entryId
].vddc
=
362 table_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
365 for (entryId
= 0; entryId
< mclk_table
->count
; ++entryId
) {
366 voltageId
= mclk_table
->entries
[entryId
].vddInd
;
367 mclk_table
->entries
[entryId
].vddc
=
368 table_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
371 for (entryId
= 0; entryId
< mm_table
->count
; ++entryId
) {
372 voltageId
= mm_table
->entries
[entryId
].vddcInd
;
373 mm_table
->entries
[entryId
].vddc
=
374 table_info
->vddc_lookup_table
->entries
[voltageId
].us_vdd
;
381 static int fiji_calc_voltage_dependency_tables(struct pp_hwmgr
*hwmgr
)
383 /* Need to determine if we need calculated voltage. */
387 static int fiji_calc_mm_voltage_dependency_table(struct pp_hwmgr
*hwmgr
)
389 /* Need to determine if we need calculated voltage from mm table. */
393 static int fiji_sort_lookup_table(struct pp_hwmgr
*hwmgr
,
394 struct phm_ppt_v1_voltage_lookup_table
*lookup_table
)
396 uint32_t table_size
, i
, j
;
397 struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record
;
398 table_size
= lookup_table
->count
;
400 PP_ASSERT_WITH_CODE(0 != lookup_table
->count
,
401 "Lookup table is empty", return -EINVAL
);
403 /* Sorting voltages */
404 for (i
= 0; i
< table_size
- 1; i
++) {
405 for (j
= i
+ 1; j
> 0; j
--) {
406 if (lookup_table
->entries
[j
].us_vdd
<
407 lookup_table
->entries
[j
- 1].us_vdd
) {
408 tmp_voltage_lookup_record
= lookup_table
->entries
[j
- 1];
409 lookup_table
->entries
[j
- 1] = lookup_table
->entries
[j
];
410 lookup_table
->entries
[j
] = tmp_voltage_lookup_record
;
418 static int fiji_complete_dependency_tables(struct pp_hwmgr
*hwmgr
)
422 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
423 struct phm_ppt_v1_information
*table_info
=
424 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
426 tmp_result
= fiji_patch_lookup_table_with_leakage(hwmgr
,
427 table_info
->vddc_lookup_table
, &(data
->vddc_leakage
));
431 tmp_result
= fiji_patch_clock_voltage_limits_with_vddc_leakage(hwmgr
,
432 &(data
->vddc_leakage
), &table_info
->max_clock_voltage_on_dc
.vddc
);
436 tmp_result
= fiji_patch_voltage_dependency_tables_with_lookup_table(hwmgr
);
440 tmp_result
= fiji_calc_voltage_dependency_tables(hwmgr
);
444 tmp_result
= fiji_calc_mm_voltage_dependency_table(hwmgr
);
448 tmp_result
= fiji_sort_lookup_table(hwmgr
, table_info
->vddc_lookup_table
);
455 static int fiji_set_private_data_based_on_pptable(struct pp_hwmgr
*hwmgr
)
457 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
458 struct phm_ppt_v1_information
*table_info
=
459 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
461 struct phm_ppt_v1_clock_voltage_dependency_table
*allowed_sclk_vdd_table
=
462 table_info
->vdd_dep_on_sclk
;
463 struct phm_ppt_v1_clock_voltage_dependency_table
*allowed_mclk_vdd_table
=
464 table_info
->vdd_dep_on_mclk
;
466 PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table
!= NULL
,
467 "VDD dependency on SCLK table is missing. \
468 This table is mandatory", return -EINVAL
);
469 PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table
->count
>= 1,
470 "VDD dependency on SCLK table has to have is missing. \
471 This table is mandatory", return -EINVAL
);
473 PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table
!= NULL
,
474 "VDD dependency on MCLK table is missing. \
475 This table is mandatory", return -EINVAL
);
476 PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table
->count
>= 1,
477 "VDD dependency on MCLK table has to have is missing. \
478 This table is mandatory", return -EINVAL
);
480 data
->min_vddc_in_pptable
= (uint16_t)allowed_sclk_vdd_table
->entries
[0].vddc
;
481 data
->max_vddc_in_pptable
= (uint16_t)allowed_sclk_vdd_table
->
482 entries
[allowed_sclk_vdd_table
->count
- 1].vddc
;
484 table_info
->max_clock_voltage_on_ac
.sclk
=
485 allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].clk
;
486 table_info
->max_clock_voltage_on_ac
.mclk
=
487 allowed_mclk_vdd_table
->entries
[allowed_mclk_vdd_table
->count
- 1].clk
;
488 table_info
->max_clock_voltage_on_ac
.vddc
=
489 allowed_sclk_vdd_table
->entries
[allowed_sclk_vdd_table
->count
- 1].vddc
;
490 table_info
->max_clock_voltage_on_ac
.vddci
=
491 allowed_mclk_vdd_table
->entries
[allowed_mclk_vdd_table
->count
- 1].vddci
;
493 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.sclk
=
494 table_info
->max_clock_voltage_on_ac
.sclk
;
495 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.mclk
=
496 table_info
->max_clock_voltage_on_ac
.mclk
;
497 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.vddc
=
498 table_info
->max_clock_voltage_on_ac
.vddc
;
499 hwmgr
->dyn_state
.max_clock_voltage_on_ac
.vddci
=
500 table_info
->max_clock_voltage_on_ac
.vddci
;
505 static uint16_t fiji_get_current_pcie_speed(struct pp_hwmgr
*hwmgr
)
507 uint32_t speedCntl
= 0;
509 /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
510 speedCntl
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__PCIE
,
511 ixPCIE_LC_SPEED_CNTL
);
512 return((uint16_t)PHM_GET_FIELD(speedCntl
,
513 PCIE_LC_SPEED_CNTL
, LC_CURRENT_DATA_RATE
));
516 static int fiji_get_current_pcie_lane_number(struct pp_hwmgr
*hwmgr
)
520 /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
521 link_width
= PHM_READ_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__PCIE
,
522 PCIE_LC_LINK_WIDTH_CNTL
, LC_LINK_WIDTH_RD
);
524 PP_ASSERT_WITH_CODE((7 >= link_width
),
525 "Invalid PCIe lane width!", return 0);
527 return decode_pcie_lane_width(link_width
);
530 /** Patch the Boot State to match VBIOS boot clocks and voltage.
532 * @param hwmgr Pointer to the hardware manager.
533 * @param pPowerState The address of the PowerState instance being created.
536 static int fiji_patch_boot_state(struct pp_hwmgr
*hwmgr
,
537 struct pp_hw_power_state
*hw_ps
)
539 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
540 struct fiji_power_state
*ps
= (struct fiji_power_state
*)hw_ps
;
541 ATOM_FIRMWARE_INFO_V2_2
*fw_info
;
544 int index
= GetIndexIntoMasterTable(DATA
, FirmwareInfo
);
546 /* First retrieve the Boot clocks and VDDC from the firmware info table.
547 * We assume here that fw_info is unchanged if this call fails.
549 fw_info
= (ATOM_FIRMWARE_INFO_V2_2
*)cgs_atom_get_data_table(
550 hwmgr
->device
, index
,
551 &size
, &frev
, &crev
);
553 /* During a test, there is no firmware info table. */
556 /* Patch the state. */
557 data
->vbios_boot_state
.sclk_bootup_value
=
558 le32_to_cpu(fw_info
->ulDefaultEngineClock
);
559 data
->vbios_boot_state
.mclk_bootup_value
=
560 le32_to_cpu(fw_info
->ulDefaultMemoryClock
);
561 data
->vbios_boot_state
.mvdd_bootup_value
=
562 le16_to_cpu(fw_info
->usBootUpMVDDCVoltage
);
563 data
->vbios_boot_state
.vddc_bootup_value
=
564 le16_to_cpu(fw_info
->usBootUpVDDCVoltage
);
565 data
->vbios_boot_state
.vddci_bootup_value
=
566 le16_to_cpu(fw_info
->usBootUpVDDCIVoltage
);
567 data
->vbios_boot_state
.pcie_gen_bootup_value
=
568 fiji_get_current_pcie_speed(hwmgr
);
569 data
->vbios_boot_state
.pcie_lane_bootup_value
=
570 (uint16_t)fiji_get_current_pcie_lane_number(hwmgr
);
572 /* set boot power state */
573 ps
->performance_levels
[0].memory_clock
= data
->vbios_boot_state
.mclk_bootup_value
;
574 ps
->performance_levels
[0].engine_clock
= data
->vbios_boot_state
.sclk_bootup_value
;
575 ps
->performance_levels
[0].pcie_gen
= data
->vbios_boot_state
.pcie_gen_bootup_value
;
576 ps
->performance_levels
[0].pcie_lane
= data
->vbios_boot_state
.pcie_lane_bootup_value
;
581 static int fiji_hwmgr_backend_fini(struct pp_hwmgr
*hwmgr
)
583 return phm_hwmgr_backend_fini(hwmgr
);
586 static int fiji_hwmgr_backend_init(struct pp_hwmgr
*hwmgr
)
588 struct fiji_hwmgr
*data
;
590 struct phm_ppt_v1_information
*table_info
=
591 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
595 data
= kzalloc(sizeof(struct fiji_hwmgr
), GFP_KERNEL
);
599 hwmgr
->backend
= data
;
601 data
->dll_default_on
= false;
602 data
->sram_end
= SMC_RAM_END
;
604 for (i
= 0; i
< SMU73_MAX_LEVELS_GRAPHICS
; i
++)
605 data
->activity_target
[i
] = FIJI_AT_DFLT
;
607 data
->vddc_vddci_delta
= VDDC_VDDCI_DELTA
;
609 data
->mclk_activity_target
= PPFIJI_MCLK_TARGETACTIVITY_DFLT
;
610 data
->mclk_dpm0_activity_target
= 0xa;
612 data
->sclk_dpm_key_disabled
= 0;
613 data
->mclk_dpm_key_disabled
= 0;
614 data
->pcie_dpm_key_disabled
= 0;
616 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
617 PHM_PlatformCaps_UnTabledHardwareInterface
);
618 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
619 PHM_PlatformCaps_TablelessHardwareInterface
);
621 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
622 PHM_PlatformCaps_SclkDeepSleep
);
624 data
->gpio_debug
= 0;
626 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
627 PHM_PlatformCaps_DynamicPatchPowerState
);
629 /* need to set voltage control types before EVV patching */
630 data
->voltage_control
= FIJI_VOLTAGE_CONTROL_NONE
;
631 data
->vddci_control
= FIJI_VOLTAGE_CONTROL_NONE
;
632 data
->mvdd_control
= FIJI_VOLTAGE_CONTROL_NONE
;
634 data
->force_pcie_gen
= PP_PCIEGenInvalid
;
636 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
637 VOLTAGE_TYPE_VDDC
, VOLTAGE_OBJ_SVID2
))
638 data
->voltage_control
= FIJI_VOLTAGE_CONTROL_BY_SVID2
;
640 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
641 PHM_PlatformCaps_EnableMVDDControl
))
642 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
643 VOLTAGE_TYPE_MVDDC
, VOLTAGE_OBJ_GPIO_LUT
))
644 data
->mvdd_control
= FIJI_VOLTAGE_CONTROL_BY_GPIO
;
646 if (data
->mvdd_control
== FIJI_VOLTAGE_CONTROL_NONE
)
647 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
648 PHM_PlatformCaps_EnableMVDDControl
);
650 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
651 PHM_PlatformCaps_ControlVDDCI
)) {
652 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
653 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_GPIO_LUT
))
654 data
->vddci_control
= FIJI_VOLTAGE_CONTROL_BY_GPIO
;
655 else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr
,
656 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_SVID2
))
657 data
->vddci_control
= FIJI_VOLTAGE_CONTROL_BY_SVID2
;
660 if (data
->vddci_control
== FIJI_VOLTAGE_CONTROL_NONE
)
661 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
662 PHM_PlatformCaps_ControlVDDCI
);
664 if (table_info
&& table_info
->cac_dtp_table
->usClockStretchAmount
)
665 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
666 PHM_PlatformCaps_ClockStretcher
);
668 fiji_init_dpm_defaults(hwmgr
);
670 /* Get leakage voltage based on leakage ID. */
671 fiji_get_evv_voltages(hwmgr
);
673 /* Patch our voltage dependency table with actual leakage voltage
674 * We need to perform leakage translation before it's used by other functions
676 fiji_complete_dependency_tables(hwmgr
);
678 /* Parse pptable data read from VBIOS */
679 fiji_set_private_data_based_on_pptable(hwmgr
);
682 data
->ulv
.ulv_supported
= true; /* ULV feature is enabled by default */
684 /* Initalize Dynamic State Adjustment Rule Settings */
685 result
= tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr
);
688 data
->uvd_enabled
= false;
689 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
690 PHM_PlatformCaps_EnableSMU7ThermalManagement
);
691 data
->vddc_phase_shed_control
= false;
694 stay_in_boot
= phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
695 PHM_PlatformCaps_StayInBootState
);
698 struct cgs_system_info sys_info
= {0};
700 data
->is_tlu_enabled
= false;
701 hwmgr
->platform_descriptor
.hardwareActivityPerformanceLevels
=
702 FIJI_MAX_HARDWARE_POWERLEVELS
;
703 hwmgr
->platform_descriptor
.hardwarePerformanceLevels
= 2;
704 hwmgr
->platform_descriptor
.minimumClocksReductionPercentage
= 50;
706 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
707 PHM_PlatformCaps_FanSpeedInTableIsRPM
);
709 if (table_info
->cac_dtp_table
->usDefaultTargetOperatingTemp
&&
710 hwmgr
->thermal_controller
.
711 advanceFanControlParameters
.ucFanControlMode
) {
712 hwmgr
->thermal_controller
.advanceFanControlParameters
.usMaxFanPWM
=
713 hwmgr
->thermal_controller
.advanceFanControlParameters
.usDefaultMaxFanPWM
;
714 hwmgr
->thermal_controller
.advanceFanControlParameters
.usMaxFanRPM
=
715 hwmgr
->thermal_controller
.advanceFanControlParameters
.usDefaultMaxFanRPM
;
716 hwmgr
->dyn_state
.cac_dtp_table
->usOperatingTempMinLimit
=
717 table_info
->cac_dtp_table
->usOperatingTempMinLimit
;
718 hwmgr
->dyn_state
.cac_dtp_table
->usOperatingTempMaxLimit
=
719 table_info
->cac_dtp_table
->usOperatingTempMaxLimit
;
720 hwmgr
->dyn_state
.cac_dtp_table
->usDefaultTargetOperatingTemp
=
721 table_info
->cac_dtp_table
->usDefaultTargetOperatingTemp
;
722 hwmgr
->dyn_state
.cac_dtp_table
->usOperatingTempStep
=
723 table_info
->cac_dtp_table
->usOperatingTempStep
;
724 hwmgr
->dyn_state
.cac_dtp_table
->usTargetOperatingTemp
=
725 table_info
->cac_dtp_table
->usTargetOperatingTemp
;
727 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
728 PHM_PlatformCaps_ODFuzzyFanControlSupport
);
731 sys_info
.size
= sizeof(struct cgs_system_info
);
732 sys_info
.info_id
= CGS_SYSTEM_INFO_PCIE_GEN_INFO
;
733 result
= cgs_query_system_info(hwmgr
->device
, &sys_info
);
735 data
->pcie_gen_cap
= AMDGPU_DEFAULT_PCIE_GEN_MASK
;
737 data
->pcie_gen_cap
= (uint32_t)sys_info
.value
;
738 if (data
->pcie_gen_cap
& CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3
)
739 data
->pcie_spc_cap
= 20;
740 sys_info
.size
= sizeof(struct cgs_system_info
);
741 sys_info
.info_id
= CGS_SYSTEM_INFO_PCIE_MLW
;
742 result
= cgs_query_system_info(hwmgr
->device
, &sys_info
);
744 data
->pcie_lane_cap
= AMDGPU_DEFAULT_PCIE_MLW_MASK
;
746 data
->pcie_lane_cap
= (uint32_t)sys_info
.value
;
748 /* Ignore return value in here, we are cleaning up a mess. */
749 fiji_hwmgr_backend_fini(hwmgr
);
756 * Read clock related registers.
758 * @param hwmgr the address of the powerplay hardware manager.
761 static int fiji_read_clock_registers(struct pp_hwmgr
*hwmgr
)
763 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
765 data
->clock_registers
.vCG_SPLL_FUNC_CNTL
=
766 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
767 ixCG_SPLL_FUNC_CNTL
);
768 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
=
769 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
770 ixCG_SPLL_FUNC_CNTL_2
);
771 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
=
772 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
773 ixCG_SPLL_FUNC_CNTL_3
);
774 data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
=
775 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
776 ixCG_SPLL_FUNC_CNTL_4
);
777 data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
=
778 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
779 ixCG_SPLL_SPREAD_SPECTRUM
);
780 data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
=
781 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
782 ixCG_SPLL_SPREAD_SPECTRUM_2
);
788 * Find out if memory is GDDR5.
790 * @param hwmgr the address of the powerplay hardware manager.
793 static int fiji_get_memory_type(struct pp_hwmgr
*hwmgr
)
795 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
798 temp
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC0
);
800 data
->is_memory_gddr5
= (MC_SEQ_MISC0_GDDR5_VALUE
==
801 ((temp
& MC_SEQ_MISC0_GDDR5_MASK
) >>
802 MC_SEQ_MISC0_GDDR5_SHIFT
));
808 * Enables Dynamic Power Management by SMC
810 * @param hwmgr the address of the powerplay hardware manager.
813 static int fiji_enable_acpi_power_management(struct pp_hwmgr
*hwmgr
)
815 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
816 GENERAL_PWRMGT
, STATIC_PM_EN
, 1);
822 * Initialize PowerGating States for different engines
824 * @param hwmgr the address of the powerplay hardware manager.
827 static int fiji_init_power_gate_state(struct pp_hwmgr
*hwmgr
)
829 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
831 data
->uvd_power_gated
= false;
832 data
->vce_power_gated
= false;
833 data
->samu_power_gated
= false;
834 data
->acp_power_gated
= false;
835 data
->pg_acp_init
= true;
840 static int fiji_init_sclk_threshold(struct pp_hwmgr
*hwmgr
)
842 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
843 data
->low_sclk_interrupt_threshold
= 0;
848 static int fiji_setup_asic_task(struct pp_hwmgr
*hwmgr
)
850 int tmp_result
, result
= 0;
852 tmp_result
= fiji_read_clock_registers(hwmgr
);
853 PP_ASSERT_WITH_CODE((0 == tmp_result
),
854 "Failed to read clock registers!", result
= tmp_result
);
856 tmp_result
= fiji_get_memory_type(hwmgr
);
857 PP_ASSERT_WITH_CODE((0 == tmp_result
),
858 "Failed to get memory type!", result
= tmp_result
);
860 tmp_result
= fiji_enable_acpi_power_management(hwmgr
);
861 PP_ASSERT_WITH_CODE((0 == tmp_result
),
862 "Failed to enable ACPI power management!", result
= tmp_result
);
864 tmp_result
= fiji_init_power_gate_state(hwmgr
);
865 PP_ASSERT_WITH_CODE((0 == tmp_result
),
866 "Failed to init power gate state!", result
= tmp_result
);
868 tmp_result
= tonga_get_mc_microcode_version(hwmgr
);
869 PP_ASSERT_WITH_CODE((0 == tmp_result
),
870 "Failed to get MC microcode version!", result
= tmp_result
);
872 tmp_result
= fiji_init_sclk_threshold(hwmgr
);
873 PP_ASSERT_WITH_CODE((0 == tmp_result
),
874 "Failed to init sclk threshold!", result
= tmp_result
);
880 * Checks if we want to support voltage control
882 * @param hwmgr the address of the powerplay hardware manager.
884 static bool fiji_voltage_control(const struct pp_hwmgr
*hwmgr
)
886 const struct fiji_hwmgr
*data
=
887 (const struct fiji_hwmgr
*)(hwmgr
->backend
);
889 return (FIJI_VOLTAGE_CONTROL_NONE
!= data
->voltage_control
);
893 * Enable voltage control
895 * @param hwmgr the address of the powerplay hardware manager.
898 static int fiji_enable_voltage_control(struct pp_hwmgr
*hwmgr
)
900 /* enable voltage control */
901 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
902 GENERAL_PWRMGT
, VOLT_PWRMGT_EN
, 1);
908 * Remove repeated voltage values and create table with unique values.
910 * @param hwmgr the address of the powerplay hardware manager.
911 * @param vol_table the pointer to changing voltage table
912 * @return 0 in success
915 static int fiji_trim_voltage_table(struct pp_hwmgr
*hwmgr
,
916 struct pp_atomctrl_voltage_table
*vol_table
)
921 struct pp_atomctrl_voltage_table
*table
;
923 PP_ASSERT_WITH_CODE((NULL
!= vol_table
),
924 "Voltage Table empty.", return -EINVAL
);
925 table
= kzalloc(sizeof(struct pp_atomctrl_voltage_table
),
931 table
->mask_low
= vol_table
->mask_low
;
932 table
->phase_delay
= vol_table
->phase_delay
;
934 for (i
= 0; i
< vol_table
->count
; i
++) {
935 vvalue
= vol_table
->entries
[i
].value
;
938 for (j
= 0; j
< table
->count
; j
++) {
939 if (vvalue
== table
->entries
[j
].value
) {
946 table
->entries
[table
->count
].value
= vvalue
;
947 table
->entries
[table
->count
].smio_low
=
948 vol_table
->entries
[i
].smio_low
;
953 memcpy(vol_table
, table
, sizeof(struct pp_atomctrl_voltage_table
));
959 static int fiji_get_svi2_mvdd_voltage_table(struct pp_hwmgr
*hwmgr
,
960 phm_ppt_v1_clock_voltage_dependency_table
*dep_table
)
964 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
965 struct pp_atomctrl_voltage_table
*vol_table
= &(data
->mvdd_voltage_table
);
967 PP_ASSERT_WITH_CODE((0 != dep_table
->count
),
968 "Voltage Dependency Table empty.", return -EINVAL
);
970 vol_table
->mask_low
= 0;
971 vol_table
->phase_delay
= 0;
972 vol_table
->count
= dep_table
->count
;
974 for (i
= 0; i
< dep_table
->count
; i
++) {
975 vol_table
->entries
[i
].value
= dep_table
->entries
[i
].mvdd
;
976 vol_table
->entries
[i
].smio_low
= 0;
979 result
= fiji_trim_voltage_table(hwmgr
, vol_table
);
980 PP_ASSERT_WITH_CODE((0 == result
),
981 "Failed to trim MVDD table.", return result
);
986 static int fiji_get_svi2_vddci_voltage_table(struct pp_hwmgr
*hwmgr
,
987 phm_ppt_v1_clock_voltage_dependency_table
*dep_table
)
991 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
992 struct pp_atomctrl_voltage_table
*vol_table
= &(data
->vddci_voltage_table
);
994 PP_ASSERT_WITH_CODE((0 != dep_table
->count
),
995 "Voltage Dependency Table empty.", return -EINVAL
);
997 vol_table
->mask_low
= 0;
998 vol_table
->phase_delay
= 0;
999 vol_table
->count
= dep_table
->count
;
1001 for (i
= 0; i
< dep_table
->count
; i
++) {
1002 vol_table
->entries
[i
].value
= dep_table
->entries
[i
].vddci
;
1003 vol_table
->entries
[i
].smio_low
= 0;
1006 result
= fiji_trim_voltage_table(hwmgr
, vol_table
);
1007 PP_ASSERT_WITH_CODE((0 == result
),
1008 "Failed to trim VDDCI table.", return result
);
1013 static int fiji_get_svi2_vdd_voltage_table(struct pp_hwmgr
*hwmgr
,
1014 phm_ppt_v1_voltage_lookup_table
*lookup_table
)
1017 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1018 struct pp_atomctrl_voltage_table
*vol_table
= &(data
->vddc_voltage_table
);
1020 PP_ASSERT_WITH_CODE((0 != lookup_table
->count
),
1021 "Voltage Lookup Table empty.", return -EINVAL
);
1023 vol_table
->mask_low
= 0;
1024 vol_table
->phase_delay
= 0;
1026 vol_table
->count
= lookup_table
->count
;
1028 for (i
= 0; i
< vol_table
->count
; i
++) {
1029 vol_table
->entries
[i
].value
= lookup_table
->entries
[i
].us_vdd
;
1030 vol_table
->entries
[i
].smio_low
= 0;
1036 /* ---- Voltage Tables ----
1037 * If the voltage table would be bigger than
1038 * what will fit into the state table on
1039 * the SMC keep only the higher entries.
1041 static void fiji_trim_voltage_table_to_fit_state_table(struct pp_hwmgr
*hwmgr
,
1042 uint32_t max_vol_steps
, struct pp_atomctrl_voltage_table
*vol_table
)
1044 unsigned int i
, diff
;
1046 if (vol_table
->count
<= max_vol_steps
)
1049 diff
= vol_table
->count
- max_vol_steps
;
1051 for (i
= 0; i
< max_vol_steps
; i
++)
1052 vol_table
->entries
[i
] = vol_table
->entries
[i
+ diff
];
1054 vol_table
->count
= max_vol_steps
;
1060 * Create Voltage Tables.
1062 * @param hwmgr the address of the powerplay hardware manager.
1065 static int fiji_construct_voltage_tables(struct pp_hwmgr
*hwmgr
)
1067 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1068 struct phm_ppt_v1_information
*table_info
=
1069 (struct phm_ppt_v1_information
*)hwmgr
->pptable
;
1072 if (FIJI_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1073 result
= atomctrl_get_voltage_table_v3(hwmgr
,
1074 VOLTAGE_TYPE_MVDDC
, VOLTAGE_OBJ_GPIO_LUT
,
1075 &(data
->mvdd_voltage_table
));
1076 PP_ASSERT_WITH_CODE((0 == result
),
1077 "Failed to retrieve MVDD table.",
1079 } else if (FIJI_VOLTAGE_CONTROL_BY_SVID2
== data
->mvdd_control
) {
1080 result
= fiji_get_svi2_mvdd_voltage_table(hwmgr
,
1081 table_info
->vdd_dep_on_mclk
);
1082 PP_ASSERT_WITH_CODE((0 == result
),
1083 "Failed to retrieve SVI2 MVDD table from dependancy table.",
1087 if (FIJI_VOLTAGE_CONTROL_BY_GPIO
== data
->vddci_control
) {
1088 result
= atomctrl_get_voltage_table_v3(hwmgr
,
1089 VOLTAGE_TYPE_VDDCI
, VOLTAGE_OBJ_GPIO_LUT
,
1090 &(data
->vddci_voltage_table
));
1091 PP_ASSERT_WITH_CODE((0 == result
),
1092 "Failed to retrieve VDDCI table.",
1094 } else if (FIJI_VOLTAGE_CONTROL_BY_SVID2
== data
->vddci_control
) {
1095 result
= fiji_get_svi2_vddci_voltage_table(hwmgr
,
1096 table_info
->vdd_dep_on_mclk
);
1097 PP_ASSERT_WITH_CODE((0 == result
),
1098 "Failed to retrieve SVI2 VDDCI table from dependancy table.",
1102 if(FIJI_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1103 result
= fiji_get_svi2_vdd_voltage_table(hwmgr
,
1104 table_info
->vddc_lookup_table
);
1105 PP_ASSERT_WITH_CODE((0 == result
),
1106 "Failed to retrieve SVI2 VDDC table from lookup table.",
1110 PP_ASSERT_WITH_CODE(
1111 (data
->vddc_voltage_table
.count
<= (SMU73_MAX_LEVELS_VDDC
)),
1112 "Too many voltage values for VDDC. Trimming to fit state table.",
1113 fiji_trim_voltage_table_to_fit_state_table(hwmgr
,
1114 SMU73_MAX_LEVELS_VDDC
, &(data
->vddc_voltage_table
)));
1116 PP_ASSERT_WITH_CODE(
1117 (data
->vddci_voltage_table
.count
<= (SMU73_MAX_LEVELS_VDDCI
)),
1118 "Too many voltage values for VDDCI. Trimming to fit state table.",
1119 fiji_trim_voltage_table_to_fit_state_table(hwmgr
,
1120 SMU73_MAX_LEVELS_VDDCI
, &(data
->vddci_voltage_table
)));
1122 PP_ASSERT_WITH_CODE(
1123 (data
->mvdd_voltage_table
.count
<= (SMU73_MAX_LEVELS_MVDD
)),
1124 "Too many voltage values for MVDD. Trimming to fit state table.",
1125 fiji_trim_voltage_table_to_fit_state_table(hwmgr
,
1126 SMU73_MAX_LEVELS_MVDD
, &(data
->mvdd_voltage_table
)));
1131 static int fiji_initialize_mc_reg_table(struct pp_hwmgr
*hwmgr
)
1133 /* Program additional LP registers
1134 * that are no longer programmed by VBIOS
1136 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING_LP
,
1137 cgs_read_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING
));
1138 cgs_write_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING_LP
,
1139 cgs_read_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING
));
1140 cgs_write_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2_LP
,
1141 cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2
));
1142 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1_LP
,
1143 cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1
));
1144 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0_LP
,
1145 cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0
));
1146 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1_LP
,
1147 cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1
));
1148 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING_LP
,
1149 cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING
));
1155 * Programs static screed detection parameters
1157 * @param hwmgr the address of the powerplay hardware manager.
1160 static int fiji_program_static_screen_threshold_parameters(
1161 struct pp_hwmgr
*hwmgr
)
1163 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1165 /* Set static screen threshold unit */
1166 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
1167 CG_STATIC_SCREEN_PARAMETER
, STATIC_SCREEN_THRESHOLD_UNIT
,
1168 data
->static_screen_threshold_unit
);
1169 /* Set static screen threshold */
1170 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
1171 CG_STATIC_SCREEN_PARAMETER
, STATIC_SCREEN_THRESHOLD
,
1172 data
->static_screen_threshold
);
1178 * Setup display gap for glitch free memory clock switching.
1180 * @param hwmgr the address of the powerplay hardware manager.
1183 static int fiji_enable_display_gap(struct pp_hwmgr
*hwmgr
)
1185 uint32_t displayGap
=
1186 cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1187 ixCG_DISPLAY_GAP_CNTL
);
1189 displayGap
= PHM_SET_FIELD(displayGap
, CG_DISPLAY_GAP_CNTL
,
1190 DISP_GAP
, DISPLAY_GAP_IGNORE
);
1192 displayGap
= PHM_SET_FIELD(displayGap
, CG_DISPLAY_GAP_CNTL
,
1193 DISP_GAP_MCHG
, DISPLAY_GAP_VBLANK
);
1195 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1196 ixCG_DISPLAY_GAP_CNTL
, displayGap
);
1202 * Programs activity state transition voting clients
1204 * @param hwmgr the address of the powerplay hardware manager.
1207 static int fiji_program_voting_clients(struct pp_hwmgr
*hwmgr
)
1209 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1211 /* Clear reset for voting clients before enabling DPM */
1212 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
1213 SCLK_PWRMGT_CNTL
, RESET_SCLK_CNT
, 0);
1214 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
1215 SCLK_PWRMGT_CNTL
, RESET_BUSY_CNT
, 0);
1217 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1218 ixCG_FREQ_TRAN_VOTING_0
, data
->voting_rights_clients0
);
1219 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1220 ixCG_FREQ_TRAN_VOTING_1
, data
->voting_rights_clients1
);
1221 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1222 ixCG_FREQ_TRAN_VOTING_2
, data
->voting_rights_clients2
);
1223 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1224 ixCG_FREQ_TRAN_VOTING_3
, data
->voting_rights_clients3
);
1225 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1226 ixCG_FREQ_TRAN_VOTING_4
, data
->voting_rights_clients4
);
1227 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1228 ixCG_FREQ_TRAN_VOTING_5
, data
->voting_rights_clients5
);
1229 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1230 ixCG_FREQ_TRAN_VOTING_6
, data
->voting_rights_clients6
);
1231 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1232 ixCG_FREQ_TRAN_VOTING_7
, data
->voting_rights_clients7
);
1237 static int fiji_clear_voting_clients(struct pp_hwmgr
*hwmgr
)
1239 /* Reset voting clients before disabling DPM */
1240 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
1241 SCLK_PWRMGT_CNTL
, RESET_SCLK_CNT
, 1);
1242 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
1243 SCLK_PWRMGT_CNTL
, RESET_BUSY_CNT
, 1);
1245 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1246 ixCG_FREQ_TRAN_VOTING_0
, 0);
1247 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1248 ixCG_FREQ_TRAN_VOTING_1
, 0);
1249 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1250 ixCG_FREQ_TRAN_VOTING_2
, 0);
1251 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1252 ixCG_FREQ_TRAN_VOTING_3
, 0);
1253 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1254 ixCG_FREQ_TRAN_VOTING_4
, 0);
1255 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1256 ixCG_FREQ_TRAN_VOTING_5
, 0);
1257 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1258 ixCG_FREQ_TRAN_VOTING_6
, 0);
1259 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1260 ixCG_FREQ_TRAN_VOTING_7
, 0);
1266 * Get the location of various tables inside the FW image.
1268 * @param hwmgr the address of the powerplay hardware manager.
1271 static int fiji_process_firmware_header(struct pp_hwmgr
*hwmgr
)
1273 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1274 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
1279 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
1280 SMU7_FIRMWARE_HEADER_LOCATION
+
1281 offsetof(SMU73_Firmware_Header
, DpmTable
),
1282 &tmp
, data
->sram_end
);
1285 data
->dpm_table_start
= tmp
;
1287 error
|= (0 != result
);
1289 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
1290 SMU7_FIRMWARE_HEADER_LOCATION
+
1291 offsetof(SMU73_Firmware_Header
, SoftRegisters
),
1292 &tmp
, data
->sram_end
);
1295 data
->soft_regs_start
= tmp
;
1296 smu_data
->soft_regs_start
= tmp
;
1299 error
|= (0 != result
);
1301 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
1302 SMU7_FIRMWARE_HEADER_LOCATION
+
1303 offsetof(SMU73_Firmware_Header
, mcRegisterTable
),
1304 &tmp
, data
->sram_end
);
1307 data
->mc_reg_table_start
= tmp
;
1309 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
1310 SMU7_FIRMWARE_HEADER_LOCATION
+
1311 offsetof(SMU73_Firmware_Header
, FanTable
),
1312 &tmp
, data
->sram_end
);
1315 data
->fan_table_start
= tmp
;
1317 error
|= (0 != result
);
1319 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
1320 SMU7_FIRMWARE_HEADER_LOCATION
+
1321 offsetof(SMU73_Firmware_Header
, mcArbDramTimingTable
),
1322 &tmp
, data
->sram_end
);
1325 data
->arb_table_start
= tmp
;
1327 error
|= (0 != result
);
1329 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
1330 SMU7_FIRMWARE_HEADER_LOCATION
+
1331 offsetof(SMU73_Firmware_Header
, Version
),
1332 &tmp
, data
->sram_end
);
1335 hwmgr
->microcode_version_info
.SMC
= tmp
;
1337 error
|= (0 != result
);
1339 return error
? -1 : 0;
1342 /* Copy one arb setting to another and then switch the active set.
1343 * arb_src and arb_dest is one of the MC_CG_ARB_FREQ_Fx constants.
1345 static int fiji_copy_and_switch_arb_sets(struct pp_hwmgr
*hwmgr
,
1346 uint32_t arb_src
, uint32_t arb_dest
)
1348 uint32_t mc_arb_dram_timing
;
1349 uint32_t mc_arb_dram_timing2
;
1350 uint32_t burst_time
;
1351 uint32_t mc_cg_config
;
1354 case MC_CG_ARB_FREQ_F0
:
1355 mc_arb_dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
1356 mc_arb_dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
1357 burst_time
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
);
1359 case MC_CG_ARB_FREQ_F1
:
1360 mc_arb_dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING_1
);
1361 mc_arb_dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2_1
);
1362 burst_time
= PHM_READ_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE1
);
1369 case MC_CG_ARB_FREQ_F0
:
1370 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
, mc_arb_dram_timing
);
1371 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
, mc_arb_dram_timing2
);
1372 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE0
, burst_time
);
1374 case MC_CG_ARB_FREQ_F1
:
1375 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING_1
, mc_arb_dram_timing
);
1376 cgs_write_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2_1
, mc_arb_dram_timing2
);
1377 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_BURST_TIME
, STATE1
, burst_time
);
1383 mc_cg_config
= cgs_read_register(hwmgr
->device
, mmMC_CG_CONFIG
);
1384 mc_cg_config
|= 0x0000000F;
1385 cgs_write_register(hwmgr
->device
, mmMC_CG_CONFIG
, mc_cg_config
);
1386 PHM_WRITE_FIELD(hwmgr
->device
, MC_ARB_CG
, CG_ARB_REQ
, arb_dest
);
1392 * Call SMC to reset S0/S1 to S1 and Reset SMIO to initial value
1394 * @param hwmgr the address of the powerplay hardware manager.
1395 * @return if success then 0;
1397 static int fiji_reset_to_default(struct pp_hwmgr
*hwmgr
)
1399 return smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_ResetToDefaults
);
1403 * Initial switch from ARB F0->F1
1405 * @param hwmgr the address of the powerplay hardware manager.
1407 * This function is to be called from the SetPowerState table.
1409 static int fiji_initial_switch_from_arbf0_to_f1(struct pp_hwmgr
*hwmgr
)
1411 return fiji_copy_and_switch_arb_sets(hwmgr
,
1412 MC_CG_ARB_FREQ_F0
, MC_CG_ARB_FREQ_F1
);
1415 static int fiji_force_switch_to_arbf0(struct pp_hwmgr
*hwmgr
)
1419 tmp
= (cgs_read_ind_register(hwmgr
->device
,
1420 CGS_IND_REG__SMC
, ixSMC_SCRATCH9
) &
1423 if (tmp
== MC_CG_ARB_FREQ_F0
)
1426 return fiji_copy_and_switch_arb_sets(hwmgr
,
1427 tmp
, MC_CG_ARB_FREQ_F0
);
1430 static int fiji_reset_single_dpm_table(struct pp_hwmgr
*hwmgr
,
1431 struct fiji_single_dpm_table
*dpm_table
, uint32_t count
)
1434 PP_ASSERT_WITH_CODE(count
<= MAX_REGULAR_DPM_NUMBER
,
1435 "Fatal error, can not set up single DPM table entries "
1436 "to exceed max number!",);
1438 dpm_table
->count
= count
;
1439 for (i
= 0; i
< MAX_REGULAR_DPM_NUMBER
; i
++)
1440 dpm_table
->dpm_levels
[i
].enabled
= false;
1445 static void fiji_setup_pcie_table_entry(
1446 struct fiji_single_dpm_table
*dpm_table
,
1447 uint32_t index
, uint32_t pcie_gen
,
1448 uint32_t pcie_lanes
)
1450 dpm_table
->dpm_levels
[index
].value
= pcie_gen
;
1451 dpm_table
->dpm_levels
[index
].param1
= pcie_lanes
;
1452 dpm_table
->dpm_levels
[index
].enabled
= true;
1455 static int fiji_setup_default_pcie_table(struct pp_hwmgr
*hwmgr
)
1457 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1458 struct phm_ppt_v1_information
*table_info
=
1459 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1460 struct phm_ppt_v1_pcie_table
*pcie_table
= table_info
->pcie_table
;
1461 uint32_t i
, max_entry
;
1463 PP_ASSERT_WITH_CODE((data
->use_pcie_performance_levels
||
1464 data
->use_pcie_power_saving_levels
), "No pcie performance levels!",
1467 if (data
->use_pcie_performance_levels
&&
1468 !data
->use_pcie_power_saving_levels
) {
1469 data
->pcie_gen_power_saving
= data
->pcie_gen_performance
;
1470 data
->pcie_lane_power_saving
= data
->pcie_lane_performance
;
1471 } else if (!data
->use_pcie_performance_levels
&&
1472 data
->use_pcie_power_saving_levels
) {
1473 data
->pcie_gen_performance
= data
->pcie_gen_power_saving
;
1474 data
->pcie_lane_performance
= data
->pcie_lane_power_saving
;
1477 fiji_reset_single_dpm_table(hwmgr
,
1478 &data
->dpm_table
.pcie_speed_table
, SMU73_MAX_LEVELS_LINK
);
1480 if (pcie_table
!= NULL
) {
1481 /* max_entry is used to make sure we reserve one PCIE level
1482 * for boot level (fix for A+A PSPP issue).
1483 * If PCIE table from PPTable have ULV entry + 8 entries,
1484 * then ignore the last entry.*/
1485 max_entry
= (SMU73_MAX_LEVELS_LINK
< pcie_table
->count
) ?
1486 SMU73_MAX_LEVELS_LINK
: pcie_table
->count
;
1487 for (i
= 1; i
< max_entry
; i
++) {
1488 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, i
- 1,
1489 get_pcie_gen_support(data
->pcie_gen_cap
,
1490 pcie_table
->entries
[i
].gen_speed
),
1491 get_pcie_lane_support(data
->pcie_lane_cap
,
1492 pcie_table
->entries
[i
].lane_width
));
1494 data
->dpm_table
.pcie_speed_table
.count
= max_entry
- 1;
1496 /* Hardcode Pcie Table */
1497 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 0,
1498 get_pcie_gen_support(data
->pcie_gen_cap
,
1500 get_pcie_lane_support(data
->pcie_lane_cap
,
1502 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 1,
1503 get_pcie_gen_support(data
->pcie_gen_cap
,
1505 get_pcie_lane_support(data
->pcie_lane_cap
,
1507 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 2,
1508 get_pcie_gen_support(data
->pcie_gen_cap
,
1510 get_pcie_lane_support(data
->pcie_lane_cap
,
1512 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 3,
1513 get_pcie_gen_support(data
->pcie_gen_cap
,
1515 get_pcie_lane_support(data
->pcie_lane_cap
,
1517 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 4,
1518 get_pcie_gen_support(data
->pcie_gen_cap
,
1520 get_pcie_lane_support(data
->pcie_lane_cap
,
1522 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
, 5,
1523 get_pcie_gen_support(data
->pcie_gen_cap
,
1525 get_pcie_lane_support(data
->pcie_lane_cap
,
1528 data
->dpm_table
.pcie_speed_table
.count
= 6;
1530 /* Populate last level for boot PCIE level, but do not increment count. */
1531 fiji_setup_pcie_table_entry(&data
->dpm_table
.pcie_speed_table
,
1532 data
->dpm_table
.pcie_speed_table
.count
,
1533 get_pcie_gen_support(data
->pcie_gen_cap
,
1535 get_pcie_lane_support(data
->pcie_lane_cap
,
1542 * This function is to initalize all DPM state tables
1543 * for SMU7 based on the dependency table.
1544 * Dynamic state patching function will then trim these
1545 * state tables to the allowed range based
1546 * on the power policy or external client requests,
1547 * such as UVD request, etc.
1549 static int fiji_setup_default_dpm_tables(struct pp_hwmgr
*hwmgr
)
1551 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1552 struct phm_ppt_v1_information
*table_info
=
1553 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1556 struct phm_ppt_v1_clock_voltage_dependency_table
*dep_sclk_table
=
1557 table_info
->vdd_dep_on_sclk
;
1558 struct phm_ppt_v1_clock_voltage_dependency_table
*dep_mclk_table
=
1559 table_info
->vdd_dep_on_mclk
;
1561 PP_ASSERT_WITH_CODE(dep_sclk_table
!= NULL
,
1562 "SCLK dependency table is missing. This table is mandatory",
1564 PP_ASSERT_WITH_CODE(dep_sclk_table
->count
>= 1,
1565 "SCLK dependency table has to have is missing. "
1566 "This table is mandatory",
1569 PP_ASSERT_WITH_CODE(dep_mclk_table
!= NULL
,
1570 "MCLK dependency table is missing. This table is mandatory",
1572 PP_ASSERT_WITH_CODE(dep_mclk_table
->count
>= 1,
1573 "MCLK dependency table has to have is missing. "
1574 "This table is mandatory",
1577 /* clear the state table to reset everything to default */
1578 fiji_reset_single_dpm_table(hwmgr
,
1579 &data
->dpm_table
.sclk_table
, SMU73_MAX_LEVELS_GRAPHICS
);
1580 fiji_reset_single_dpm_table(hwmgr
,
1581 &data
->dpm_table
.mclk_table
, SMU73_MAX_LEVELS_MEMORY
);
1583 /* Initialize Sclk DPM table based on allow Sclk values */
1584 data
->dpm_table
.sclk_table
.count
= 0;
1585 for (i
= 0; i
< dep_sclk_table
->count
; i
++) {
1586 if (i
== 0 || data
->dpm_table
.sclk_table
.dpm_levels
1587 [data
->dpm_table
.sclk_table
.count
- 1].value
!=
1588 dep_sclk_table
->entries
[i
].clk
) {
1589 data
->dpm_table
.sclk_table
.dpm_levels
1590 [data
->dpm_table
.sclk_table
.count
].value
=
1591 dep_sclk_table
->entries
[i
].clk
;
1592 data
->dpm_table
.sclk_table
.dpm_levels
1593 [data
->dpm_table
.sclk_table
.count
].enabled
=
1594 (i
== 0) ? true : false;
1595 data
->dpm_table
.sclk_table
.count
++;
1599 /* Initialize Mclk DPM table based on allow Mclk values */
1600 data
->dpm_table
.mclk_table
.count
= 0;
1601 for (i
=0; i
<dep_mclk_table
->count
; i
++) {
1602 if ( i
==0 || data
->dpm_table
.mclk_table
.dpm_levels
1603 [data
->dpm_table
.mclk_table
.count
- 1].value
!=
1604 dep_mclk_table
->entries
[i
].clk
) {
1605 data
->dpm_table
.mclk_table
.dpm_levels
1606 [data
->dpm_table
.mclk_table
.count
].value
=
1607 dep_mclk_table
->entries
[i
].clk
;
1608 data
->dpm_table
.mclk_table
.dpm_levels
1609 [data
->dpm_table
.mclk_table
.count
].enabled
=
1610 (i
== 0) ? true : false;
1611 data
->dpm_table
.mclk_table
.count
++;
1615 /* setup PCIE gen speed levels */
1616 fiji_setup_default_pcie_table(hwmgr
);
1618 /* save a copy of the default DPM table */
1619 memcpy(&(data
->golden_dpm_table
), &(data
->dpm_table
),
1620 sizeof(struct fiji_dpm_table
));
1626 * @brief PhwFiji_GetVoltageOrder
1627 * Returns index of requested voltage record in lookup(table)
1628 * @param lookup_table - lookup list to search in
1629 * @param voltage - voltage to look for
1630 * @return 0 on success
1632 uint8_t fiji_get_voltage_index(
1633 struct phm_ppt_v1_voltage_lookup_table
*lookup_table
, uint16_t voltage
)
1635 uint8_t count
= (uint8_t) (lookup_table
->count
);
1638 PP_ASSERT_WITH_CODE((NULL
!= lookup_table
),
1639 "Lookup Table empty.", return 0);
1640 PP_ASSERT_WITH_CODE((0 != count
),
1641 "Lookup Table empty.", return 0);
1643 for (i
= 0; i
< lookup_table
->count
; i
++) {
1644 /* find first voltage equal or bigger than requested */
1645 if (lookup_table
->entries
[i
].us_vdd
>= voltage
)
1648 /* voltage is bigger than max voltage in the table */
1653 * Preparation of vddc and vddgfx CAC tables for SMC.
1655 * @param hwmgr the address of the hardware manager
1656 * @param table the SMC DPM table structure to be populated
1659 static int fiji_populate_cac_table(struct pp_hwmgr
*hwmgr
,
1660 struct SMU73_Discrete_DpmTable
*table
)
1664 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1665 struct phm_ppt_v1_information
*table_info
=
1666 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1667 struct phm_ppt_v1_voltage_lookup_table
*lookup_table
=
1668 table_info
->vddc_lookup_table
;
1669 /* tables is already swapped, so in order to use the value from it,
1670 * we need to swap it back.
1671 * We are populating vddc CAC data to BapmVddc table
1672 * in split and merged mode
1674 for( count
= 0; count
<lookup_table
->count
; count
++) {
1675 index
= fiji_get_voltage_index(lookup_table
,
1676 data
->vddc_voltage_table
.entries
[count
].value
);
1677 table
->BapmVddcVidLoSidd
[count
] = (uint8_t) ((6200 -
1678 (lookup_table
->entries
[index
].us_cac_low
*
1679 VOLTAGE_SCALE
)) / 25);
1680 table
->BapmVddcVidHiSidd
[count
] = (uint8_t) ((6200 -
1681 (lookup_table
->entries
[index
].us_cac_high
*
1682 VOLTAGE_SCALE
)) / 25);
1689 * Preparation of voltage tables for SMC.
1691 * @param hwmgr the address of the hardware manager
1692 * @param table the SMC DPM table structure to be populated
1696 int fiji_populate_smc_voltage_tables(struct pp_hwmgr
*hwmgr
,
1697 struct SMU73_Discrete_DpmTable
*table
)
1701 result
= fiji_populate_cac_table(hwmgr
, table
);
1702 PP_ASSERT_WITH_CODE(0 == result
,
1703 "can not populate CAC voltage tables to SMC",
1709 static int fiji_populate_ulv_level(struct pp_hwmgr
*hwmgr
,
1710 struct SMU73_Discrete_Ulv
*state
)
1713 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1714 struct phm_ppt_v1_information
*table_info
=
1715 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1717 state
->CcPwrDynRm
= 0;
1718 state
->CcPwrDynRm1
= 0;
1720 state
->VddcOffset
= (uint16_t) table_info
->us_ulv_voltage_offset
;
1721 state
->VddcOffsetVid
= (uint8_t)( table_info
->us_ulv_voltage_offset
*
1722 VOLTAGE_VID_OFFSET_SCALE2
/ VOLTAGE_VID_OFFSET_SCALE1
);
1724 state
->VddcPhase
= (data
->vddc_phase_shed_control
) ? 0 : 1;
1727 CONVERT_FROM_HOST_TO_SMC_UL(state
->CcPwrDynRm
);
1728 CONVERT_FROM_HOST_TO_SMC_UL(state
->CcPwrDynRm1
);
1729 CONVERT_FROM_HOST_TO_SMC_US(state
->VddcOffset
);
1734 static int fiji_populate_ulv_state(struct pp_hwmgr
*hwmgr
,
1735 struct SMU73_Discrete_DpmTable
*table
)
1737 return fiji_populate_ulv_level(hwmgr
, &table
->Ulv
);
1740 static int32_t fiji_get_dpm_level_enable_mask_value(
1741 struct fiji_single_dpm_table
* dpm_table
)
1746 for (i
= dpm_table
->count
; i
> 0; i
--) {
1748 if (dpm_table
->dpm_levels
[i
- 1].enabled
)
1756 static int fiji_populate_smc_link_level(struct pp_hwmgr
*hwmgr
,
1757 struct SMU73_Discrete_DpmTable
*table
)
1759 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1760 struct fiji_dpm_table
*dpm_table
= &data
->dpm_table
;
1763 /* Index (dpm_table->pcie_speed_table.count)
1764 * is reserved for PCIE boot level. */
1765 for (i
= 0; i
<= dpm_table
->pcie_speed_table
.count
; i
++) {
1766 table
->LinkLevel
[i
].PcieGenSpeed
=
1767 (uint8_t)dpm_table
->pcie_speed_table
.dpm_levels
[i
].value
;
1768 table
->LinkLevel
[i
].PcieLaneCount
= (uint8_t)encode_pcie_lane_width(
1769 dpm_table
->pcie_speed_table
.dpm_levels
[i
].param1
);
1770 table
->LinkLevel
[i
].EnabledForActivity
= 1;
1771 table
->LinkLevel
[i
].SPC
= (uint8_t)(data
->pcie_spc_cap
& 0xff);
1772 table
->LinkLevel
[i
].DownThreshold
= PP_HOST_TO_SMC_UL(5);
1773 table
->LinkLevel
[i
].UpThreshold
= PP_HOST_TO_SMC_UL(30);
1776 data
->smc_state_table
.LinkLevelCount
=
1777 (uint8_t)dpm_table
->pcie_speed_table
.count
;
1778 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
=
1779 fiji_get_dpm_level_enable_mask_value(&dpm_table
->pcie_speed_table
);
1785 * Calculates the SCLK dividers using the provided engine clock
1787 * @param hwmgr the address of the hardware manager
1788 * @param clock the engine clock to use to populate the structure
1789 * @param sclk the SMC SCLK structure to be populated
1791 static int fiji_calculate_sclk_params(struct pp_hwmgr
*hwmgr
,
1792 uint32_t clock
, struct SMU73_Discrete_GraphicsLevel
*sclk
)
1794 const struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1795 struct pp_atomctrl_clock_dividers_vi dividers
;
1796 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
1797 uint32_t spll_func_cntl_3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
1798 uint32_t spll_func_cntl_4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
1799 uint32_t cg_spll_spread_spectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
1800 uint32_t cg_spll_spread_spectrum_2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
1802 uint32_t ref_divider
;
1806 /* get the engine clock dividers for this clock value */
1807 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
, clock
, ÷rs
);
1809 PP_ASSERT_WITH_CODE(result
== 0,
1810 "Error retrieving Engine Clock dividers from VBIOS.",
1813 /* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */
1814 ref_clock
= atomctrl_get_reference_clock(hwmgr
);
1815 ref_divider
= 1 + dividers
.uc_pll_ref_div
;
1817 /* low 14 bits is fraction and high 12 bits is divider */
1818 fbdiv
= dividers
.ul_fb_div
.ul_fb_divider
& 0x3FFFFFF;
1820 /* SPLL_FUNC_CNTL setup */
1821 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
1822 SPLL_REF_DIV
, dividers
.uc_pll_ref_div
);
1823 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
1824 SPLL_PDIV_A
, dividers
.uc_pll_post_div
);
1826 /* SPLL_FUNC_CNTL_3 setup*/
1827 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
, CG_SPLL_FUNC_CNTL_3
,
1828 SPLL_FB_DIV
, fbdiv
);
1830 /* set to use fractional accumulation*/
1831 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
, CG_SPLL_FUNC_CNTL_3
,
1834 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
1835 PHM_PlatformCaps_EngineSpreadSpectrumSupport
)) {
1836 struct pp_atomctrl_internal_ss_info ssInfo
;
1838 uint32_t vco_freq
= clock
* dividers
.uc_pll_post_div
;
1839 if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr
,
1840 vco_freq
, &ssInfo
)) {
1842 * ss_info.speed_spectrum_percentage -- in unit of 0.01%
1843 * ss_info.speed_spectrum_rate -- in unit of khz
1845 * clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2
1847 uint32_t clk_s
= ref_clock
* 5 /
1848 (ref_divider
* ssInfo
.speed_spectrum_rate
);
1849 /* clkv = 2 * D * fbdiv / NS */
1850 uint32_t clk_v
= 4 * ssInfo
.speed_spectrum_percentage
*
1851 fbdiv
/ (clk_s
* 10000);
1853 cg_spll_spread_spectrum
= PHM_SET_FIELD(cg_spll_spread_spectrum
,
1854 CG_SPLL_SPREAD_SPECTRUM
, CLKS
, clk_s
);
1855 cg_spll_spread_spectrum
= PHM_SET_FIELD(cg_spll_spread_spectrum
,
1856 CG_SPLL_SPREAD_SPECTRUM
, SSEN
, 1);
1857 cg_spll_spread_spectrum_2
= PHM_SET_FIELD(cg_spll_spread_spectrum_2
,
1858 CG_SPLL_SPREAD_SPECTRUM_2
, CLKV
, clk_v
);
1862 sclk
->SclkFrequency
= clock
;
1863 sclk
->CgSpllFuncCntl3
= spll_func_cntl_3
;
1864 sclk
->CgSpllFuncCntl4
= spll_func_cntl_4
;
1865 sclk
->SpllSpreadSpectrum
= cg_spll_spread_spectrum
;
1866 sclk
->SpllSpreadSpectrum2
= cg_spll_spread_spectrum_2
;
1867 sclk
->SclkDid
= (uint8_t)dividers
.pll_post_divider
;
1872 static uint16_t fiji_find_closest_vddci(struct pp_hwmgr
*hwmgr
, uint16_t vddci
)
1875 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1876 struct pp_atomctrl_voltage_table
*vddci_table
=
1877 &(data
->vddci_voltage_table
);
1879 for (i
= 0; i
< vddci_table
->count
; i
++) {
1880 if (vddci_table
->entries
[i
].value
>= vddci
)
1881 return vddci_table
->entries
[i
].value
;
1884 PP_ASSERT_WITH_CODE(false,
1885 "VDDCI is larger than max VDDCI in VDDCI Voltage Table!",
1886 return vddci_table
->entries
[i
-1].value
);
1889 static int fiji_get_dependency_volt_by_clk(struct pp_hwmgr
*hwmgr
,
1890 struct phm_ppt_v1_clock_voltage_dependency_table
* dep_table
,
1891 uint32_t clock
, SMU_VoltageLevel
*voltage
, uint32_t *mvdd
)
1895 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1897 *voltage
= *mvdd
= 0;
1899 /* clock - voltage dependency table is empty table */
1900 if (dep_table
->count
== 0)
1903 for (i
= 0; i
< dep_table
->count
; i
++) {
1904 /* find first sclk bigger than request */
1905 if (dep_table
->entries
[i
].clk
>= clock
) {
1906 *voltage
|= (dep_table
->entries
[i
].vddc
*
1907 VOLTAGE_SCALE
) << VDDC_SHIFT
;
1908 if (FIJI_VOLTAGE_CONTROL_NONE
== data
->vddci_control
)
1909 *voltage
|= (data
->vbios_boot_state
.vddci_bootup_value
*
1910 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1911 else if (dep_table
->entries
[i
].vddci
)
1912 *voltage
|= (dep_table
->entries
[i
].vddci
*
1913 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1915 vddci
= fiji_find_closest_vddci(hwmgr
,
1916 (dep_table
->entries
[i
].vddc
-
1917 (uint16_t)data
->vddc_vddci_delta
));
1918 *voltage
|= (vddci
* VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1921 if (FIJI_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
)
1922 *mvdd
= data
->vbios_boot_state
.mvdd_bootup_value
*
1924 else if (dep_table
->entries
[i
].mvdd
)
1925 *mvdd
= (uint32_t) dep_table
->entries
[i
].mvdd
*
1928 *voltage
|= 1 << PHASES_SHIFT
;
1933 /* sclk is bigger than max sclk in the dependence table */
1934 *voltage
|= (dep_table
->entries
[i
- 1].vddc
* VOLTAGE_SCALE
) << VDDC_SHIFT
;
1936 if (FIJI_VOLTAGE_CONTROL_NONE
== data
->vddci_control
)
1937 *voltage
|= (data
->vbios_boot_state
.vddci_bootup_value
*
1938 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1939 else if (dep_table
->entries
[i
-1].vddci
) {
1940 vddci
= fiji_find_closest_vddci(hwmgr
,
1941 (dep_table
->entries
[i
].vddc
-
1942 (uint16_t)data
->vddc_vddci_delta
));
1943 *voltage
|= (vddci
* VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1946 if (FIJI_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
)
1947 *mvdd
= data
->vbios_boot_state
.mvdd_bootup_value
* VOLTAGE_SCALE
;
1948 else if (dep_table
->entries
[i
].mvdd
)
1949 *mvdd
= (uint32_t) dep_table
->entries
[i
- 1].mvdd
* VOLTAGE_SCALE
;
1954 static uint8_t fiji_get_sleep_divider_id_from_clock(uint32_t clock
,
1955 uint32_t clock_insr
)
1959 uint32_t min
= max(clock_insr
, (uint32_t)FIJI_MINIMUM_ENGINE_CLOCK
);
1961 PP_ASSERT_WITH_CODE((clock
>= min
), "Engine clock can't satisfy stutter requirement!", return 0);
1962 for (i
= FIJI_MAX_DEEPSLEEP_DIVIDER_ID
; ; i
--) {
1965 if (temp
>= min
|| i
== 0)
1971 * Populates single SMC SCLK structure using the provided engine clock
1973 * @param hwmgr the address of the hardware manager
1974 * @param clock the engine clock to use to populate the structure
1975 * @param sclk the SMC SCLK structure to be populated
1978 static int fiji_populate_single_graphic_level(struct pp_hwmgr
*hwmgr
,
1979 uint32_t clock
, uint16_t sclk_al_threshold
,
1980 struct SMU73_Discrete_GraphicsLevel
*level
)
1983 /* PP_Clocks minClocks; */
1984 uint32_t threshold
, mvdd
;
1985 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
1986 struct phm_ppt_v1_information
*table_info
=
1987 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1989 result
= fiji_calculate_sclk_params(hwmgr
, clock
, level
);
1991 /* populate graphics levels */
1992 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
1993 table_info
->vdd_dep_on_sclk
, clock
,
1994 &level
->MinVoltage
, &mvdd
);
1995 PP_ASSERT_WITH_CODE((0 == result
),
1996 "can not find VDDC voltage value for "
1997 "VDDC engine clock dependency table",
2000 level
->SclkFrequency
= clock
;
2001 level
->ActivityLevel
= sclk_al_threshold
;
2002 level
->CcPwrDynRm
= 0;
2003 level
->CcPwrDynRm1
= 0;
2004 level
->EnabledForActivity
= 0;
2005 level
->EnabledForThrottle
= 1;
2007 level
->DownHyst
= 0;
2008 level
->VoltageDownHyst
= 0;
2009 level
->PowerThrottle
= 0;
2011 threshold
= clock
* data
->fast_watermark_threshold
/ 100;
2014 data
->display_timing
.min_clock_in_sr
= hwmgr
->display_config
.min_core_set_clock_in_sr
;
2016 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_SclkDeepSleep
))
2017 level
->DeepSleepDivId
= fiji_get_sleep_divider_id_from_clock(clock
,
2018 hwmgr
->display_config
.min_core_set_clock_in_sr
);
2021 /* Default to slow, highest DPM level will be
2022 * set to PPSMC_DISPLAY_WATERMARK_LOW later.
2024 level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2026 CONVERT_FROM_HOST_TO_SMC_UL(level
->MinVoltage
);
2027 CONVERT_FROM_HOST_TO_SMC_UL(level
->SclkFrequency
);
2028 CONVERT_FROM_HOST_TO_SMC_US(level
->ActivityLevel
);
2029 CONVERT_FROM_HOST_TO_SMC_UL(level
->CgSpllFuncCntl3
);
2030 CONVERT_FROM_HOST_TO_SMC_UL(level
->CgSpllFuncCntl4
);
2031 CONVERT_FROM_HOST_TO_SMC_UL(level
->SpllSpreadSpectrum
);
2032 CONVERT_FROM_HOST_TO_SMC_UL(level
->SpllSpreadSpectrum2
);
2033 CONVERT_FROM_HOST_TO_SMC_UL(level
->CcPwrDynRm
);
2034 CONVERT_FROM_HOST_TO_SMC_UL(level
->CcPwrDynRm1
);
2039 * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
2041 * @param hwmgr the address of the hardware manager
2043 static int fiji_populate_all_graphic_levels(struct pp_hwmgr
*hwmgr
)
2045 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2046 struct fiji_dpm_table
*dpm_table
= &data
->dpm_table
;
2047 struct phm_ppt_v1_information
*table_info
=
2048 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2049 struct phm_ppt_v1_pcie_table
*pcie_table
= table_info
->pcie_table
;
2050 uint8_t pcie_entry_cnt
= (uint8_t) data
->dpm_table
.pcie_speed_table
.count
;
2052 uint32_t array
= data
->dpm_table_start
+
2053 offsetof(SMU73_Discrete_DpmTable
, GraphicsLevel
);
2054 uint32_t array_size
= sizeof(struct SMU73_Discrete_GraphicsLevel
) *
2055 SMU73_MAX_LEVELS_GRAPHICS
;
2056 struct SMU73_Discrete_GraphicsLevel
*levels
=
2057 data
->smc_state_table
.GraphicsLevel
;
2058 uint32_t i
, max_entry
;
2059 uint8_t hightest_pcie_level_enabled
= 0,
2060 lowest_pcie_level_enabled
= 0,
2061 mid_pcie_level_enabled
= 0,
2064 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
2065 result
= fiji_populate_single_graphic_level(hwmgr
,
2066 dpm_table
->sclk_table
.dpm_levels
[i
].value
,
2067 (uint16_t)data
->activity_target
[i
],
2072 /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
2074 levels
[i
].DeepSleepDivId
= 0;
2077 /* Only enable level 0 for now.*/
2078 levels
[0].EnabledForActivity
= 1;
2080 /* set highest level watermark to high */
2081 levels
[dpm_table
->sclk_table
.count
- 1].DisplayWatermark
=
2082 PPSMC_DISPLAY_WATERMARK_HIGH
;
2084 data
->smc_state_table
.GraphicsDpmLevelCount
=
2085 (uint8_t)dpm_table
->sclk_table
.count
;
2086 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
=
2087 fiji_get_dpm_level_enable_mask_value(&dpm_table
->sclk_table
);
2089 if (pcie_table
!= NULL
) {
2090 PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt
),
2091 "There must be 1 or more PCIE levels defined in PPTable.",
2093 max_entry
= pcie_entry_cnt
- 1;
2094 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++)
2095 levels
[i
].pcieDpmLevel
=
2096 (uint8_t) ((i
< max_entry
)? i
: max_entry
);
2098 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
2099 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2100 (1 << (hightest_pcie_level_enabled
+ 1))) != 0 ))
2101 hightest_pcie_level_enabled
++;
2103 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
2104 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2105 (1 << lowest_pcie_level_enabled
)) == 0 ))
2106 lowest_pcie_level_enabled
++;
2108 while ((count
< hightest_pcie_level_enabled
) &&
2109 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
2110 (1 << (lowest_pcie_level_enabled
+ 1 + count
))) == 0 ))
2113 mid_pcie_level_enabled
= (lowest_pcie_level_enabled
+ 1+ count
) <
2114 hightest_pcie_level_enabled
?
2115 (lowest_pcie_level_enabled
+ 1 + count
) :
2116 hightest_pcie_level_enabled
;
2118 /* set pcieDpmLevel to hightest_pcie_level_enabled */
2119 for(i
= 2; i
< dpm_table
->sclk_table
.count
; i
++)
2120 levels
[i
].pcieDpmLevel
= hightest_pcie_level_enabled
;
2122 /* set pcieDpmLevel to lowest_pcie_level_enabled */
2123 levels
[0].pcieDpmLevel
= lowest_pcie_level_enabled
;
2125 /* set pcieDpmLevel to mid_pcie_level_enabled */
2126 levels
[1].pcieDpmLevel
= mid_pcie_level_enabled
;
2128 /* level count will send to smc once at init smc table and never change */
2129 result
= fiji_copy_bytes_to_smc(hwmgr
->smumgr
, array
, (uint8_t *)levels
,
2130 (uint32_t)array_size
, data
->sram_end
);
2136 * MCLK Frequency Ratio
2137 * SEQ_CG_RESP Bit[31:24] - 0x0
2138 * Bit[27:24] \96 DDR3 Frequency ratio
2139 * 0x0 <= 100MHz, 450 < 0x8 <= 500MHz
2140 * 100 < 0x1 <= 150MHz, 500 < 0x9 <= 550MHz
2141 * 150 < 0x2 <= 200MHz, 550 < 0xA <= 600MHz
2142 * 200 < 0x3 <= 250MHz, 600 < 0xB <= 650MHz
2143 * 250 < 0x4 <= 300MHz, 650 < 0xC <= 700MHz
2144 * 300 < 0x5 <= 350MHz, 700 < 0xD <= 750MHz
2145 * 350 < 0x6 <= 400MHz, 750 < 0xE <= 800MHz
2146 * 400 < 0x7 <= 450MHz, 800 < 0xF
2148 static uint8_t fiji_get_mclk_frequency_ratio(uint32_t mem_clock
)
2150 if (mem_clock
<= 10000) return 0x0;
2151 if (mem_clock
<= 15000) return 0x1;
2152 if (mem_clock
<= 20000) return 0x2;
2153 if (mem_clock
<= 25000) return 0x3;
2154 if (mem_clock
<= 30000) return 0x4;
2155 if (mem_clock
<= 35000) return 0x5;
2156 if (mem_clock
<= 40000) return 0x6;
2157 if (mem_clock
<= 45000) return 0x7;
2158 if (mem_clock
<= 50000) return 0x8;
2159 if (mem_clock
<= 55000) return 0x9;
2160 if (mem_clock
<= 60000) return 0xa;
2161 if (mem_clock
<= 65000) return 0xb;
2162 if (mem_clock
<= 70000) return 0xc;
2163 if (mem_clock
<= 75000) return 0xd;
2164 if (mem_clock
<= 80000) return 0xe;
2165 /* mem_clock > 800MHz */
2170 * Populates the SMC MCLK structure using the provided memory clock
2172 * @param hwmgr the address of the hardware manager
2173 * @param clock the memory clock to use to populate the structure
2174 * @param sclk the SMC SCLK structure to be populated
2176 static int fiji_calculate_mclk_params(struct pp_hwmgr
*hwmgr
,
2177 uint32_t clock
, struct SMU73_Discrete_MemoryLevel
*mclk
)
2179 struct pp_atomctrl_memory_clock_param mem_param
;
2182 result
= atomctrl_get_memory_pll_dividers_vi(hwmgr
, clock
, &mem_param
);
2183 PP_ASSERT_WITH_CODE((0 == result
),
2184 "Failed to get Memory PLL Dividers.",);
2186 /* Save the result data to outpupt memory level structure */
2187 mclk
->MclkFrequency
= clock
;
2188 mclk
->MclkDivider
= (uint8_t)mem_param
.mpll_post_divider
;
2189 mclk
->FreqRange
= fiji_get_mclk_frequency_ratio(clock
);
2194 static int fiji_populate_single_memory_level(struct pp_hwmgr
*hwmgr
,
2195 uint32_t clock
, struct SMU73_Discrete_MemoryLevel
*mem_level
)
2197 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2198 struct phm_ppt_v1_information
*table_info
=
2199 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2202 if (table_info
->vdd_dep_on_mclk
) {
2203 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
2204 table_info
->vdd_dep_on_mclk
, clock
,
2205 &mem_level
->MinVoltage
, &mem_level
->MinMvdd
);
2206 PP_ASSERT_WITH_CODE((0 == result
),
2207 "can not find MinVddc voltage value from memory "
2208 "VDDC voltage dependency table", return result
);
2211 mem_level
->EnabledForThrottle
= 1;
2212 mem_level
->EnabledForActivity
= 0;
2213 mem_level
->UpHyst
= 0;
2214 mem_level
->DownHyst
= 100;
2215 mem_level
->VoltageDownHyst
= 0;
2216 mem_level
->ActivityLevel
= (uint16_t)data
->mclk_activity_target
;
2217 mem_level
->StutterEnable
= false;
2219 mem_level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2221 /* enable stutter mode if all the follow condition applied
2222 * PECI_GetNumberOfActiveDisplays(hwmgr->pPECI,
2223 * &(data->DisplayTiming.numExistingDisplays));
2225 data
->display_timing
.num_existing_displays
= 1;
2227 if ((data
->mclk_stutter_mode_threshold
) &&
2228 (clock
<= data
->mclk_stutter_mode_threshold
) &&
2229 (!data
->is_uvd_enabled
) &&
2230 (PHM_READ_FIELD(hwmgr
->device
, DPG_PIPE_STUTTER_CONTROL
,
2231 STUTTER_ENABLE
) & 0x1))
2232 mem_level
->StutterEnable
= true;
2234 result
= fiji_calculate_mclk_params(hwmgr
, clock
, mem_level
);
2236 CONVERT_FROM_HOST_TO_SMC_UL(mem_level
->MinMvdd
);
2237 CONVERT_FROM_HOST_TO_SMC_UL(mem_level
->MclkFrequency
);
2238 CONVERT_FROM_HOST_TO_SMC_US(mem_level
->ActivityLevel
);
2239 CONVERT_FROM_HOST_TO_SMC_UL(mem_level
->MinVoltage
);
2245 * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
2247 * @param hwmgr the address of the hardware manager
2249 static int fiji_populate_all_memory_levels(struct pp_hwmgr
*hwmgr
)
2251 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2252 struct fiji_dpm_table
*dpm_table
= &data
->dpm_table
;
2254 /* populate MCLK dpm table to SMU7 */
2255 uint32_t array
= data
->dpm_table_start
+
2256 offsetof(SMU73_Discrete_DpmTable
, MemoryLevel
);
2257 uint32_t array_size
= sizeof(SMU73_Discrete_MemoryLevel
) *
2258 SMU73_MAX_LEVELS_MEMORY
;
2259 struct SMU73_Discrete_MemoryLevel
*levels
=
2260 data
->smc_state_table
.MemoryLevel
;
2263 for (i
= 0; i
< dpm_table
->mclk_table
.count
; i
++) {
2264 PP_ASSERT_WITH_CODE((0 != dpm_table
->mclk_table
.dpm_levels
[i
].value
),
2265 "can not populate memory level as memory clock is zero",
2267 result
= fiji_populate_single_memory_level(hwmgr
,
2268 dpm_table
->mclk_table
.dpm_levels
[i
].value
,
2274 /* Only enable level 0 for now. */
2275 levels
[0].EnabledForActivity
= 1;
2277 /* in order to prevent MC activity from stutter mode to push DPM up.
2278 * the UVD change complements this by putting the MCLK in
2279 * a higher state by default such that we are not effected by
2280 * up threshold or and MCLK DPM latency.
2282 levels
[0].ActivityLevel
= (uint16_t)data
->mclk_dpm0_activity_target
;
2283 CONVERT_FROM_HOST_TO_SMC_US(levels
[0].ActivityLevel
);
2285 data
->smc_state_table
.MemoryDpmLevelCount
=
2286 (uint8_t)dpm_table
->mclk_table
.count
;
2287 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
=
2288 fiji_get_dpm_level_enable_mask_value(&dpm_table
->mclk_table
);
2289 /* set highest level watermark to high */
2290 levels
[dpm_table
->mclk_table
.count
- 1].DisplayWatermark
=
2291 PPSMC_DISPLAY_WATERMARK_HIGH
;
2293 /* level count will send to smc once at init smc table and never change */
2294 result
= fiji_copy_bytes_to_smc(hwmgr
->smumgr
, array
, (uint8_t *)levels
,
2295 (uint32_t)array_size
, data
->sram_end
);
2301 * Populates the SMC MVDD structure using the provided memory clock.
2303 * @param hwmgr the address of the hardware manager
2304 * @param mclk the MCLK value to be used in the decision if MVDD should be high or low.
2305 * @param voltage the SMC VOLTAGE structure to be populated
2307 int fiji_populate_mvdd_value(struct pp_hwmgr
*hwmgr
,
2308 uint32_t mclk
, SMIO_Pattern
*smio_pat
)
2310 const struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2311 struct phm_ppt_v1_information
*table_info
=
2312 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2315 if (FIJI_VOLTAGE_CONTROL_NONE
!= data
->mvdd_control
) {
2316 /* find mvdd value which clock is more than request */
2317 for (i
= 0; i
< table_info
->vdd_dep_on_mclk
->count
; i
++) {
2318 if (mclk
<= table_info
->vdd_dep_on_mclk
->entries
[i
].clk
) {
2319 smio_pat
->Voltage
= data
->mvdd_voltage_table
.entries
[i
].value
;
2323 PP_ASSERT_WITH_CODE(i
< table_info
->vdd_dep_on_mclk
->count
,
2324 "MVDD Voltage is outside the supported range.",
2332 static int fiji_populate_smc_acpi_level(struct pp_hwmgr
*hwmgr
,
2333 SMU73_Discrete_DpmTable
*table
)
2336 const struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2337 struct phm_ppt_v1_information
*table_info
=
2338 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2339 struct pp_atomctrl_clock_dividers_vi dividers
;
2340 SMIO_Pattern vol_level
;
2343 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
2344 uint32_t spll_func_cntl_2
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
;
2346 table
->ACPILevel
.Flags
&= ~PPSMC_SWSTATE_FLAG_DC
;
2348 if (!data
->sclk_dpm_key_disabled
) {
2349 /* Get MinVoltage and Frequency from DPM0,
2350 * already converted to SMC_UL */
2351 table
->ACPILevel
.SclkFrequency
=
2352 data
->dpm_table
.sclk_table
.dpm_levels
[0].value
;
2353 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
2354 table_info
->vdd_dep_on_sclk
,
2355 table
->ACPILevel
.SclkFrequency
,
2356 &table
->ACPILevel
.MinVoltage
, &mvdd
);
2357 PP_ASSERT_WITH_CODE((0 == result
),
2358 "Cannot find ACPI VDDC voltage value "
2359 "in Clock Dependency Table",);
2361 table
->ACPILevel
.SclkFrequency
=
2362 data
->vbios_boot_state
.sclk_bootup_value
;
2363 table
->ACPILevel
.MinVoltage
=
2364 data
->vbios_boot_state
.vddc_bootup_value
* VOLTAGE_SCALE
;
2367 /* get the engine clock dividers for this clock value */
2368 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
,
2369 table
->ACPILevel
.SclkFrequency
, ÷rs
);
2370 PP_ASSERT_WITH_CODE(result
== 0,
2371 "Error retrieving Engine Clock dividers from VBIOS.",
2374 table
->ACPILevel
.SclkDid
= (uint8_t)dividers
.pll_post_divider
;
2375 table
->ACPILevel
.DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
2376 table
->ACPILevel
.DeepSleepDivId
= 0;
2378 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
2380 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
2382 spll_func_cntl_2
= PHM_SET_FIELD(spll_func_cntl_2
, CG_SPLL_FUNC_CNTL_2
,
2385 table
->ACPILevel
.CgSpllFuncCntl
= spll_func_cntl
;
2386 table
->ACPILevel
.CgSpllFuncCntl2
= spll_func_cntl_2
;
2387 table
->ACPILevel
.CgSpllFuncCntl3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
2388 table
->ACPILevel
.CgSpllFuncCntl4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
2389 table
->ACPILevel
.SpllSpreadSpectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
2390 table
->ACPILevel
.SpllSpreadSpectrum2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
2391 table
->ACPILevel
.CcPwrDynRm
= 0;
2392 table
->ACPILevel
.CcPwrDynRm1
= 0;
2394 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.Flags
);
2395 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SclkFrequency
);
2396 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.MinVoltage
);
2397 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl
);
2398 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl2
);
2399 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl3
);
2400 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl4
);
2401 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum
);
2402 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum2
);
2403 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm
);
2404 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm1
);
2406 if (!data
->mclk_dpm_key_disabled
) {
2407 /* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */
2408 table
->MemoryACPILevel
.MclkFrequency
=
2409 data
->dpm_table
.mclk_table
.dpm_levels
[0].value
;
2410 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
2411 table_info
->vdd_dep_on_mclk
,
2412 table
->MemoryACPILevel
.MclkFrequency
,
2413 &table
->MemoryACPILevel
.MinVoltage
, &mvdd
);
2414 PP_ASSERT_WITH_CODE((0 == result
),
2415 "Cannot find ACPI VDDCI voltage value "
2416 "in Clock Dependency Table",);
2418 table
->MemoryACPILevel
.MclkFrequency
=
2419 data
->vbios_boot_state
.mclk_bootup_value
;
2420 table
->MemoryACPILevel
.MinVoltage
=
2421 data
->vbios_boot_state
.vddci_bootup_value
* VOLTAGE_SCALE
;
2425 if ((FIJI_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
) ||
2426 (data
->mclk_dpm_key_disabled
))
2427 us_mvdd
= data
->vbios_boot_state
.mvdd_bootup_value
;
2429 if (!fiji_populate_mvdd_value(hwmgr
,
2430 data
->dpm_table
.mclk_table
.dpm_levels
[0].value
,
2432 us_mvdd
= vol_level
.Voltage
;
2435 table
->MemoryACPILevel
.MinMvdd
=
2436 PP_HOST_TO_SMC_UL(us_mvdd
* VOLTAGE_SCALE
);
2438 table
->MemoryACPILevel
.EnabledForThrottle
= 0;
2439 table
->MemoryACPILevel
.EnabledForActivity
= 0;
2440 table
->MemoryACPILevel
.UpHyst
= 0;
2441 table
->MemoryACPILevel
.DownHyst
= 100;
2442 table
->MemoryACPILevel
.VoltageDownHyst
= 0;
2443 table
->MemoryACPILevel
.ActivityLevel
=
2444 PP_HOST_TO_SMC_US((uint16_t)data
->mclk_activity_target
);
2446 table
->MemoryACPILevel
.StutterEnable
= false;
2447 CONVERT_FROM_HOST_TO_SMC_UL(table
->MemoryACPILevel
.MclkFrequency
);
2448 CONVERT_FROM_HOST_TO_SMC_UL(table
->MemoryACPILevel
.MinVoltage
);
2453 static int fiji_populate_smc_vce_level(struct pp_hwmgr
*hwmgr
,
2454 SMU73_Discrete_DpmTable
*table
)
2456 int result
= -EINVAL
;
2458 struct pp_atomctrl_clock_dividers_vi dividers
;
2459 struct phm_ppt_v1_information
*table_info
=
2460 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2461 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
2462 table_info
->mm_dep_table
;
2463 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2465 table
->VceLevelCount
= (uint8_t)(mm_table
->count
);
2466 table
->VceBootLevel
= 0;
2468 for(count
= 0; count
< table
->VceLevelCount
; count
++) {
2469 table
->VceLevel
[count
].Frequency
= mm_table
->entries
[count
].eclk
;
2470 table
->VceLevel
[count
].MinVoltage
= 0;
2471 table
->VceLevel
[count
].MinVoltage
|=
2472 (mm_table
->entries
[count
].vddc
* VOLTAGE_SCALE
) << VDDC_SHIFT
;
2473 table
->VceLevel
[count
].MinVoltage
|=
2474 ((mm_table
->entries
[count
].vddc
- data
->vddc_vddci_delta
) *
2475 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
2476 table
->VceLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
2478 /*retrieve divider value for VBIOS */
2479 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
2480 table
->VceLevel
[count
].Frequency
, ÷rs
);
2481 PP_ASSERT_WITH_CODE((0 == result
),
2482 "can not find divide id for VCE engine clock",
2485 table
->VceLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
2487 CONVERT_FROM_HOST_TO_SMC_UL(table
->VceLevel
[count
].Frequency
);
2488 CONVERT_FROM_HOST_TO_SMC_UL(table
->VceLevel
[count
].MinVoltage
);
2493 static int fiji_populate_smc_acp_level(struct pp_hwmgr
*hwmgr
,
2494 SMU73_Discrete_DpmTable
*table
)
2496 int result
= -EINVAL
;
2498 struct pp_atomctrl_clock_dividers_vi dividers
;
2499 struct phm_ppt_v1_information
*table_info
=
2500 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2501 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
2502 table_info
->mm_dep_table
;
2503 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2505 table
->AcpLevelCount
= (uint8_t)(mm_table
->count
);
2506 table
->AcpBootLevel
= 0;
2508 for (count
= 0; count
< table
->AcpLevelCount
; count
++) {
2509 table
->AcpLevel
[count
].Frequency
= mm_table
->entries
[count
].aclk
;
2510 table
->AcpLevel
[count
].MinVoltage
|= (mm_table
->entries
[count
].vddc
*
2511 VOLTAGE_SCALE
) << VDDC_SHIFT
;
2512 table
->AcpLevel
[count
].MinVoltage
|= ((mm_table
->entries
[count
].vddc
-
2513 data
->vddc_vddci_delta
) * VOLTAGE_SCALE
) << VDDCI_SHIFT
;
2514 table
->AcpLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
2516 /* retrieve divider value for VBIOS */
2517 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
2518 table
->AcpLevel
[count
].Frequency
, ÷rs
);
2519 PP_ASSERT_WITH_CODE((0 == result
),
2520 "can not find divide id for engine clock", return result
);
2522 table
->AcpLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
2524 CONVERT_FROM_HOST_TO_SMC_UL(table
->AcpLevel
[count
].Frequency
);
2525 CONVERT_FROM_HOST_TO_SMC_UL(table
->AcpLevel
[count
].MinVoltage
);
2530 static int fiji_populate_smc_samu_level(struct pp_hwmgr
*hwmgr
,
2531 SMU73_Discrete_DpmTable
*table
)
2533 int result
= -EINVAL
;
2535 struct pp_atomctrl_clock_dividers_vi dividers
;
2536 struct phm_ppt_v1_information
*table_info
=
2537 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2538 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
2539 table_info
->mm_dep_table
;
2540 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2542 table
->SamuBootLevel
= 0;
2543 table
->SamuLevelCount
= (uint8_t)(mm_table
->count
);
2545 for (count
= 0; count
< table
->SamuLevelCount
; count
++) {
2546 /* not sure whether we need evclk or not */
2547 table
->SamuLevel
[count
].MinVoltage
= 0;
2548 table
->SamuLevel
[count
].Frequency
= mm_table
->entries
[count
].samclock
;
2549 table
->SamuLevel
[count
].MinVoltage
|= (mm_table
->entries
[count
].vddc
*
2550 VOLTAGE_SCALE
) << VDDC_SHIFT
;
2551 table
->SamuLevel
[count
].MinVoltage
|= ((mm_table
->entries
[count
].vddc
-
2552 data
->vddc_vddci_delta
) * VOLTAGE_SCALE
) << VDDCI_SHIFT
;
2553 table
->SamuLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
2555 /* retrieve divider value for VBIOS */
2556 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
2557 table
->SamuLevel
[count
].Frequency
, ÷rs
);
2558 PP_ASSERT_WITH_CODE((0 == result
),
2559 "can not find divide id for samu clock", return result
);
2561 table
->SamuLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
2563 CONVERT_FROM_HOST_TO_SMC_UL(table
->SamuLevel
[count
].Frequency
);
2564 CONVERT_FROM_HOST_TO_SMC_UL(table
->SamuLevel
[count
].MinVoltage
);
2569 static int fiji_populate_memory_timing_parameters(struct pp_hwmgr
*hwmgr
,
2570 int32_t eng_clock
, int32_t mem_clock
,
2571 struct SMU73_Discrete_MCArbDramTimingTableEntry
*arb_regs
)
2573 uint32_t dram_timing
;
2574 uint32_t dram_timing2
;
2576 ULONG state
, trrds
, trrdl
;
2579 result
= atomctrl_set_engine_dram_timings_rv770(hwmgr
,
2580 eng_clock
, mem_clock
);
2581 PP_ASSERT_WITH_CODE(result
== 0,
2582 "Error calling VBIOS to set DRAM_TIMING.", return result
);
2584 dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
2585 dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
2586 burstTime
= cgs_read_register(hwmgr
->device
, mmMC_ARB_BURST_TIME
);
2588 state
= PHM_GET_FIELD(burstTime
, MC_ARB_BURST_TIME
, STATE0
);
2589 trrds
= PHM_GET_FIELD(burstTime
, MC_ARB_BURST_TIME
, TRRDS0
);
2590 trrdl
= PHM_GET_FIELD(burstTime
, MC_ARB_BURST_TIME
, TRRDL0
);
2592 arb_regs
->McArbDramTiming
= PP_HOST_TO_SMC_UL(dram_timing
);
2593 arb_regs
->McArbDramTiming2
= PP_HOST_TO_SMC_UL(dram_timing2
);
2594 arb_regs
->McArbBurstTime
= (uint8_t)burstTime
;
2595 arb_regs
->TRRDS
= (uint8_t)trrds
;
2596 arb_regs
->TRRDL
= (uint8_t)trrdl
;
2601 static int fiji_program_memory_timing_parameters(struct pp_hwmgr
*hwmgr
)
2603 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2604 struct SMU73_Discrete_MCArbDramTimingTable arb_regs
;
2608 for (i
= 0; i
< data
->dpm_table
.sclk_table
.count
; i
++) {
2609 for (j
= 0; j
< data
->dpm_table
.mclk_table
.count
; j
++) {
2610 result
= fiji_populate_memory_timing_parameters(hwmgr
,
2611 data
->dpm_table
.sclk_table
.dpm_levels
[i
].value
,
2612 data
->dpm_table
.mclk_table
.dpm_levels
[j
].value
,
2613 &arb_regs
.entries
[i
][j
]);
2620 result
= fiji_copy_bytes_to_smc(
2622 data
->arb_table_start
,
2623 (uint8_t *)&arb_regs
,
2624 sizeof(SMU73_Discrete_MCArbDramTimingTable
),
2629 static int fiji_populate_smc_uvd_level(struct pp_hwmgr
*hwmgr
,
2630 struct SMU73_Discrete_DpmTable
*table
)
2632 int result
= -EINVAL
;
2634 struct pp_atomctrl_clock_dividers_vi dividers
;
2635 struct phm_ppt_v1_information
*table_info
=
2636 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2637 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
2638 table_info
->mm_dep_table
;
2639 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2641 table
->UvdLevelCount
= (uint8_t)(mm_table
->count
);
2642 table
->UvdBootLevel
= 0;
2644 for (count
= 0; count
< table
->UvdLevelCount
; count
++) {
2645 table
->UvdLevel
[count
].MinVoltage
= 0;
2646 table
->UvdLevel
[count
].VclkFrequency
= mm_table
->entries
[count
].vclk
;
2647 table
->UvdLevel
[count
].DclkFrequency
= mm_table
->entries
[count
].dclk
;
2648 table
->UvdLevel
[count
].MinVoltage
|= (mm_table
->entries
[count
].vddc
*
2649 VOLTAGE_SCALE
) << VDDC_SHIFT
;
2650 table
->UvdLevel
[count
].MinVoltage
|= ((mm_table
->entries
[count
].vddc
-
2651 data
->vddc_vddci_delta
) * VOLTAGE_SCALE
) << VDDCI_SHIFT
;
2652 table
->UvdLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
2654 /* retrieve divider value for VBIOS */
2655 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
2656 table
->UvdLevel
[count
].VclkFrequency
, ÷rs
);
2657 PP_ASSERT_WITH_CODE((0 == result
),
2658 "can not find divide id for Vclk clock", return result
);
2660 table
->UvdLevel
[count
].VclkDivider
= (uint8_t)dividers
.pll_post_divider
;
2662 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
2663 table
->UvdLevel
[count
].DclkFrequency
, ÷rs
);
2664 PP_ASSERT_WITH_CODE((0 == result
),
2665 "can not find divide id for Dclk clock", return result
);
2667 table
->UvdLevel
[count
].DclkDivider
= (uint8_t)dividers
.pll_post_divider
;
2669 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].VclkFrequency
);
2670 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].DclkFrequency
);
2671 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].MinVoltage
);
2677 static int fiji_find_boot_level(struct fiji_single_dpm_table
*table
,
2678 uint32_t value
, uint32_t *boot_level
)
2680 int result
= -EINVAL
;
2683 for (i
= 0; i
< table
->count
; i
++) {
2684 if (value
== table
->dpm_levels
[i
].value
) {
2692 static int fiji_populate_smc_boot_level(struct pp_hwmgr
*hwmgr
,
2693 struct SMU73_Discrete_DpmTable
*table
)
2696 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2698 table
->GraphicsBootLevel
= 0;
2699 table
->MemoryBootLevel
= 0;
2701 /* find boot level from dpm table */
2702 result
= fiji_find_boot_level(&(data
->dpm_table
.sclk_table
),
2703 data
->vbios_boot_state
.sclk_bootup_value
,
2704 (uint32_t *)&(table
->GraphicsBootLevel
));
2706 result
= fiji_find_boot_level(&(data
->dpm_table
.mclk_table
),
2707 data
->vbios_boot_state
.mclk_bootup_value
,
2708 (uint32_t *)&(table
->MemoryBootLevel
));
2710 table
->BootVddc
= data
->vbios_boot_state
.vddc_bootup_value
*
2712 table
->BootVddci
= data
->vbios_boot_state
.vddci_bootup_value
*
2714 table
->BootMVdd
= data
->vbios_boot_state
.mvdd_bootup_value
*
2717 CONVERT_FROM_HOST_TO_SMC_US(table
->BootVddc
);
2718 CONVERT_FROM_HOST_TO_SMC_US(table
->BootVddci
);
2719 CONVERT_FROM_HOST_TO_SMC_US(table
->BootMVdd
);
2724 static int fiji_populate_smc_initailial_state(struct pp_hwmgr
*hwmgr
)
2726 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2727 struct phm_ppt_v1_information
*table_info
=
2728 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2729 uint8_t count
, level
;
2731 count
= (uint8_t)(table_info
->vdd_dep_on_sclk
->count
);
2732 for (level
= 0; level
< count
; level
++) {
2733 if(table_info
->vdd_dep_on_sclk
->entries
[level
].clk
>=
2734 data
->vbios_boot_state
.sclk_bootup_value
) {
2735 data
->smc_state_table
.GraphicsBootLevel
= level
;
2740 count
= (uint8_t)(table_info
->vdd_dep_on_mclk
->count
);
2741 for (level
= 0; level
< count
; level
++) {
2742 if(table_info
->vdd_dep_on_mclk
->entries
[level
].clk
>=
2743 data
->vbios_boot_state
.mclk_bootup_value
) {
2744 data
->smc_state_table
.MemoryBootLevel
= level
;
2752 static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr
*hwmgr
)
2754 uint32_t ro
, efuse
, efuse2
, clock_freq
, volt_without_cks
,
2755 volt_with_cks
, value
;
2756 uint16_t clock_freq_u16
;
2757 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2758 uint8_t type
, i
, j
, cks_setting
, stretch_amount
, stretch_amount2
,
2760 struct phm_ppt_v1_information
*table_info
=
2761 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2762 struct phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
=
2763 table_info
->vdd_dep_on_sclk
;
2765 stretch_amount
= (uint8_t)table_info
->cac_dtp_table
->usClockStretchAmount
;
2767 /* Read SMU_Eefuse to read and calculate RO and determine
2768 * if the part is SS or FF. if RO >= 1660MHz, part is FF.
2770 efuse
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
2771 ixSMU_EFUSE_0
+ (146 * 4));
2772 efuse2
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
2773 ixSMU_EFUSE_0
+ (148 * 4));
2774 efuse
&= 0xFF000000;
2775 efuse
= efuse
>> 24;
2779 ro
= (2300 - 1350) * efuse
/ 255 + 1350;
2781 ro
= (2500 - 1000) * efuse
/ 255 + 1000;
2788 /* Populate Stretch amount */
2789 data
->smc_state_table
.ClockStretcherAmount
= stretch_amount
;
2791 /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
2792 for (i
= 0; i
< sclk_table
->count
; i
++) {
2793 data
->smc_state_table
.Sclk_CKS_masterEn0_7
|=
2794 sclk_table
->entries
[i
].cks_enable
<< i
;
2795 volt_without_cks
= (uint32_t)((14041 *
2796 (sclk_table
->entries
[i
].clk
/100) / 10000 + 3571 + 75 - ro
) * 1000 /
2797 (4026 - (13924 * (sclk_table
->entries
[i
].clk
/100) / 10000)));
2798 volt_with_cks
= (uint32_t)((13946 *
2799 (sclk_table
->entries
[i
].clk
/100) / 10000 + 3320 + 45 - ro
) * 1000 /
2800 (3664 - (11454 * (sclk_table
->entries
[i
].clk
/100) / 10000)));
2801 if (volt_without_cks
>= volt_with_cks
)
2802 volt_offset
= (uint8_t)(((volt_without_cks
- volt_with_cks
+
2803 sclk_table
->entries
[i
].cks_voffset
) * 100 / 625) + 1);
2804 data
->smc_state_table
.Sclk_voltageOffset
[i
] = volt_offset
;
2807 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
2808 STRETCH_ENABLE
, 0x0);
2809 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
2811 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
2813 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
2816 /* Populate CKS Lookup Table */
2817 if (stretch_amount
== 1 || stretch_amount
== 2 || stretch_amount
== 5)
2818 stretch_amount2
= 0;
2819 else if (stretch_amount
== 3 || stretch_amount
== 4)
2820 stretch_amount2
= 1;
2822 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
2823 PHM_PlatformCaps_ClockStretcher
);
2824 PP_ASSERT_WITH_CODE(false,
2825 "Stretch Amount in PPTable not supported\n",
2829 value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
2831 value
&= 0xFFC2FF87;
2832 data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].minFreq
=
2833 fiji_clock_stretcher_lookup_table
[stretch_amount2
][0];
2834 data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].maxFreq
=
2835 fiji_clock_stretcher_lookup_table
[stretch_amount2
][1];
2836 clock_freq_u16
= (uint16_t)(PP_SMC_TO_HOST_UL(data
->smc_state_table
.
2837 GraphicsLevel
[data
->smc_state_table
.GraphicsDpmLevelCount
- 1].
2838 SclkFrequency
) / 100);
2839 if (fiji_clock_stretcher_lookup_table
[stretch_amount2
][0] <
2841 fiji_clock_stretcher_lookup_table
[stretch_amount2
][1] >
2843 /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
2844 value
|= (fiji_clock_stretcher_lookup_table
[stretch_amount2
][3]) << 16;
2845 /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
2846 value
|= (fiji_clock_stretcher_lookup_table
[stretch_amount2
][2]) << 18;
2847 /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
2848 value
|= (fiji_clock_stretch_amount_conversion
2849 [fiji_clock_stretcher_lookup_table
[stretch_amount2
][3]]
2850 [stretch_amount
]) << 3;
2852 CONVERT_FROM_HOST_TO_SMC_US(data
->smc_state_table
.CKS_LOOKUPTable
.
2853 CKS_LOOKUPTableEntry
[0].minFreq
);
2854 CONVERT_FROM_HOST_TO_SMC_US(data
->smc_state_table
.CKS_LOOKUPTable
.
2855 CKS_LOOKUPTableEntry
[0].maxFreq
);
2856 data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].setting
=
2857 fiji_clock_stretcher_lookup_table
[stretch_amount2
][2] & 0x7F;
2858 data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].setting
|=
2859 (fiji_clock_stretcher_lookup_table
[stretch_amount2
][3]) << 7;
2861 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
2862 ixPWR_CKS_CNTL
, value
);
2864 /* Populate DDT Lookup Table */
2865 for (i
= 0; i
< 4; i
++) {
2866 /* Assign the minimum and maximum VID stored
2867 * in the last row of Clock Stretcher Voltage Table.
2869 data
->smc_state_table
.ClockStretcherDataTable
.
2870 ClockStretcherDataTableEntry
[i
].minVID
=
2871 (uint8_t) fiji_clock_stretcher_ddt_table
[type
][i
][2];
2872 data
->smc_state_table
.ClockStretcherDataTable
.
2873 ClockStretcherDataTableEntry
[i
].maxVID
=
2874 (uint8_t) fiji_clock_stretcher_ddt_table
[type
][i
][3];
2875 /* Loop through each SCLK and check the frequency
2876 * to see if it lies within the frequency for clock stretcher.
2878 for (j
= 0; j
< data
->smc_state_table
.GraphicsDpmLevelCount
; j
++) {
2880 clock_freq
= PP_SMC_TO_HOST_UL(
2881 data
->smc_state_table
.GraphicsLevel
[j
].SclkFrequency
);
2882 /* Check the allowed frequency against the sclk level[j].
2883 * Sclk's endianness has already been converted,
2884 * and it's in 10Khz unit,
2885 * as opposed to Data table, which is in Mhz unit.
2888 (fiji_clock_stretcher_ddt_table
[type
][i
][0]) * 100) {
2891 (fiji_clock_stretcher_ddt_table
[type
][i
][1]) * 100)
2894 data
->smc_state_table
.ClockStretcherDataTable
.
2895 ClockStretcherDataTableEntry
[i
].setting
|= cks_setting
<< (j
* 2);
2897 CONVERT_FROM_HOST_TO_SMC_US(data
->smc_state_table
.
2898 ClockStretcherDataTable
.
2899 ClockStretcherDataTableEntry
[i
].setting
);
2902 value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixPWR_CKS_CNTL
);
2903 value
&= 0xFFFFFFFE;
2904 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixPWR_CKS_CNTL
, value
);
2910 * Populates the SMC VRConfig field in DPM table.
2912 * @param hwmgr the address of the hardware manager
2913 * @param table the SMC DPM table structure to be populated
2916 static int fiji_populate_vr_config(struct pp_hwmgr
*hwmgr
,
2917 struct SMU73_Discrete_DpmTable
*table
)
2919 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2922 config
= VR_MERGED_WITH_VDDC
;
2923 table
->VRConfig
|= (config
<< VRCONF_VDDGFX_SHIFT
);
2925 /* Set Vddc Voltage Controller */
2926 if(FIJI_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
2927 config
= VR_SVI2_PLANE_1
;
2928 table
->VRConfig
|= config
;
2930 PP_ASSERT_WITH_CODE(false,
2931 "VDDC should be on SVI2 control in merged mode!",);
2933 /* Set Vddci Voltage Controller */
2934 if(FIJI_VOLTAGE_CONTROL_BY_SVID2
== data
->vddci_control
) {
2935 config
= VR_SVI2_PLANE_2
; /* only in merged mode */
2936 table
->VRConfig
|= (config
<< VRCONF_VDDCI_SHIFT
);
2937 } else if (FIJI_VOLTAGE_CONTROL_BY_GPIO
== data
->vddci_control
) {
2938 config
= VR_SMIO_PATTERN_1
;
2939 table
->VRConfig
|= (config
<< VRCONF_VDDCI_SHIFT
);
2941 config
= VR_STATIC_VOLTAGE
;
2942 table
->VRConfig
|= (config
<< VRCONF_VDDCI_SHIFT
);
2944 /* Set Mvdd Voltage Controller */
2945 if(FIJI_VOLTAGE_CONTROL_BY_SVID2
== data
->mvdd_control
) {
2946 config
= VR_SVI2_PLANE_2
;
2947 table
->VRConfig
|= (config
<< VRCONF_MVDD_SHIFT
);
2948 } else if(FIJI_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
2949 config
= VR_SMIO_PATTERN_2
;
2950 table
->VRConfig
|= (config
<< VRCONF_MVDD_SHIFT
);
2952 config
= VR_STATIC_VOLTAGE
;
2953 table
->VRConfig
|= (config
<< VRCONF_MVDD_SHIFT
);
2960 * Initializes the SMC table and uploads it
2962 * @param hwmgr the address of the powerplay hardware manager.
2963 * @param pInput the pointer to input data (PowerState)
2966 static int fiji_init_smc_table(struct pp_hwmgr
*hwmgr
)
2969 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
2970 struct phm_ppt_v1_information
*table_info
=
2971 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2972 struct SMU73_Discrete_DpmTable
*table
= &(data
->smc_state_table
);
2973 const struct fiji_ulv_parm
*ulv
= &(data
->ulv
);
2975 struct pp_atomctrl_gpio_pin_assignment gpio_pin
;
2977 result
= fiji_setup_default_dpm_tables(hwmgr
);
2978 PP_ASSERT_WITH_CODE(0 == result
,
2979 "Failed to setup default DPM tables!", return result
);
2981 if(FIJI_VOLTAGE_CONTROL_NONE
!= data
->voltage_control
)
2982 fiji_populate_smc_voltage_tables(hwmgr
, table
);
2984 table
->SystemFlags
= 0;
2986 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2987 PHM_PlatformCaps_AutomaticDCTransition
))
2988 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GPIO_DC
;
2990 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2991 PHM_PlatformCaps_StepVddc
))
2992 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_STEPVDDC
;
2994 if (data
->is_memory_gddr5
)
2995 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GDDR5
;
2997 if (ulv
->ulv_supported
&& table_info
->us_ulv_voltage_offset
) {
2998 result
= fiji_populate_ulv_state(hwmgr
, table
);
2999 PP_ASSERT_WITH_CODE(0 == result
,
3000 "Failed to initialize ULV state!", return result
);
3001 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3002 ixCG_ULV_PARAMETER
, ulv
->cg_ulv_parameter
);
3005 result
= fiji_populate_smc_link_level(hwmgr
, table
);
3006 PP_ASSERT_WITH_CODE(0 == result
,
3007 "Failed to initialize Link Level!", return result
);
3009 result
= fiji_populate_all_graphic_levels(hwmgr
);
3010 PP_ASSERT_WITH_CODE(0 == result
,
3011 "Failed to initialize Graphics Level!", return result
);
3013 result
= fiji_populate_all_memory_levels(hwmgr
);
3014 PP_ASSERT_WITH_CODE(0 == result
,
3015 "Failed to initialize Memory Level!", return result
);
3017 result
= fiji_populate_smc_acpi_level(hwmgr
, table
);
3018 PP_ASSERT_WITH_CODE(0 == result
,
3019 "Failed to initialize ACPI Level!", return result
);
3021 result
= fiji_populate_smc_vce_level(hwmgr
, table
);
3022 PP_ASSERT_WITH_CODE(0 == result
,
3023 "Failed to initialize VCE Level!", return result
);
3025 result
= fiji_populate_smc_acp_level(hwmgr
, table
);
3026 PP_ASSERT_WITH_CODE(0 == result
,
3027 "Failed to initialize ACP Level!", return result
);
3029 result
= fiji_populate_smc_samu_level(hwmgr
, table
);
3030 PP_ASSERT_WITH_CODE(0 == result
,
3031 "Failed to initialize SAMU Level!", return result
);
3033 /* Since only the initial state is completely set up at this point
3034 * (the other states are just copies of the boot state) we only
3035 * need to populate the ARB settings for the initial state.
3037 result
= fiji_program_memory_timing_parameters(hwmgr
);
3038 PP_ASSERT_WITH_CODE(0 == result
,
3039 "Failed to Write ARB settings for the initial state.", return result
);
3041 result
= fiji_populate_smc_uvd_level(hwmgr
, table
);
3042 PP_ASSERT_WITH_CODE(0 == result
,
3043 "Failed to initialize UVD Level!", return result
);
3045 result
= fiji_populate_smc_boot_level(hwmgr
, table
);
3046 PP_ASSERT_WITH_CODE(0 == result
,
3047 "Failed to initialize Boot Level!", return result
);
3049 result
= fiji_populate_smc_initailial_state(hwmgr
);
3050 PP_ASSERT_WITH_CODE(0 == result
,
3051 "Failed to initialize Boot State!", return result
);
3053 result
= fiji_populate_bapm_parameters_in_dpm_table(hwmgr
);
3054 PP_ASSERT_WITH_CODE(0 == result
,
3055 "Failed to populate BAPM Parameters!", return result
);
3057 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3058 PHM_PlatformCaps_ClockStretcher
)) {
3059 result
= fiji_populate_clock_stretcher_data_table(hwmgr
);
3060 PP_ASSERT_WITH_CODE(0 == result
,
3061 "Failed to populate Clock Stretcher Data Table!",
3065 table
->GraphicsVoltageChangeEnable
= 1;
3066 table
->GraphicsThermThrottleEnable
= 1;
3067 table
->GraphicsInterval
= 1;
3068 table
->VoltageInterval
= 1;
3069 table
->ThermalInterval
= 1;
3070 table
->TemperatureLimitHigh
=
3071 table_info
->cac_dtp_table
->usTargetOperatingTemp
*
3072 FIJI_Q88_FORMAT_CONVERSION_UNIT
;
3073 table
->TemperatureLimitLow
=
3074 (table_info
->cac_dtp_table
->usTargetOperatingTemp
- 1) *
3075 FIJI_Q88_FORMAT_CONVERSION_UNIT
;
3076 table
->MemoryVoltageChangeEnable
= 1;
3077 table
->MemoryInterval
= 1;
3078 table
->VoltageResponseTime
= 0;
3079 table
->PhaseResponseTime
= 0;
3080 table
->MemoryThermThrottleEnable
= 1;
3081 table
->PCIeBootLinkLevel
= 0; /* 0:Gen1 1:Gen2 2:Gen3*/
3082 table
->PCIeGenInterval
= 1;
3083 table
->VRConfig
= 0;
3085 result
= fiji_populate_vr_config(hwmgr
, table
);
3086 PP_ASSERT_WITH_CODE(0 == result
,
3087 "Failed to populate VRConfig setting!", return result
);
3089 table
->ThermGpio
= 17;
3090 table
->SclkStepSize
= 0x4000;
3092 if (atomctrl_get_pp_assign_pin(hwmgr
, VDDC_VRHOT_GPIO_PINID
, &gpio_pin
)) {
3093 table
->VRHotGpio
= gpio_pin
.uc_gpio_pin_bit_shift
;
3094 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3095 PHM_PlatformCaps_RegulatorHot
);
3097 table
->VRHotGpio
= FIJI_UNUSED_GPIO_PIN
;
3098 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3099 PHM_PlatformCaps_RegulatorHot
);
3102 if (atomctrl_get_pp_assign_pin(hwmgr
, PP_AC_DC_SWITCH_GPIO_PINID
,
3104 table
->AcDcGpio
= gpio_pin
.uc_gpio_pin_bit_shift
;
3105 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3106 PHM_PlatformCaps_AutomaticDCTransition
);
3108 table
->AcDcGpio
= FIJI_UNUSED_GPIO_PIN
;
3109 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3110 PHM_PlatformCaps_AutomaticDCTransition
);
3113 /* Thermal Output GPIO */
3114 if (atomctrl_get_pp_assign_pin(hwmgr
, THERMAL_INT_OUTPUT_GPIO_PINID
,
3116 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
3117 PHM_PlatformCaps_ThermalOutGPIO
);
3119 table
->ThermOutGpio
= gpio_pin
.uc_gpio_pin_bit_shift
;
3121 /* For porlarity read GPIOPAD_A with assigned Gpio pin
3122 * since VBIOS will program this register to set 'inactive state',
3123 * driver can then determine 'active state' from this and
3124 * program SMU with correct polarity
3126 table
->ThermOutPolarity
= (0 == (cgs_read_register(hwmgr
->device
, mmGPIOPAD_A
) &
3127 (1 << gpio_pin
.uc_gpio_pin_bit_shift
))) ? 1:0;
3128 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_ONLY
;
3130 /* if required, combine VRHot/PCC with thermal out GPIO */
3131 if(phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3132 PHM_PlatformCaps_RegulatorHot
) &&
3133 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3134 PHM_PlatformCaps_CombinePCCWithThermalSignal
))
3135 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_VRHOT
;
3137 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
3138 PHM_PlatformCaps_ThermalOutGPIO
);
3139 table
->ThermOutGpio
= 17;
3140 table
->ThermOutPolarity
= 1;
3141 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_DISABLE
;
3144 for (i
= 0; i
< SMU73_MAX_ENTRIES_SMIO
; i
++)
3145 table
->Smio
[i
] = PP_HOST_TO_SMC_UL(table
->Smio
[i
]);
3147 CONVERT_FROM_HOST_TO_SMC_UL(table
->SystemFlags
);
3148 CONVERT_FROM_HOST_TO_SMC_UL(table
->VRConfig
);
3149 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask1
);
3150 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask2
);
3151 CONVERT_FROM_HOST_TO_SMC_UL(table
->SclkStepSize
);
3152 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitHigh
);
3153 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitLow
);
3154 CONVERT_FROM_HOST_TO_SMC_US(table
->VoltageResponseTime
);
3155 CONVERT_FROM_HOST_TO_SMC_US(table
->PhaseResponseTime
);
3157 /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
3158 result
= fiji_copy_bytes_to_smc(hwmgr
->smumgr
,
3159 data
->dpm_table_start
+
3160 offsetof(SMU73_Discrete_DpmTable
, SystemFlags
),
3161 (uint8_t *)&(table
->SystemFlags
),
3162 sizeof(SMU73_Discrete_DpmTable
) - 3 * sizeof(SMU73_PIDController
),
3164 PP_ASSERT_WITH_CODE(0 == result
,
3165 "Failed to upload dpm data to SMC memory!", return result
);
3171 * Initialize the ARB DRAM timing table's index field.
3173 * @param hwmgr the address of the powerplay hardware manager.
3176 static int fiji_init_arb_table_index(struct pp_hwmgr
*hwmgr
)
3178 const struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3182 /* This is a read-modify-write on the first byte of the ARB table.
3183 * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure
3184 * is the field 'current'.
3185 * This solution is ugly, but we never write the whole table only
3186 * individual fields in it.
3187 * In reality this field should not be in that structure
3188 * but in a soft register.
3190 result
= fiji_read_smc_sram_dword(hwmgr
->smumgr
,
3191 data
->arb_table_start
, &tmp
, data
->sram_end
);
3197 tmp
|= ((uint32_t)MC_CG_ARB_FREQ_F1
) << 24;
3199 return fiji_write_smc_sram_dword(hwmgr
->smumgr
,
3200 data
->arb_table_start
, tmp
, data
->sram_end
);
3203 static int fiji_enable_vrhot_gpio_interrupt(struct pp_hwmgr
*hwmgr
)
3205 if(phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3206 PHM_PlatformCaps_RegulatorHot
))
3207 return smum_send_msg_to_smc(hwmgr
->smumgr
,
3208 PPSMC_MSG_EnableVRHotGPIOInterrupt
);
3213 static int fiji_enable_sclk_control(struct pp_hwmgr
*hwmgr
)
3215 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
,
3216 SCLK_PWRMGT_OFF
, 0);
3220 static int fiji_enable_ulv(struct pp_hwmgr
*hwmgr
)
3222 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3223 struct fiji_ulv_parm
*ulv
= &(data
->ulv
);
3225 if (ulv
->ulv_supported
)
3226 return smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_EnableULV
);
3231 static int fiji_disable_ulv(struct pp_hwmgr
*hwmgr
)
3233 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3234 struct fiji_ulv_parm
*ulv
= &(data
->ulv
);
3236 if (ulv
->ulv_supported
)
3237 return smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_DisableULV
);
3242 static int fiji_enable_deep_sleep_master_switch(struct pp_hwmgr
*hwmgr
)
3244 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3245 PHM_PlatformCaps_SclkDeepSleep
)) {
3246 if (smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_MASTER_DeepSleep_ON
))
3247 PP_ASSERT_WITH_CODE(false,
3248 "Attempt to enable Master Deep Sleep switch failed!",
3251 if (smum_send_msg_to_smc(hwmgr
->smumgr
,
3252 PPSMC_MSG_MASTER_DeepSleep_OFF
)) {
3253 PP_ASSERT_WITH_CODE(false,
3254 "Attempt to disable Master Deep Sleep switch failed!",
3262 static int fiji_disable_deep_sleep_master_switch(struct pp_hwmgr
*hwmgr
)
3264 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3265 PHM_PlatformCaps_SclkDeepSleep
)) {
3266 if (smum_send_msg_to_smc(hwmgr
->smumgr
,
3267 PPSMC_MSG_MASTER_DeepSleep_OFF
)) {
3268 PP_ASSERT_WITH_CODE(false,
3269 "Attempt to disable Master Deep Sleep switch failed!",
3277 static int fiji_enable_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
3279 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3280 uint32_t val
, val0
, val2
;
3281 uint32_t i
, cpl_cntl
, cpl_threshold
, mc_threshold
;
3283 /* enable SCLK dpm */
3284 if(!data
->sclk_dpm_key_disabled
)
3285 PP_ASSERT_WITH_CODE(
3286 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_DPM_Enable
)),
3287 "Failed to enable SCLK DPM during DPM Start Function!",
3290 /* enable MCLK dpm */
3291 if(0 == data
->mclk_dpm_key_disabled
) {
3295 /* Read per MCD tile (0 - 7) */
3296 for (i
= 0; i
< 8; i
++) {
3297 PHM_WRITE_FIELD(hwmgr
->device
, MC_CONFIG_MCD
, MC_RD_ENABLE
, i
);
3298 val
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_RESERVE_0_S
) & 0xf0000000;
3299 if (0xf0000000 != val
) {
3300 /* count number of MCQ that has channel(s) enabled */
3302 /* only harvest 3 or full 4 supported */
3303 mc_threshold
= val
? 3 : 4;
3306 PP_ASSERT_WITH_CODE(0 != cpl_threshold
,
3307 "Number of MCQ is zero!", return -EINVAL
;);
3309 mc_threshold
= ((mc_threshold
& LCAC_MC0_CNTL__MC0_THRESHOLD_MASK
) <<
3310 LCAC_MC0_CNTL__MC0_THRESHOLD__SHIFT
) |
3311 LCAC_MC0_CNTL__MC0_ENABLE_MASK
;
3312 cpl_cntl
= ((cpl_threshold
& LCAC_CPL_CNTL__CPL_THRESHOLD_MASK
) <<
3313 LCAC_CPL_CNTL__CPL_THRESHOLD__SHIFT
) |
3314 LCAC_CPL_CNTL__CPL_ENABLE_MASK
;
3315 cpl_cntl
= (cpl_cntl
| (8 << LCAC_CPL_CNTL__CPL_BLOCK_ID__SHIFT
));
3316 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3317 ixLCAC_MC0_CNTL
, mc_threshold
);
3318 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3319 ixLCAC_MC1_CNTL
, mc_threshold
);
3320 if (8 == cpl_threshold
) {
3321 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3322 ixLCAC_MC2_CNTL
, mc_threshold
);
3323 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3324 ixLCAC_MC3_CNTL
, mc_threshold
);
3325 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3326 ixLCAC_MC4_CNTL
, mc_threshold
);
3327 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3328 ixLCAC_MC5_CNTL
, mc_threshold
);
3329 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3330 ixLCAC_MC6_CNTL
, mc_threshold
);
3331 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3332 ixLCAC_MC7_CNTL
, mc_threshold
);
3334 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3335 ixLCAC_CPL_CNTL
, cpl_cntl
);
3339 mc_threshold
= mc_threshold
|
3340 (1 << LCAC_MC0_CNTL__MC0_SIGNAL_ID__SHIFT
);
3341 cpl_cntl
= cpl_cntl
| (1 << LCAC_CPL_CNTL__CPL_SIGNAL_ID__SHIFT
);
3342 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3343 ixLCAC_MC0_CNTL
, mc_threshold
);
3344 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3345 ixLCAC_MC1_CNTL
, mc_threshold
);
3346 if (8 == cpl_threshold
) {
3347 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3348 ixLCAC_MC2_CNTL
, mc_threshold
);
3349 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3350 ixLCAC_MC3_CNTL
, mc_threshold
);
3351 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3352 ixLCAC_MC4_CNTL
, mc_threshold
);
3353 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3354 ixLCAC_MC5_CNTL
, mc_threshold
);
3355 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3356 ixLCAC_MC6_CNTL
, mc_threshold
);
3357 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3358 ixLCAC_MC7_CNTL
, mc_threshold
);
3360 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3361 ixLCAC_CPL_CNTL
, cpl_cntl
);
3363 /* Program CAC_EN per MCD (0-7) Tile */
3364 val0
= val
= cgs_read_register(hwmgr
->device
, mmMC_CONFIG_MCD
);
3365 val
&= ~(MC_CONFIG_MCD__MCD0_WR_ENABLE_MASK
|
3366 MC_CONFIG_MCD__MCD1_WR_ENABLE_MASK
|
3367 MC_CONFIG_MCD__MCD2_WR_ENABLE_MASK
|
3368 MC_CONFIG_MCD__MCD3_WR_ENABLE_MASK
|
3369 MC_CONFIG_MCD__MCD4_WR_ENABLE_MASK
|
3370 MC_CONFIG_MCD__MCD5_WR_ENABLE_MASK
|
3371 MC_CONFIG_MCD__MCD6_WR_ENABLE_MASK
|
3372 MC_CONFIG_MCD__MCD7_WR_ENABLE_MASK
|
3373 MC_CONFIG_MCD__MC_RD_ENABLE_MASK
);
3375 for (i
= 0; i
< 8; i
++) {
3376 /* Enable MCD i Tile read & write */
3377 val2
= (val
| (i
<< MC_CONFIG_MCD__MC_RD_ENABLE__SHIFT
) |
3379 cgs_write_register(hwmgr
->device
, mmMC_CONFIG_MCD
, val2
);
3380 /* Enbale CAC_ON MCD i Tile */
3381 val2
= cgs_read_register(hwmgr
->device
, mmMC_SEQ_CNTL
);
3382 val2
|= MC_SEQ_CNTL__CAC_EN_MASK
;
3383 cgs_write_register(hwmgr
->device
, mmMC_SEQ_CNTL
, val2
);
3385 /* Set MC_CONFIG_MCD back to its default setting val0 */
3386 cgs_write_register(hwmgr
->device
, mmMC_CONFIG_MCD
, val0
);
3388 PP_ASSERT_WITH_CODE(
3389 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
3390 PPSMC_MSG_MCLKDPM_Enable
)),
3391 "Failed to enable MCLK DPM during DPM Start Function!",
3397 static int fiji_start_dpm(struct pp_hwmgr
*hwmgr
)
3399 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3401 /*enable general power management */
3402 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
,
3403 GLOBAL_PWRMGT_EN
, 1);
3404 /* enable sclk deep sleep */
3405 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
,
3407 /* prepare for PCIE DPM */
3408 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
3409 data
->soft_regs_start
+ offsetof(SMU73_SoftRegisters
,
3410 VoltageChangeTimeout
), 0x1000);
3411 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__PCIE
,
3412 SWRST_COMMAND_1
, RESETLC
, 0x0);
3414 PP_ASSERT_WITH_CODE(
3415 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
3416 PPSMC_MSG_Voltage_Cntl_Enable
)),
3417 "Failed to enable voltage DPM during DPM Start Function!",
3420 if (fiji_enable_sclk_mclk_dpm(hwmgr
)) {
3421 printk(KERN_ERR
"Failed to enable Sclk DPM and Mclk DPM!");
3425 /* enable PCIE dpm */
3426 if(!data
->pcie_dpm_key_disabled
) {
3427 PP_ASSERT_WITH_CODE(
3428 (0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
3429 PPSMC_MSG_PCIeDPM_Enable
)),
3430 "Failed to enable pcie DPM during DPM Start Function!",
3437 static int fiji_disable_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
3439 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3441 /* disable SCLK dpm */
3442 if (!data
->sclk_dpm_key_disabled
)
3443 PP_ASSERT_WITH_CODE(
3444 (smum_send_msg_to_smc(hwmgr
->smumgr
,
3445 PPSMC_MSG_DPM_Disable
) == 0),
3446 "Failed to disable SCLK DPM!",
3449 /* disable MCLK dpm */
3450 if (!data
->mclk_dpm_key_disabled
) {
3451 PP_ASSERT_WITH_CODE(
3452 (smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3453 PPSMC_MSG_MCLKDPM_SetEnabledMask
, 1) == 0),
3454 "Failed to force MCLK DPM0!",
3457 PP_ASSERT_WITH_CODE(
3458 (smum_send_msg_to_smc(hwmgr
->smumgr
,
3459 PPSMC_MSG_MCLKDPM_Disable
) == 0),
3460 "Failed to disable MCLK DPM!",
3467 static int fiji_stop_dpm(struct pp_hwmgr
*hwmgr
)
3469 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3471 /* disable general power management */
3472 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
,
3473 GLOBAL_PWRMGT_EN
, 0);
3474 /* disable sclk deep sleep */
3475 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, SCLK_PWRMGT_CNTL
,
3478 /* disable PCIE dpm */
3479 if (!data
->pcie_dpm_key_disabled
) {
3480 PP_ASSERT_WITH_CODE(
3481 (smum_send_msg_to_smc(hwmgr
->smumgr
,
3482 PPSMC_MSG_PCIeDPM_Disable
) == 0),
3483 "Failed to disable pcie DPM during DPM Stop Function!",
3487 if (fiji_disable_sclk_mclk_dpm(hwmgr
)) {
3488 printk(KERN_ERR
"Failed to disable Sclk DPM and Mclk DPM!");
3492 PP_ASSERT_WITH_CODE(
3493 (smum_send_msg_to_smc(hwmgr
->smumgr
,
3494 PPSMC_MSG_Voltage_Cntl_Disable
) == 0),
3495 "Failed to disable voltage DPM during DPM Stop Function!",
3501 static void fiji_set_dpm_event_sources(struct pp_hwmgr
*hwmgr
,
3505 enum DPM_EVENT_SRC src
;
3509 printk(KERN_ERR
"Unknown throttling event sources.");
3515 case (1 << PHM_AutoThrottleSource_Thermal
):
3517 src
= DPM_EVENT_SRC_DIGITAL
;
3519 case (1 << PHM_AutoThrottleSource_External
):
3521 src
= DPM_EVENT_SRC_EXTERNAL
;
3523 case (1 << PHM_AutoThrottleSource_External
) |
3524 (1 << PHM_AutoThrottleSource_Thermal
):
3526 src
= DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL
;
3529 /* Order matters - don't enable thermal protection for the wrong source. */
3531 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, CG_THERMAL_CTRL
,
3532 DPM_EVENT_SRC
, src
);
3533 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
,
3534 THERMAL_PROTECTION_DIS
,
3535 !phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3536 PHM_PlatformCaps_ThermalController
));
3538 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, GENERAL_PWRMGT
,
3539 THERMAL_PROTECTION_DIS
, 1);
3542 static int fiji_enable_auto_throttle_source(struct pp_hwmgr
*hwmgr
,
3543 PHM_AutoThrottleSource source
)
3545 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3547 if (!(data
->active_auto_throttle_sources
& (1 << source
))) {
3548 data
->active_auto_throttle_sources
|= 1 << source
;
3549 fiji_set_dpm_event_sources(hwmgr
, data
->active_auto_throttle_sources
);
3554 static int fiji_enable_thermal_auto_throttle(struct pp_hwmgr
*hwmgr
)
3556 return fiji_enable_auto_throttle_source(hwmgr
, PHM_AutoThrottleSource_Thermal
);
3559 static int fiji_disable_auto_throttle_source(struct pp_hwmgr
*hwmgr
,
3560 PHM_AutoThrottleSource source
)
3562 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3564 if (data
->active_auto_throttle_sources
& (1 << source
)) {
3565 data
->active_auto_throttle_sources
&= ~(1 << source
);
3566 fiji_set_dpm_event_sources(hwmgr
, data
->active_auto_throttle_sources
);
3571 static int fiji_disable_thermal_auto_throttle(struct pp_hwmgr
*hwmgr
)
3573 return fiji_disable_auto_throttle_source(hwmgr
, PHM_AutoThrottleSource_Thermal
);
3576 static int fiji_enable_dpm_tasks(struct pp_hwmgr
*hwmgr
)
3578 int tmp_result
, result
= 0;
3580 tmp_result
= (!fiji_is_dpm_running(hwmgr
))? 0 : -1;
3581 PP_ASSERT_WITH_CODE(result
== 0,
3582 "DPM is already running right now, no need to enable DPM!",
3585 if (fiji_voltage_control(hwmgr
)) {
3586 tmp_result
= fiji_enable_voltage_control(hwmgr
);
3587 PP_ASSERT_WITH_CODE(tmp_result
== 0,
3588 "Failed to enable voltage control!",
3589 result
= tmp_result
);
3592 if (fiji_voltage_control(hwmgr
)) {
3593 tmp_result
= fiji_construct_voltage_tables(hwmgr
);
3594 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3595 "Failed to contruct voltage tables!",
3596 result
= tmp_result
);
3599 tmp_result
= fiji_initialize_mc_reg_table(hwmgr
);
3600 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3601 "Failed to initialize MC reg table!", result
= tmp_result
);
3603 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3604 PHM_PlatformCaps_EngineSpreadSpectrumSupport
))
3605 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3606 GENERAL_PWRMGT
, DYN_SPREAD_SPECTRUM_EN
, 1);
3608 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3609 PHM_PlatformCaps_ThermalController
))
3610 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3611 GENERAL_PWRMGT
, THERMAL_PROTECTION_DIS
, 0);
3613 tmp_result
= fiji_program_static_screen_threshold_parameters(hwmgr
);
3614 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3615 "Failed to program static screen threshold parameters!",
3616 result
= tmp_result
);
3618 tmp_result
= fiji_enable_display_gap(hwmgr
);
3619 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3620 "Failed to enable display gap!", result
= tmp_result
);
3622 tmp_result
= fiji_program_voting_clients(hwmgr
);
3623 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3624 "Failed to program voting clients!", result
= tmp_result
);
3626 tmp_result
= fiji_process_firmware_header(hwmgr
);
3627 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3628 "Failed to process firmware header!", result
= tmp_result
);
3630 tmp_result
= fiji_initial_switch_from_arbf0_to_f1(hwmgr
);
3631 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3632 "Failed to initialize switch from ArbF0 to F1!",
3633 result
= tmp_result
);
3635 tmp_result
= fiji_init_smc_table(hwmgr
);
3636 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3637 "Failed to initialize SMC table!", result
= tmp_result
);
3639 tmp_result
= fiji_init_arb_table_index(hwmgr
);
3640 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3641 "Failed to initialize ARB table index!", result
= tmp_result
);
3643 tmp_result
= fiji_populate_pm_fuses(hwmgr
);
3644 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3645 "Failed to populate PM fuses!", result
= tmp_result
);
3647 tmp_result
= fiji_enable_vrhot_gpio_interrupt(hwmgr
);
3648 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3649 "Failed to enable VR hot GPIO interrupt!", result
= tmp_result
);
3651 tmp_result
= tonga_notify_smc_display_change(hwmgr
, false);
3652 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3653 "Failed to notify no display!", result
= tmp_result
);
3655 tmp_result
= fiji_enable_sclk_control(hwmgr
);
3656 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3657 "Failed to enable SCLK control!", result
= tmp_result
);
3659 tmp_result
= fiji_enable_ulv(hwmgr
);
3660 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3661 "Failed to enable ULV!", result
= tmp_result
);
3663 tmp_result
= fiji_enable_deep_sleep_master_switch(hwmgr
);
3664 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3665 "Failed to enable deep sleep master switch!", result
= tmp_result
);
3667 tmp_result
= fiji_start_dpm(hwmgr
);
3668 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3669 "Failed to start DPM!", result
= tmp_result
);
3671 tmp_result
= fiji_enable_smc_cac(hwmgr
);
3672 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3673 "Failed to enable SMC CAC!", result
= tmp_result
);
3675 tmp_result
= fiji_enable_power_containment(hwmgr
);
3676 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3677 "Failed to enable power containment!", result
= tmp_result
);
3679 tmp_result
= fiji_power_control_set_level(hwmgr
);
3680 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3681 "Failed to power control set level!", result
= tmp_result
);
3683 tmp_result
= fiji_enable_thermal_auto_throttle(hwmgr
);
3684 PP_ASSERT_WITH_CODE((0 == tmp_result
),
3685 "Failed to enable thermal auto throttle!", result
= tmp_result
);
3690 static int fiji_disable_dpm_tasks(struct pp_hwmgr
*hwmgr
)
3692 int tmp_result
, result
= 0;
3694 tmp_result
= (fiji_is_dpm_running(hwmgr
)) ? 0 : -1;
3695 PP_ASSERT_WITH_CODE(tmp_result
== 0,
3696 "DPM is not running right now, no need to disable DPM!",
3699 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
3700 PHM_PlatformCaps_ThermalController
))
3701 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3702 GENERAL_PWRMGT
, THERMAL_PROTECTION_DIS
, 1);
3704 tmp_result
= fiji_disable_power_containment(hwmgr
);
3705 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3706 "Failed to disable power containment!", result
= tmp_result
);
3708 tmp_result
= fiji_disable_smc_cac(hwmgr
);
3709 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3710 "Failed to disable SMC CAC!", result
= tmp_result
);
3712 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3713 CG_SPLL_SPREAD_SPECTRUM
, SSEN
, 0);
3714 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
3715 GENERAL_PWRMGT
, DYN_SPREAD_SPECTRUM_EN
, 0);
3717 tmp_result
= fiji_disable_thermal_auto_throttle(hwmgr
);
3718 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3719 "Failed to disable thermal auto throttle!", result
= tmp_result
);
3721 tmp_result
= fiji_stop_dpm(hwmgr
);
3722 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3723 "Failed to stop DPM!", result
= tmp_result
);
3725 tmp_result
= fiji_disable_deep_sleep_master_switch(hwmgr
);
3726 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3727 "Failed to disable deep sleep master switch!", result
= tmp_result
);
3729 tmp_result
= fiji_disable_ulv(hwmgr
);
3730 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3731 "Failed to disable ULV!", result
= tmp_result
);
3733 tmp_result
= fiji_clear_voting_clients(hwmgr
);
3734 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3735 "Failed to clear voting clients!", result
= tmp_result
);
3737 tmp_result
= fiji_reset_to_default(hwmgr
);
3738 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3739 "Failed to reset to default!", result
= tmp_result
);
3741 tmp_result
= fiji_force_switch_to_arbf0(hwmgr
);
3742 PP_ASSERT_WITH_CODE((tmp_result
== 0),
3743 "Failed to force to switch arbf0!", result
= tmp_result
);
3748 static int fiji_force_dpm_highest(struct pp_hwmgr
*hwmgr
)
3750 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3751 uint32_t level
, tmp
;
3753 if (!data
->sclk_dpm_key_disabled
) {
3754 if (data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
3756 tmp
= data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
;
3760 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3761 PPSMC_MSG_SCLKDPM_SetEnabledMask
,
3766 if (!data
->mclk_dpm_key_disabled
) {
3767 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
) {
3769 tmp
= data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
;
3773 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3774 PPSMC_MSG_MCLKDPM_SetEnabledMask
,
3779 if (!data
->pcie_dpm_key_disabled
) {
3780 if (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
) {
3782 tmp
= data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
;
3786 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3787 PPSMC_MSG_PCIeDPM_ForceLevel
,
3794 static int fiji_upload_dpmlevel_enable_mask(struct pp_hwmgr
*hwmgr
)
3796 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3798 phm_apply_dal_min_voltage_request(hwmgr
);
3800 if (!data
->sclk_dpm_key_disabled
) {
3801 if (data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
)
3802 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3803 PPSMC_MSG_SCLKDPM_SetEnabledMask
,
3804 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
3809 static int fiji_unforce_dpm_levels(struct pp_hwmgr
*hwmgr
)
3811 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3813 if (!fiji_is_dpm_running(hwmgr
))
3816 if (!data
->pcie_dpm_key_disabled
) {
3817 smum_send_msg_to_smc(hwmgr
->smumgr
,
3818 PPSMC_MSG_PCIeDPM_UnForceLevel
);
3821 return fiji_upload_dpmlevel_enable_mask(hwmgr
);
3824 static uint32_t fiji_get_lowest_enabled_level(
3825 struct pp_hwmgr
*hwmgr
, uint32_t mask
)
3829 while(0 == (mask
& (1 << level
)))
3835 static int fiji_force_dpm_lowest(struct pp_hwmgr
*hwmgr
)
3837 struct fiji_hwmgr
*data
=
3838 (struct fiji_hwmgr
*)(hwmgr
->backend
);
3841 if (!data
->sclk_dpm_key_disabled
)
3842 if (data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
3843 level
= fiji_get_lowest_enabled_level(hwmgr
,
3844 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
3845 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3846 PPSMC_MSG_SCLKDPM_SetEnabledMask
,
3851 if (!data
->mclk_dpm_key_disabled
) {
3852 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
) {
3853 level
= fiji_get_lowest_enabled_level(hwmgr
,
3854 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
);
3855 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3856 PPSMC_MSG_MCLKDPM_SetEnabledMask
,
3861 if (!data
->pcie_dpm_key_disabled
) {
3862 if (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
) {
3863 level
= fiji_get_lowest_enabled_level(hwmgr
,
3864 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
);
3865 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
3866 PPSMC_MSG_PCIeDPM_ForceLevel
,
3874 static int fiji_dpm_force_dpm_level(struct pp_hwmgr
*hwmgr
,
3875 enum amd_dpm_forced_level level
)
3880 case AMD_DPM_FORCED_LEVEL_HIGH
:
3881 ret
= fiji_force_dpm_highest(hwmgr
);
3885 case AMD_DPM_FORCED_LEVEL_LOW
:
3886 ret
= fiji_force_dpm_lowest(hwmgr
);
3890 case AMD_DPM_FORCED_LEVEL_AUTO
:
3891 ret
= fiji_unforce_dpm_levels(hwmgr
);
3899 hwmgr
->dpm_level
= level
;
3904 static int fiji_get_power_state_size(struct pp_hwmgr
*hwmgr
)
3906 return sizeof(struct fiji_power_state
);
3909 static int fiji_get_pp_table_entry_callback_func(struct pp_hwmgr
*hwmgr
,
3910 void *state
, struct pp_power_state
*power_state
,
3911 void *pp_table
, uint32_t classification_flag
)
3913 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
3914 struct fiji_power_state
*fiji_power_state
=
3915 (struct fiji_power_state
*)(&(power_state
->hardware
));
3916 struct fiji_performance_level
*performance_level
;
3917 ATOM_Tonga_State
*state_entry
= (ATOM_Tonga_State
*)state
;
3918 ATOM_Tonga_POWERPLAYTABLE
*powerplay_table
=
3919 (ATOM_Tonga_POWERPLAYTABLE
*)pp_table
;
3920 ATOM_Tonga_SCLK_Dependency_Table
*sclk_dep_table
=
3921 (ATOM_Tonga_SCLK_Dependency_Table
*)
3922 (((unsigned long)powerplay_table
) +
3923 le16_to_cpu(powerplay_table
->usSclkDependencyTableOffset
));
3924 ATOM_Tonga_MCLK_Dependency_Table
*mclk_dep_table
=
3925 (ATOM_Tonga_MCLK_Dependency_Table
*)
3926 (((unsigned long)powerplay_table
) +
3927 le16_to_cpu(powerplay_table
->usMclkDependencyTableOffset
));
3929 /* The following fields are not initialized here: id orderedList allStatesList */
3930 power_state
->classification
.ui_label
=
3931 (le16_to_cpu(state_entry
->usClassification
) &
3932 ATOM_PPLIB_CLASSIFICATION_UI_MASK
) >>
3933 ATOM_PPLIB_CLASSIFICATION_UI_SHIFT
;
3934 power_state
->classification
.flags
= classification_flag
;
3935 /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
3937 power_state
->classification
.temporary_state
= false;
3938 power_state
->classification
.to_be_deleted
= false;
3940 power_state
->validation
.disallowOnDC
=
3941 (0 != (le32_to_cpu(state_entry
->ulCapsAndSettings
) &
3942 ATOM_Tonga_DISALLOW_ON_DC
));
3944 power_state
->pcie
.lanes
= 0;
3946 power_state
->display
.disableFrameModulation
= false;
3947 power_state
->display
.limitRefreshrate
= false;
3948 power_state
->display
.enableVariBright
=
3949 (0 != (le32_to_cpu(state_entry
->ulCapsAndSettings
) &
3950 ATOM_Tonga_ENABLE_VARIBRIGHT
));
3952 power_state
->validation
.supportedPowerLevels
= 0;
3953 power_state
->uvd_clocks
.VCLK
= 0;
3954 power_state
->uvd_clocks
.DCLK
= 0;
3955 power_state
->temperatures
.min
= 0;
3956 power_state
->temperatures
.max
= 0;
3958 performance_level
= &(fiji_power_state
->performance_levels
3959 [fiji_power_state
->performance_level_count
++]);
3961 PP_ASSERT_WITH_CODE(
3962 (fiji_power_state
->performance_level_count
< SMU73_MAX_LEVELS_GRAPHICS
),
3963 "Performance levels exceeds SMC limit!",
3966 PP_ASSERT_WITH_CODE(
3967 (fiji_power_state
->performance_level_count
<=
3968 hwmgr
->platform_descriptor
.hardwareActivityPerformanceLevels
),
3969 "Performance levels exceeds Driver limit!",
3972 /* Performance levels are arranged from low to high. */
3973 performance_level
->memory_clock
= mclk_dep_table
->entries
3974 [state_entry
->ucMemoryClockIndexLow
].ulMclk
;
3975 performance_level
->engine_clock
= sclk_dep_table
->entries
3976 [state_entry
->ucEngineClockIndexLow
].ulSclk
;
3977 performance_level
->pcie_gen
= get_pcie_gen_support(data
->pcie_gen_cap
,
3978 state_entry
->ucPCIEGenLow
);
3979 performance_level
->pcie_lane
= get_pcie_lane_support(data
->pcie_lane_cap
,
3980 state_entry
->ucPCIELaneHigh
);
3982 performance_level
= &(fiji_power_state
->performance_levels
3983 [fiji_power_state
->performance_level_count
++]);
3984 performance_level
->memory_clock
= mclk_dep_table
->entries
3985 [state_entry
->ucMemoryClockIndexHigh
].ulMclk
;
3986 performance_level
->engine_clock
= sclk_dep_table
->entries
3987 [state_entry
->ucEngineClockIndexHigh
].ulSclk
;
3988 performance_level
->pcie_gen
= get_pcie_gen_support(data
->pcie_gen_cap
,
3989 state_entry
->ucPCIEGenHigh
);
3990 performance_level
->pcie_lane
= get_pcie_lane_support(data
->pcie_lane_cap
,
3991 state_entry
->ucPCIELaneHigh
);
3996 static int fiji_get_pp_table_entry(struct pp_hwmgr
*hwmgr
,
3997 unsigned long entry_index
, struct pp_power_state
*state
)
4000 struct fiji_power_state
*ps
;
4001 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4002 struct phm_ppt_v1_information
*table_info
=
4003 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4004 struct phm_ppt_v1_clock_voltage_dependency_table
*dep_mclk_table
=
4005 table_info
->vdd_dep_on_mclk
;
4007 state
->hardware
.magic
= PHM_VIslands_Magic
;
4009 ps
= (struct fiji_power_state
*)(&state
->hardware
);
4011 result
= tonga_get_powerplay_table_entry(hwmgr
, entry_index
, state
,
4012 fiji_get_pp_table_entry_callback_func
);
4014 /* This is the earliest time we have all the dependency table and the VBIOS boot state
4015 * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
4016 * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
4018 if (dep_mclk_table
!= NULL
&& dep_mclk_table
->count
== 1) {
4019 if (dep_mclk_table
->entries
[0].clk
!=
4020 data
->vbios_boot_state
.mclk_bootup_value
)
4021 printk(KERN_ERR
"Single MCLK entry VDDCI/MCLK dependency table "
4022 "does not match VBIOS boot MCLK level");
4023 if (dep_mclk_table
->entries
[0].vddci
!=
4024 data
->vbios_boot_state
.vddci_bootup_value
)
4025 printk(KERN_ERR
"Single VDDCI entry VDDCI/MCLK dependency table "
4026 "does not match VBIOS boot VDDCI level");
4029 /* set DC compatible flag if this state supports DC */
4030 if (!state
->validation
.disallowOnDC
)
4031 ps
->dc_compatible
= true;
4033 if (state
->classification
.flags
& PP_StateClassificationFlag_ACPI
)
4034 data
->acpi_pcie_gen
= ps
->performance_levels
[0].pcie_gen
;
4036 ps
->uvd_clks
.vclk
= state
->uvd_clocks
.VCLK
;
4037 ps
->uvd_clks
.dclk
= state
->uvd_clocks
.DCLK
;
4042 switch (state
->classification
.ui_label
) {
4043 case PP_StateUILabel_Performance
:
4044 data
->use_pcie_performance_levels
= true;
4046 for (i
= 0; i
< ps
->performance_level_count
; i
++) {
4047 if (data
->pcie_gen_performance
.max
<
4048 ps
->performance_levels
[i
].pcie_gen
)
4049 data
->pcie_gen_performance
.max
=
4050 ps
->performance_levels
[i
].pcie_gen
;
4052 if (data
->pcie_gen_performance
.min
>
4053 ps
->performance_levels
[i
].pcie_gen
)
4054 data
->pcie_gen_performance
.min
=
4055 ps
->performance_levels
[i
].pcie_gen
;
4057 if (data
->pcie_lane_performance
.max
<
4058 ps
->performance_levels
[i
].pcie_lane
)
4059 data
->pcie_lane_performance
.max
=
4060 ps
->performance_levels
[i
].pcie_lane
;
4062 if (data
->pcie_lane_performance
.min
>
4063 ps
->performance_levels
[i
].pcie_lane
)
4064 data
->pcie_lane_performance
.min
=
4065 ps
->performance_levels
[i
].pcie_lane
;
4068 case PP_StateUILabel_Battery
:
4069 data
->use_pcie_power_saving_levels
= true;
4071 for (i
= 0; i
< ps
->performance_level_count
; i
++) {
4072 if (data
->pcie_gen_power_saving
.max
<
4073 ps
->performance_levels
[i
].pcie_gen
)
4074 data
->pcie_gen_power_saving
.max
=
4075 ps
->performance_levels
[i
].pcie_gen
;
4077 if (data
->pcie_gen_power_saving
.min
>
4078 ps
->performance_levels
[i
].pcie_gen
)
4079 data
->pcie_gen_power_saving
.min
=
4080 ps
->performance_levels
[i
].pcie_gen
;
4082 if (data
->pcie_lane_power_saving
.max
<
4083 ps
->performance_levels
[i
].pcie_lane
)
4084 data
->pcie_lane_power_saving
.max
=
4085 ps
->performance_levels
[i
].pcie_lane
;
4087 if (data
->pcie_lane_power_saving
.min
>
4088 ps
->performance_levels
[i
].pcie_lane
)
4089 data
->pcie_lane_power_saving
.min
=
4090 ps
->performance_levels
[i
].pcie_lane
;
4100 static int fiji_apply_state_adjust_rules(struct pp_hwmgr
*hwmgr
,
4101 struct pp_power_state
*request_ps
,
4102 const struct pp_power_state
*current_ps
)
4104 struct fiji_power_state
*fiji_ps
=
4105 cast_phw_fiji_power_state(&request_ps
->hardware
);
4108 struct PP_Clocks minimum_clocks
= {0};
4109 bool disable_mclk_switching
;
4110 bool disable_mclk_switching_for_frame_lock
;
4111 struct cgs_display_info info
= {0};
4112 const struct phm_clock_and_voltage_limits
*max_limits
;
4114 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4115 struct phm_ppt_v1_information
*table_info
=
4116 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4118 int32_t stable_pstate_sclk
= 0, stable_pstate_mclk
= 0;
4120 data
->battery_state
= (PP_StateUILabel_Battery
==
4121 request_ps
->classification
.ui_label
);
4123 PP_ASSERT_WITH_CODE(fiji_ps
->performance_level_count
== 2,
4124 "VI should always have 2 performance levels",);
4126 max_limits
= (PP_PowerSource_AC
== hwmgr
->power_source
) ?
4127 &(hwmgr
->dyn_state
.max_clock_voltage_on_ac
) :
4128 &(hwmgr
->dyn_state
.max_clock_voltage_on_dc
);
4130 /* Cap clock DPM tables at DC MAX if it is in DC. */
4131 if (PP_PowerSource_DC
== hwmgr
->power_source
) {
4132 for (i
= 0; i
< fiji_ps
->performance_level_count
; i
++) {
4133 if (fiji_ps
->performance_levels
[i
].memory_clock
> max_limits
->mclk
)
4134 fiji_ps
->performance_levels
[i
].memory_clock
= max_limits
->mclk
;
4135 if (fiji_ps
->performance_levels
[i
].engine_clock
> max_limits
->sclk
)
4136 fiji_ps
->performance_levels
[i
].engine_clock
= max_limits
->sclk
;
4140 fiji_ps
->vce_clks
.evclk
= hwmgr
->vce_arbiter
.evclk
;
4141 fiji_ps
->vce_clks
.ecclk
= hwmgr
->vce_arbiter
.ecclk
;
4143 fiji_ps
->acp_clk
= hwmgr
->acp_arbiter
.acpclk
;
4145 cgs_get_active_displays_info(hwmgr
->device
, &info
);
4147 /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
4149 /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
4151 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4152 PHM_PlatformCaps_StablePState
)) {
4153 max_limits
= &(hwmgr
->dyn_state
.max_clock_voltage_on_ac
);
4154 stable_pstate_sclk
= (max_limits
->sclk
* 75) / 100;
4156 for (count
= table_info
->vdd_dep_on_sclk
->count
- 1;
4157 count
>= 0; count
--) {
4158 if (stable_pstate_sclk
>=
4159 table_info
->vdd_dep_on_sclk
->entries
[count
].clk
) {
4160 stable_pstate_sclk
=
4161 table_info
->vdd_dep_on_sclk
->entries
[count
].clk
;
4167 stable_pstate_sclk
= table_info
->vdd_dep_on_sclk
->entries
[0].clk
;
4169 stable_pstate_mclk
= max_limits
->mclk
;
4171 minimum_clocks
.engineClock
= stable_pstate_sclk
;
4172 minimum_clocks
.memoryClock
= stable_pstate_mclk
;
4175 if (minimum_clocks
.engineClock
< hwmgr
->gfx_arbiter
.sclk
)
4176 minimum_clocks
.engineClock
= hwmgr
->gfx_arbiter
.sclk
;
4178 if (minimum_clocks
.memoryClock
< hwmgr
->gfx_arbiter
.mclk
)
4179 minimum_clocks
.memoryClock
= hwmgr
->gfx_arbiter
.mclk
;
4181 fiji_ps
->sclk_threshold
= hwmgr
->gfx_arbiter
.sclk_threshold
;
4183 if (0 != hwmgr
->gfx_arbiter
.sclk_over_drive
) {
4184 PP_ASSERT_WITH_CODE((hwmgr
->gfx_arbiter
.sclk_over_drive
<=
4185 hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
),
4186 "Overdrive sclk exceeds limit",
4187 hwmgr
->gfx_arbiter
.sclk_over_drive
=
4188 hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
);
4190 if (hwmgr
->gfx_arbiter
.sclk_over_drive
>= hwmgr
->gfx_arbiter
.sclk
)
4191 fiji_ps
->performance_levels
[1].engine_clock
=
4192 hwmgr
->gfx_arbiter
.sclk_over_drive
;
4195 if (0 != hwmgr
->gfx_arbiter
.mclk_over_drive
) {
4196 PP_ASSERT_WITH_CODE((hwmgr
->gfx_arbiter
.mclk_over_drive
<=
4197 hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
),
4198 "Overdrive mclk exceeds limit",
4199 hwmgr
->gfx_arbiter
.mclk_over_drive
=
4200 hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
);
4202 if (hwmgr
->gfx_arbiter
.mclk_over_drive
>= hwmgr
->gfx_arbiter
.mclk
)
4203 fiji_ps
->performance_levels
[1].memory_clock
=
4204 hwmgr
->gfx_arbiter
.mclk_over_drive
;
4207 disable_mclk_switching_for_frame_lock
= phm_cap_enabled(
4208 hwmgr
->platform_descriptor
.platformCaps
,
4209 PHM_PlatformCaps_DisableMclkSwitchingForFrameLock
);
4211 disable_mclk_switching
= (1 < info
.display_count
) ||
4212 disable_mclk_switching_for_frame_lock
;
4214 sclk
= fiji_ps
->performance_levels
[0].engine_clock
;
4215 mclk
= fiji_ps
->performance_levels
[0].memory_clock
;
4217 if (disable_mclk_switching
)
4218 mclk
= fiji_ps
->performance_levels
4219 [fiji_ps
->performance_level_count
- 1].memory_clock
;
4221 if (sclk
< minimum_clocks
.engineClock
)
4222 sclk
= (minimum_clocks
.engineClock
> max_limits
->sclk
) ?
4223 max_limits
->sclk
: minimum_clocks
.engineClock
;
4225 if (mclk
< minimum_clocks
.memoryClock
)
4226 mclk
= (minimum_clocks
.memoryClock
> max_limits
->mclk
) ?
4227 max_limits
->mclk
: minimum_clocks
.memoryClock
;
4229 fiji_ps
->performance_levels
[0].engine_clock
= sclk
;
4230 fiji_ps
->performance_levels
[0].memory_clock
= mclk
;
4232 fiji_ps
->performance_levels
[1].engine_clock
=
4233 (fiji_ps
->performance_levels
[1].engine_clock
>=
4234 fiji_ps
->performance_levels
[0].engine_clock
) ?
4235 fiji_ps
->performance_levels
[1].engine_clock
:
4236 fiji_ps
->performance_levels
[0].engine_clock
;
4238 if (disable_mclk_switching
) {
4239 if (mclk
< fiji_ps
->performance_levels
[1].memory_clock
)
4240 mclk
= fiji_ps
->performance_levels
[1].memory_clock
;
4242 fiji_ps
->performance_levels
[0].memory_clock
= mclk
;
4243 fiji_ps
->performance_levels
[1].memory_clock
= mclk
;
4245 if (fiji_ps
->performance_levels
[1].memory_clock
<
4246 fiji_ps
->performance_levels
[0].memory_clock
)
4247 fiji_ps
->performance_levels
[1].memory_clock
=
4248 fiji_ps
->performance_levels
[0].memory_clock
;
4251 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4252 PHM_PlatformCaps_StablePState
)) {
4253 for (i
= 0; i
< fiji_ps
->performance_level_count
; i
++) {
4254 fiji_ps
->performance_levels
[i
].engine_clock
= stable_pstate_sclk
;
4255 fiji_ps
->performance_levels
[i
].memory_clock
= stable_pstate_mclk
;
4256 fiji_ps
->performance_levels
[i
].pcie_gen
= data
->pcie_gen_performance
.max
;
4257 fiji_ps
->performance_levels
[i
].pcie_lane
= data
->pcie_gen_performance
.max
;
4264 static int fiji_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr
*hwmgr
, const void *input
)
4266 const struct phm_set_power_state_input
*states
=
4267 (const struct phm_set_power_state_input
*)input
;
4268 const struct fiji_power_state
*fiji_ps
=
4269 cast_const_phw_fiji_power_state(states
->pnew_state
);
4270 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4271 struct fiji_single_dpm_table
*sclk_table
= &(data
->dpm_table
.sclk_table
);
4272 uint32_t sclk
= fiji_ps
->performance_levels
4273 [fiji_ps
->performance_level_count
- 1].engine_clock
;
4274 struct fiji_single_dpm_table
*mclk_table
= &(data
->dpm_table
.mclk_table
);
4275 uint32_t mclk
= fiji_ps
->performance_levels
4276 [fiji_ps
->performance_level_count
- 1].memory_clock
;
4278 struct cgs_display_info info
= {0};
4280 data
->need_update_smu7_dpm_table
= 0;
4282 for (i
= 0; i
< sclk_table
->count
; i
++) {
4283 if (sclk
== sclk_table
->dpm_levels
[i
].value
)
4287 if (i
>= sclk_table
->count
)
4288 data
->need_update_smu7_dpm_table
|= DPMTABLE_OD_UPDATE_SCLK
;
4290 if(data
->display_timing
.min_clock_in_sr
!=
4291 hwmgr
->display_config
.min_core_set_clock_in_sr
)
4292 data
->need_update_smu7_dpm_table
|= DPMTABLE_UPDATE_SCLK
;
4295 for (i
= 0; i
< mclk_table
->count
; i
++) {
4296 if (mclk
== mclk_table
->dpm_levels
[i
].value
)
4300 if (i
>= mclk_table
->count
)
4301 data
->need_update_smu7_dpm_table
|= DPMTABLE_OD_UPDATE_MCLK
;
4303 cgs_get_active_displays_info(hwmgr
->device
, &info
);
4305 if (data
->display_timing
.num_existing_displays
!= info
.display_count
)
4306 data
->need_update_smu7_dpm_table
|= DPMTABLE_UPDATE_MCLK
;
4311 static uint16_t fiji_get_maximum_link_speed(struct pp_hwmgr
*hwmgr
,
4312 const struct fiji_power_state
*fiji_ps
)
4315 uint32_t sclk
, max_sclk
= 0;
4316 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4317 struct fiji_dpm_table
*dpm_table
= &data
->dpm_table
;
4319 for (i
= 0; i
< fiji_ps
->performance_level_count
; i
++) {
4320 sclk
= fiji_ps
->performance_levels
[i
].engine_clock
;
4321 if (max_sclk
< sclk
)
4325 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
4326 if (dpm_table
->sclk_table
.dpm_levels
[i
].value
== max_sclk
)
4327 return (uint16_t) ((i
>= dpm_table
->pcie_speed_table
.count
) ?
4328 dpm_table
->pcie_speed_table
.dpm_levels
4329 [dpm_table
->pcie_speed_table
.count
- 1].value
:
4330 dpm_table
->pcie_speed_table
.dpm_levels
[i
].value
);
4336 static int fiji_request_link_speed_change_before_state_change(
4337 struct pp_hwmgr
*hwmgr
, const void *input
)
4339 const struct phm_set_power_state_input
*states
=
4340 (const struct phm_set_power_state_input
*)input
;
4341 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4342 const struct fiji_power_state
*fiji_nps
=
4343 cast_const_phw_fiji_power_state(states
->pnew_state
);
4344 const struct fiji_power_state
*fiji_cps
=
4345 cast_const_phw_fiji_power_state(states
->pcurrent_state
);
4347 uint16_t target_link_speed
= fiji_get_maximum_link_speed(hwmgr
, fiji_nps
);
4348 uint16_t current_link_speed
;
4350 if (data
->force_pcie_gen
== PP_PCIEGenInvalid
)
4351 current_link_speed
= fiji_get_maximum_link_speed(hwmgr
, fiji_cps
);
4353 current_link_speed
= data
->force_pcie_gen
;
4355 data
->force_pcie_gen
= PP_PCIEGenInvalid
;
4356 data
->pspp_notify_required
= false;
4357 if (target_link_speed
> current_link_speed
) {
4358 switch(target_link_speed
) {
4360 if (0 == acpi_pcie_perf_request(hwmgr
->device
, PCIE_PERF_REQ_GEN3
, false))
4362 data
->force_pcie_gen
= PP_PCIEGen2
;
4363 if (current_link_speed
== PP_PCIEGen2
)
4366 if (0 == acpi_pcie_perf_request(hwmgr
->device
, PCIE_PERF_REQ_GEN2
, false))
4369 data
->force_pcie_gen
= fiji_get_current_pcie_speed(hwmgr
);
4373 if (target_link_speed
< current_link_speed
)
4374 data
->pspp_notify_required
= true;
4380 static int fiji_freeze_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
4382 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4384 if (0 == data
->need_update_smu7_dpm_table
)
4387 if ((0 == data
->sclk_dpm_key_disabled
) &&
4388 (data
->need_update_smu7_dpm_table
&
4389 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
))) {
4390 PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr
),
4391 "Trying to freeze SCLK DPM when DPM is disabled",
4393 PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
4394 PPSMC_MSG_SCLKDPM_FreezeLevel
),
4395 "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
4399 if ((0 == data
->mclk_dpm_key_disabled
) &&
4400 (data
->need_update_smu7_dpm_table
&
4401 DPMTABLE_OD_UPDATE_MCLK
)) {
4402 PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr
),
4403 "Trying to freeze MCLK DPM when DPM is disabled",
4405 PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
4406 PPSMC_MSG_MCLKDPM_FreezeLevel
),
4407 "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
4414 static int fiji_populate_and_upload_sclk_mclk_dpm_levels(
4415 struct pp_hwmgr
*hwmgr
, const void *input
)
4418 const struct phm_set_power_state_input
*states
=
4419 (const struct phm_set_power_state_input
*)input
;
4420 const struct fiji_power_state
*fiji_ps
=
4421 cast_const_phw_fiji_power_state(states
->pnew_state
);
4422 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4423 uint32_t sclk
= fiji_ps
->performance_levels
4424 [fiji_ps
->performance_level_count
- 1].engine_clock
;
4425 uint32_t mclk
= fiji_ps
->performance_levels
4426 [fiji_ps
->performance_level_count
- 1].memory_clock
;
4427 struct fiji_dpm_table
*dpm_table
= &data
->dpm_table
;
4429 struct fiji_dpm_table
*golden_dpm_table
= &data
->golden_dpm_table
;
4430 uint32_t dpm_count
, clock_percent
;
4433 if (0 == data
->need_update_smu7_dpm_table
)
4436 if (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_SCLK
) {
4437 dpm_table
->sclk_table
.dpm_levels
4438 [dpm_table
->sclk_table
.count
- 1].value
= sclk
;
4440 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4441 PHM_PlatformCaps_OD6PlusinACSupport
) ||
4442 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4443 PHM_PlatformCaps_OD6PlusinDCSupport
)) {
4444 /* Need to do calculation based on the golden DPM table
4445 * as the Heatmap GPU Clock axis is also based on the default values
4447 PP_ASSERT_WITH_CODE(
4448 (golden_dpm_table
->sclk_table
.dpm_levels
4449 [golden_dpm_table
->sclk_table
.count
- 1].value
!= 0),
4452 dpm_count
= dpm_table
->sclk_table
.count
< 2 ?
4453 0 : dpm_table
->sclk_table
.count
- 2;
4454 for (i
= dpm_count
; i
> 1; i
--) {
4455 if (sclk
> golden_dpm_table
->sclk_table
.dpm_levels
4456 [golden_dpm_table
->sclk_table
.count
-1].value
) {
4458 ((sclk
- golden_dpm_table
->sclk_table
.dpm_levels
4459 [golden_dpm_table
->sclk_table
.count
-1].value
) * 100) /
4460 golden_dpm_table
->sclk_table
.dpm_levels
4461 [golden_dpm_table
->sclk_table
.count
-1].value
;
4463 dpm_table
->sclk_table
.dpm_levels
[i
].value
=
4464 golden_dpm_table
->sclk_table
.dpm_levels
[i
].value
+
4465 (golden_dpm_table
->sclk_table
.dpm_levels
[i
].value
*
4468 } else if (golden_dpm_table
->sclk_table
.dpm_levels
4469 [dpm_table
->sclk_table
.count
-1].value
> sclk
) {
4471 ((golden_dpm_table
->sclk_table
.dpm_levels
4472 [golden_dpm_table
->sclk_table
.count
- 1].value
- sclk
) *
4474 golden_dpm_table
->sclk_table
.dpm_levels
4475 [golden_dpm_table
->sclk_table
.count
-1].value
;
4477 dpm_table
->sclk_table
.dpm_levels
[i
].value
=
4478 golden_dpm_table
->sclk_table
.dpm_levels
[i
].value
-
4479 (golden_dpm_table
->sclk_table
.dpm_levels
[i
].value
*
4480 clock_percent
) / 100;
4482 dpm_table
->sclk_table
.dpm_levels
[i
].value
=
4483 golden_dpm_table
->sclk_table
.dpm_levels
[i
].value
;
4488 if (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
) {
4489 dpm_table
->mclk_table
.dpm_levels
4490 [dpm_table
->mclk_table
.count
- 1].value
= mclk
;
4491 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4492 PHM_PlatformCaps_OD6PlusinACSupport
) ||
4493 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4494 PHM_PlatformCaps_OD6PlusinDCSupport
)) {
4496 PP_ASSERT_WITH_CODE(
4497 (golden_dpm_table
->mclk_table
.dpm_levels
4498 [golden_dpm_table
->mclk_table
.count
-1].value
!= 0),
4501 dpm_count
= dpm_table
->mclk_table
.count
< 2 ?
4502 0 : dpm_table
->mclk_table
.count
- 2;
4503 for (i
= dpm_count
; i
> 1; i
--) {
4504 if (mclk
> golden_dpm_table
->mclk_table
.dpm_levels
4505 [golden_dpm_table
->mclk_table
.count
-1].value
) {
4506 clock_percent
= ((mclk
-
4507 golden_dpm_table
->mclk_table
.dpm_levels
4508 [golden_dpm_table
->mclk_table
.count
-1].value
) * 100) /
4509 golden_dpm_table
->mclk_table
.dpm_levels
4510 [golden_dpm_table
->mclk_table
.count
-1].value
;
4512 dpm_table
->mclk_table
.dpm_levels
[i
].value
=
4513 golden_dpm_table
->mclk_table
.dpm_levels
[i
].value
+
4514 (golden_dpm_table
->mclk_table
.dpm_levels
[i
].value
*
4515 clock_percent
) / 100;
4517 } else if (golden_dpm_table
->mclk_table
.dpm_levels
4518 [dpm_table
->mclk_table
.count
-1].value
> mclk
) {
4519 clock_percent
= ((golden_dpm_table
->mclk_table
.dpm_levels
4520 [golden_dpm_table
->mclk_table
.count
-1].value
- mclk
) * 100) /
4521 golden_dpm_table
->mclk_table
.dpm_levels
4522 [golden_dpm_table
->mclk_table
.count
-1].value
;
4524 dpm_table
->mclk_table
.dpm_levels
[i
].value
=
4525 golden_dpm_table
->mclk_table
.dpm_levels
[i
].value
-
4526 (golden_dpm_table
->mclk_table
.dpm_levels
[i
].value
*
4527 clock_percent
) / 100;
4529 dpm_table
->mclk_table
.dpm_levels
[i
].value
=
4530 golden_dpm_table
->mclk_table
.dpm_levels
[i
].value
;
4535 if (data
->need_update_smu7_dpm_table
&
4536 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
)) {
4537 result
= fiji_populate_all_graphic_levels(hwmgr
);
4538 PP_ASSERT_WITH_CODE((0 == result
),
4539 "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
4543 if (data
->need_update_smu7_dpm_table
&
4544 (DPMTABLE_OD_UPDATE_MCLK
+ DPMTABLE_UPDATE_MCLK
)) {
4545 /*populate MCLK dpm table to SMU7 */
4546 result
= fiji_populate_all_memory_levels(hwmgr
);
4547 PP_ASSERT_WITH_CODE((0 == result
),
4548 "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
4555 static int fiji_trim_single_dpm_states(struct pp_hwmgr
*hwmgr
,
4556 struct fiji_single_dpm_table
* dpm_table
,
4557 uint32_t low_limit
, uint32_t high_limit
)
4561 for (i
= 0; i
< dpm_table
->count
; i
++) {
4562 if ((dpm_table
->dpm_levels
[i
].value
< low_limit
) ||
4563 (dpm_table
->dpm_levels
[i
].value
> high_limit
))
4564 dpm_table
->dpm_levels
[i
].enabled
= false;
4566 dpm_table
->dpm_levels
[i
].enabled
= true;
4571 static int fiji_trim_dpm_states(struct pp_hwmgr
*hwmgr
,
4572 const struct fiji_power_state
*fiji_ps
)
4574 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4575 uint32_t high_limit_count
;
4577 PP_ASSERT_WITH_CODE((fiji_ps
->performance_level_count
>= 1),
4578 "power state did not have any performance level",
4581 high_limit_count
= (1 == fiji_ps
->performance_level_count
) ? 0 : 1;
4583 fiji_trim_single_dpm_states(hwmgr
,
4584 &(data
->dpm_table
.sclk_table
),
4585 fiji_ps
->performance_levels
[0].engine_clock
,
4586 fiji_ps
->performance_levels
[high_limit_count
].engine_clock
);
4588 fiji_trim_single_dpm_states(hwmgr
,
4589 &(data
->dpm_table
.mclk_table
),
4590 fiji_ps
->performance_levels
[0].memory_clock
,
4591 fiji_ps
->performance_levels
[high_limit_count
].memory_clock
);
4596 static int fiji_generate_dpm_level_enable_mask(
4597 struct pp_hwmgr
*hwmgr
, const void *input
)
4600 const struct phm_set_power_state_input
*states
=
4601 (const struct phm_set_power_state_input
*)input
;
4602 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4603 const struct fiji_power_state
*fiji_ps
=
4604 cast_const_phw_fiji_power_state(states
->pnew_state
);
4606 result
= fiji_trim_dpm_states(hwmgr
, fiji_ps
);
4610 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
=
4611 fiji_get_dpm_level_enable_mask_value(&data
->dpm_table
.sclk_table
);
4612 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
=
4613 fiji_get_dpm_level_enable_mask_value(&data
->dpm_table
.mclk_table
);
4614 data
->last_mclk_dpm_enable_mask
=
4615 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
;
4617 if (data
->uvd_enabled
) {
4618 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
& 1)
4619 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
&= 0xFFFFFFFE;
4622 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
=
4623 fiji_get_dpm_level_enable_mask_value(&data
->dpm_table
.pcie_speed_table
);
4628 int fiji_enable_disable_uvd_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
4630 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
4631 (PPSMC_Msg
)PPSMC_MSG_UVDDPM_Enable
:
4632 (PPSMC_Msg
)PPSMC_MSG_UVDDPM_Disable
);
4635 int fiji_enable_disable_vce_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
4637 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
4638 PPSMC_MSG_VCEDPM_Enable
:
4639 PPSMC_MSG_VCEDPM_Disable
);
4642 int fiji_enable_disable_samu_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
4644 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
4645 PPSMC_MSG_SAMUDPM_Enable
:
4646 PPSMC_MSG_SAMUDPM_Disable
);
4649 int fiji_enable_disable_acp_dpm(struct pp_hwmgr
*hwmgr
, bool enable
)
4651 return smum_send_msg_to_smc(hwmgr
->smumgr
, enable
?
4652 PPSMC_MSG_ACPDPM_Enable
:
4653 PPSMC_MSG_ACPDPM_Disable
);
4656 int fiji_update_uvd_dpm(struct pp_hwmgr
*hwmgr
, bool bgate
)
4658 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4659 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
4660 struct phm_ppt_v1_information
*table_info
=
4661 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4664 data
->smc_state_table
.UvdBootLevel
= 0;
4665 if (table_info
->mm_dep_table
->count
> 0)
4666 data
->smc_state_table
.UvdBootLevel
=
4667 (uint8_t) (table_info
->mm_dep_table
->count
- 1);
4668 mm_boot_level_offset
= data
->dpm_table_start
+
4669 offsetof(SMU73_Discrete_DpmTable
, UvdBootLevel
);
4670 mm_boot_level_offset
/= 4;
4671 mm_boot_level_offset
*= 4;
4672 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
4673 CGS_IND_REG__SMC
, mm_boot_level_offset
);
4674 mm_boot_level_value
&= 0x00FFFFFF;
4675 mm_boot_level_value
|= data
->smc_state_table
.UvdBootLevel
<< 24;
4676 cgs_write_ind_register(hwmgr
->device
,
4677 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
4679 if (!phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4680 PHM_PlatformCaps_UVDDPM
) ||
4681 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4682 PHM_PlatformCaps_StablePState
))
4683 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
4684 PPSMC_MSG_UVDDPM_SetEnabledMask
,
4685 (uint32_t)(1 << data
->smc_state_table
.UvdBootLevel
));
4688 return fiji_enable_disable_uvd_dpm(hwmgr
, !bgate
);
4691 int fiji_update_vce_dpm(struct pp_hwmgr
*hwmgr
, const void *input
)
4693 const struct phm_set_power_state_input
*states
=
4694 (const struct phm_set_power_state_input
*)input
;
4695 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4696 const struct fiji_power_state
*fiji_nps
=
4697 cast_const_phw_fiji_power_state(states
->pnew_state
);
4698 const struct fiji_power_state
*fiji_cps
=
4699 cast_const_phw_fiji_power_state(states
->pcurrent_state
);
4701 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
4702 struct phm_ppt_v1_information
*table_info
=
4703 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4705 if (fiji_nps
->vce_clks
.evclk
>0 &&
4706 (fiji_cps
== NULL
|| fiji_cps
->vce_clks
.evclk
== 0)) {
4707 data
->smc_state_table
.VceBootLevel
=
4708 (uint8_t) (table_info
->mm_dep_table
->count
- 1);
4710 mm_boot_level_offset
= data
->dpm_table_start
+
4711 offsetof(SMU73_Discrete_DpmTable
, VceBootLevel
);
4712 mm_boot_level_offset
/= 4;
4713 mm_boot_level_offset
*= 4;
4714 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
4715 CGS_IND_REG__SMC
, mm_boot_level_offset
);
4716 mm_boot_level_value
&= 0xFF00FFFF;
4717 mm_boot_level_value
|= data
->smc_state_table
.VceBootLevel
<< 16;
4718 cgs_write_ind_register(hwmgr
->device
,
4719 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
4721 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4722 PHM_PlatformCaps_StablePState
)) {
4723 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
4724 PPSMC_MSG_VCEDPM_SetEnabledMask
,
4725 (uint32_t)1 << data
->smc_state_table
.VceBootLevel
);
4727 fiji_enable_disable_vce_dpm(hwmgr
, true);
4728 } else if (fiji_nps
->vce_clks
.evclk
== 0 &&
4730 fiji_cps
->vce_clks
.evclk
> 0)
4731 fiji_enable_disable_vce_dpm(hwmgr
, false);
4737 int fiji_update_samu_dpm(struct pp_hwmgr
*hwmgr
, bool bgate
)
4739 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4740 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
4741 struct phm_ppt_v1_information
*table_info
=
4742 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4745 data
->smc_state_table
.SamuBootLevel
=
4746 (uint8_t) (table_info
->mm_dep_table
->count
- 1);
4747 mm_boot_level_offset
= data
->dpm_table_start
+
4748 offsetof(SMU73_Discrete_DpmTable
, SamuBootLevel
);
4749 mm_boot_level_offset
/= 4;
4750 mm_boot_level_offset
*= 4;
4751 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
4752 CGS_IND_REG__SMC
, mm_boot_level_offset
);
4753 mm_boot_level_value
&= 0xFFFFFF00;
4754 mm_boot_level_value
|= data
->smc_state_table
.SamuBootLevel
<< 0;
4755 cgs_write_ind_register(hwmgr
->device
,
4756 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
4758 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4759 PHM_PlatformCaps_StablePState
))
4760 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
4761 PPSMC_MSG_SAMUDPM_SetEnabledMask
,
4762 (uint32_t)(1 << data
->smc_state_table
.SamuBootLevel
));
4765 return fiji_enable_disable_samu_dpm(hwmgr
, !bgate
);
4768 int fiji_update_acp_dpm(struct pp_hwmgr
*hwmgr
, bool bgate
)
4770 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4771 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
4772 struct phm_ppt_v1_information
*table_info
=
4773 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
4776 data
->smc_state_table
.AcpBootLevel
=
4777 (uint8_t) (table_info
->mm_dep_table
->count
- 1);
4778 mm_boot_level_offset
= data
->dpm_table_start
+
4779 offsetof(SMU73_Discrete_DpmTable
, AcpBootLevel
);
4780 mm_boot_level_offset
/= 4;
4781 mm_boot_level_offset
*= 4;
4782 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
4783 CGS_IND_REG__SMC
, mm_boot_level_offset
);
4784 mm_boot_level_value
&= 0xFFFF00FF;
4785 mm_boot_level_value
|= data
->smc_state_table
.AcpBootLevel
<< 8;
4786 cgs_write_ind_register(hwmgr
->device
,
4787 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
4789 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4790 PHM_PlatformCaps_StablePState
))
4791 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
4792 PPSMC_MSG_ACPDPM_SetEnabledMask
,
4793 (uint32_t)(1 << data
->smc_state_table
.AcpBootLevel
));
4796 return fiji_enable_disable_acp_dpm(hwmgr
, !bgate
);
4799 static int fiji_update_sclk_threshold(struct pp_hwmgr
*hwmgr
)
4801 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4804 uint32_t low_sclk_interrupt_threshold
= 0;
4806 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4807 PHM_PlatformCaps_SclkThrottleLowNotification
)
4808 && (hwmgr
->gfx_arbiter
.sclk_threshold
!=
4809 data
->low_sclk_interrupt_threshold
)) {
4810 data
->low_sclk_interrupt_threshold
=
4811 hwmgr
->gfx_arbiter
.sclk_threshold
;
4812 low_sclk_interrupt_threshold
=
4813 data
->low_sclk_interrupt_threshold
;
4815 CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold
);
4817 result
= fiji_copy_bytes_to_smc(
4819 data
->dpm_table_start
+
4820 offsetof(SMU73_Discrete_DpmTable
,
4821 LowSclkInterruptThreshold
),
4822 (uint8_t *)&low_sclk_interrupt_threshold
,
4830 static int fiji_program_mem_timing_parameters(struct pp_hwmgr
*hwmgr
)
4832 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4834 if (data
->need_update_smu7_dpm_table
&
4835 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_OD_UPDATE_MCLK
))
4836 return fiji_program_memory_timing_parameters(hwmgr
);
4841 static int fiji_unfreeze_sclk_mclk_dpm(struct pp_hwmgr
*hwmgr
)
4843 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4845 if (0 == data
->need_update_smu7_dpm_table
)
4848 if ((0 == data
->sclk_dpm_key_disabled
) &&
4849 (data
->need_update_smu7_dpm_table
&
4850 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_UPDATE_SCLK
))) {
4852 PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr
),
4853 "Trying to Unfreeze SCLK DPM when DPM is disabled",
4855 PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
4856 PPSMC_MSG_SCLKDPM_UnfreezeLevel
),
4857 "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
4861 if ((0 == data
->mclk_dpm_key_disabled
) &&
4862 (data
->need_update_smu7_dpm_table
& DPMTABLE_OD_UPDATE_MCLK
)) {
4864 PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr
),
4865 "Trying to Unfreeze MCLK DPM when DPM is disabled",
4867 PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr
->smumgr
,
4868 PPSMC_MSG_SCLKDPM_UnfreezeLevel
),
4869 "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
4873 data
->need_update_smu7_dpm_table
= 0;
4878 /* Look up the voltaged based on DAL's requested level.
4879 * and then send the requested VDDC voltage to SMC
4881 static void fiji_apply_dal_minimum_voltage_request(struct pp_hwmgr
*hwmgr
)
4886 int fiji_upload_dpm_level_enable_mask(struct pp_hwmgr
*hwmgr
)
4889 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4891 /* Apply minimum voltage based on DAL's request level */
4892 fiji_apply_dal_minimum_voltage_request(hwmgr
);
4894 if (0 == data
->sclk_dpm_key_disabled
) {
4895 /* Checking if DPM is running. If we discover hang because of this,
4896 * we should skip this message.
4898 if (!fiji_is_dpm_running(hwmgr
))
4899 printk(KERN_ERR
"[ powerplay ] "
4900 "Trying to set Enable Mask when DPM is disabled \n");
4902 if (data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
) {
4903 result
= smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
4904 PPSMC_MSG_SCLKDPM_SetEnabledMask
,
4905 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
);
4906 PP_ASSERT_WITH_CODE((0 == result
),
4907 "Set Sclk Dpm enable Mask failed", return -1);
4911 if (0 == data
->mclk_dpm_key_disabled
) {
4912 /* Checking if DPM is running. If we discover hang because of this,
4913 * we should skip this message.
4915 if (!fiji_is_dpm_running(hwmgr
))
4916 printk(KERN_ERR
"[ powerplay ]"
4917 " Trying to set Enable Mask when DPM is disabled \n");
4919 if (data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
) {
4920 result
= smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
4921 PPSMC_MSG_MCLKDPM_SetEnabledMask
,
4922 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
);
4923 PP_ASSERT_WITH_CODE((0 == result
),
4924 "Set Mclk Dpm enable Mask failed", return -1);
4931 static int fiji_notify_link_speed_change_after_state_change(
4932 struct pp_hwmgr
*hwmgr
, const void *input
)
4934 const struct phm_set_power_state_input
*states
=
4935 (const struct phm_set_power_state_input
*)input
;
4936 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
4937 const struct fiji_power_state
*fiji_ps
=
4938 cast_const_phw_fiji_power_state(states
->pnew_state
);
4939 uint16_t target_link_speed
= fiji_get_maximum_link_speed(hwmgr
, fiji_ps
);
4942 if (data
->pspp_notify_required
) {
4943 if (target_link_speed
== PP_PCIEGen3
)
4944 request
= PCIE_PERF_REQ_GEN3
;
4945 else if (target_link_speed
== PP_PCIEGen2
)
4946 request
= PCIE_PERF_REQ_GEN2
;
4948 request
= PCIE_PERF_REQ_GEN1
;
4950 if(request
== PCIE_PERF_REQ_GEN1
&&
4951 fiji_get_current_pcie_speed(hwmgr
) > 0)
4954 if (acpi_pcie_perf_request(hwmgr
->device
, request
, false)) {
4955 if (PP_PCIEGen2
== target_link_speed
)
4956 printk("PSPP request to switch to Gen2 from Gen3 Failed!");
4958 printk("PSPP request to switch to Gen1 from Gen2 Failed!");
4965 static int fiji_set_power_state_tasks(struct pp_hwmgr
*hwmgr
,
4968 int tmp_result
, result
= 0;
4970 tmp_result
= fiji_find_dpm_states_clocks_in_dpm_table(hwmgr
, input
);
4971 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4972 "Failed to find DPM states clocks in DPM table!",
4973 result
= tmp_result
);
4975 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
4976 PHM_PlatformCaps_PCIEPerformanceRequest
)) {
4978 fiji_request_link_speed_change_before_state_change(hwmgr
, input
);
4979 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4980 "Failed to request link speed change before state change!",
4981 result
= tmp_result
);
4984 tmp_result
= fiji_freeze_sclk_mclk_dpm(hwmgr
);
4985 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4986 "Failed to freeze SCLK MCLK DPM!", result
= tmp_result
);
4988 tmp_result
= fiji_populate_and_upload_sclk_mclk_dpm_levels(hwmgr
, input
);
4989 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4990 "Failed to populate and upload SCLK MCLK DPM levels!",
4991 result
= tmp_result
);
4993 tmp_result
= fiji_generate_dpm_level_enable_mask(hwmgr
, input
);
4994 PP_ASSERT_WITH_CODE((0 == tmp_result
),
4995 "Failed to generate DPM level enabled mask!",
4996 result
= tmp_result
);
4998 tmp_result
= fiji_update_vce_dpm(hwmgr
, input
);
4999 PP_ASSERT_WITH_CODE((0 == tmp_result
),
5000 "Failed to update VCE DPM!",
5001 result
= tmp_result
);
5003 tmp_result
= fiji_update_sclk_threshold(hwmgr
);
5004 PP_ASSERT_WITH_CODE((0 == tmp_result
),
5005 "Failed to update SCLK threshold!",
5006 result
= tmp_result
);
5008 tmp_result
= fiji_program_mem_timing_parameters(hwmgr
);
5009 PP_ASSERT_WITH_CODE((0 == tmp_result
),
5010 "Failed to program memory timing parameters!",
5011 result
= tmp_result
);
5013 tmp_result
= fiji_unfreeze_sclk_mclk_dpm(hwmgr
);
5014 PP_ASSERT_WITH_CODE((0 == tmp_result
),
5015 "Failed to unfreeze SCLK MCLK DPM!",
5016 result
= tmp_result
);
5018 tmp_result
= fiji_upload_dpm_level_enable_mask(hwmgr
);
5019 PP_ASSERT_WITH_CODE((0 == tmp_result
),
5020 "Failed to upload DPM level enabled mask!",
5021 result
= tmp_result
);
5023 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
5024 PHM_PlatformCaps_PCIEPerformanceRequest
)) {
5026 fiji_notify_link_speed_change_after_state_change(hwmgr
, input
);
5027 PP_ASSERT_WITH_CODE((0 == tmp_result
),
5028 "Failed to notify link speed change after state change!",
5029 result
= tmp_result
);
5035 static int fiji_dpm_get_sclk(struct pp_hwmgr
*hwmgr
, bool low
)
5037 struct pp_power_state
*ps
;
5038 struct fiji_power_state
*fiji_ps
;
5043 ps
= hwmgr
->request_ps
;
5048 fiji_ps
= cast_phw_fiji_power_state(&ps
->hardware
);
5051 return fiji_ps
->performance_levels
[0].engine_clock
;
5053 return fiji_ps
->performance_levels
5054 [fiji_ps
->performance_level_count
-1].engine_clock
;
5057 static int fiji_dpm_get_mclk(struct pp_hwmgr
*hwmgr
, bool low
)
5059 struct pp_power_state
*ps
;
5060 struct fiji_power_state
*fiji_ps
;
5065 ps
= hwmgr
->request_ps
;
5070 fiji_ps
= cast_phw_fiji_power_state(&ps
->hardware
);
5073 return fiji_ps
->performance_levels
[0].memory_clock
;
5075 return fiji_ps
->performance_levels
5076 [fiji_ps
->performance_level_count
-1].memory_clock
;
5079 static void fiji_print_current_perforce_level(
5080 struct pp_hwmgr
*hwmgr
, struct seq_file
*m
)
5082 uint32_t sclk
, mclk
, activity_percent
= 0;
5084 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5086 smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_API_GetSclkFrequency
);
5088 sclk
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5090 smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_API_GetMclkFrequency
);
5092 mclk
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5093 seq_printf(m
, "\n [ mclk ]: %u MHz\n\n [ sclk ]: %u MHz\n",
5094 mclk
/ 100, sclk
/ 100);
5096 offset
= data
->soft_regs_start
+ offsetof(SMU73_SoftRegisters
, AverageGraphicsActivity
);
5097 activity_percent
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, offset
);
5098 activity_percent
+= 0x80;
5099 activity_percent
>>= 8;
5101 seq_printf(m
, "\n [GPU load]: %u%%\n\n", activity_percent
> 100 ? 100 : activity_percent
);
5103 seq_printf(m
, "uvd %sabled\n", data
->uvd_power_gated
? "dis" : "en");
5105 seq_printf(m
, "vce %sabled\n", data
->vce_power_gated
? "dis" : "en");
5108 static int fiji_program_display_gap(struct pp_hwmgr
*hwmgr
)
5110 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5111 uint32_t num_active_displays
= 0;
5112 uint32_t display_gap
= cgs_read_ind_register(hwmgr
->device
,
5113 CGS_IND_REG__SMC
, ixCG_DISPLAY_GAP_CNTL
);
5114 uint32_t display_gap2
;
5115 uint32_t pre_vbi_time_in_us
;
5116 uint32_t frame_time_in_us
;
5118 uint32_t refresh_rate
= 0;
5119 struct cgs_display_info info
= {0};
5120 struct cgs_mode_info mode_info
;
5122 info
.mode_info
= &mode_info
;
5124 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5125 num_active_displays
= info
.display_count
;
5127 display_gap
= PHM_SET_FIELD(display_gap
, CG_DISPLAY_GAP_CNTL
,
5128 DISP_GAP
, (num_active_displays
> 0)?
5129 DISPLAY_GAP_VBLANK_OR_WM
: DISPLAY_GAP_IGNORE
);
5130 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
5131 ixCG_DISPLAY_GAP_CNTL
, display_gap
);
5133 ref_clock
= mode_info
.ref_clock
;
5134 refresh_rate
= mode_info
.refresh_rate
;
5136 if (refresh_rate
== 0)
5139 frame_time_in_us
= 1000000 / refresh_rate
;
5141 pre_vbi_time_in_us
= frame_time_in_us
- 200 - mode_info
.vblank_time_us
;
5142 display_gap2
= pre_vbi_time_in_us
* (ref_clock
/ 100);
5144 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
5145 ixCG_DISPLAY_GAP_CNTL2
, display_gap2
);
5147 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
5148 data
->soft_regs_start
+
5149 offsetof(SMU73_SoftRegisters
, PreVBlankGap
), 0x64);
5151 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
5152 data
->soft_regs_start
+
5153 offsetof(SMU73_SoftRegisters
, VBlankTimeout
),
5154 (frame_time_in_us
- pre_vbi_time_in_us
));
5156 if (num_active_displays
== 1)
5157 tonga_notify_smc_display_change(hwmgr
, true);
5162 int fiji_display_configuration_changed_task(struct pp_hwmgr
*hwmgr
)
5164 return fiji_program_display_gap(hwmgr
);
5167 static int fiji_set_max_fan_pwm_output(struct pp_hwmgr
*hwmgr
,
5168 uint16_t us_max_fan_pwm
)
5170 hwmgr
->thermal_controller
.
5171 advanceFanControlParameters
.usMaxFanPWM
= us_max_fan_pwm
;
5173 if (phm_is_hw_access_blocked(hwmgr
))
5176 return smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5177 PPSMC_MSG_SetFanPwmMax
, us_max_fan_pwm
);
5180 static int fiji_set_max_fan_rpm_output(struct pp_hwmgr
*hwmgr
,
5181 uint16_t us_max_fan_rpm
)
5183 hwmgr
->thermal_controller
.
5184 advanceFanControlParameters
.usMaxFanRPM
= us_max_fan_rpm
;
5186 if (phm_is_hw_access_blocked(hwmgr
))
5189 return smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5190 PPSMC_MSG_SetFanRpmMax
, us_max_fan_rpm
);
5193 int fiji_dpm_set_interrupt_state(void *private_data
,
5194 unsigned src_id
, unsigned type
,
5197 uint32_t cg_thermal_int
;
5198 struct pp_hwmgr
*hwmgr
= ((struct pp_eventmgr
*)private_data
)->hwmgr
;
5204 case AMD_THERMAL_IRQ_LOW_TO_HIGH
:
5206 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
,
5207 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5208 cg_thermal_int
|= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK
;
5209 cgs_write_ind_register(hwmgr
->device
,
5210 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5212 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
,
5213 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5214 cg_thermal_int
&= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK
;
5215 cgs_write_ind_register(hwmgr
->device
,
5216 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5220 case AMD_THERMAL_IRQ_HIGH_TO_LOW
:
5222 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
,
5223 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5224 cg_thermal_int
|= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK
;
5225 cgs_write_ind_register(hwmgr
->device
,
5226 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5228 cg_thermal_int
= cgs_read_ind_register(hwmgr
->device
,
5229 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
);
5230 cg_thermal_int
&= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK
;
5231 cgs_write_ind_register(hwmgr
->device
,
5232 CGS_IND_REG__SMC
, ixCG_THERMAL_INT
, cg_thermal_int
);
5241 int fiji_register_internal_thermal_interrupt(struct pp_hwmgr
*hwmgr
,
5242 const void *thermal_interrupt_info
)
5245 const struct pp_interrupt_registration_info
*info
=
5246 (const struct pp_interrupt_registration_info
*)
5247 thermal_interrupt_info
;
5252 result
= cgs_add_irq_source(hwmgr
->device
, 230, AMD_THERMAL_IRQ_LAST
,
5253 fiji_dpm_set_interrupt_state
,
5254 info
->call_back
, info
->context
);
5259 result
= cgs_add_irq_source(hwmgr
->device
, 231, AMD_THERMAL_IRQ_LAST
,
5260 fiji_dpm_set_interrupt_state
,
5261 info
->call_back
, info
->context
);
5269 static int fiji_set_fan_control_mode(struct pp_hwmgr
*hwmgr
, uint32_t mode
)
5272 /* stop auto-manage */
5273 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
5274 PHM_PlatformCaps_MicrocodeFanControl
))
5275 fiji_fan_ctrl_stop_smc_fan_control(hwmgr
);
5276 fiji_fan_ctrl_set_static_mode(hwmgr
, mode
);
5278 /* restart auto-manage */
5279 fiji_fan_ctrl_reset_fan_speed_to_default(hwmgr
);
5284 static int fiji_get_fan_control_mode(struct pp_hwmgr
*hwmgr
)
5286 if (hwmgr
->fan_ctrl_is_in_default_mode
)
5287 return hwmgr
->fan_ctrl_default_mode
;
5289 return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
5290 CG_FDO_CTRL2
, FDO_PWM_MODE
);
5293 static int fiji_force_clock_level(struct pp_hwmgr
*hwmgr
,
5294 enum pp_clock_type type
, uint32_t mask
)
5296 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5298 if (hwmgr
->dpm_level
!= AMD_DPM_FORCED_LEVEL_MANUAL
)
5303 if (!data
->sclk_dpm_key_disabled
)
5304 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5305 PPSMC_MSG_SCLKDPM_SetEnabledMask
,
5306 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
& mask
);
5310 if (!data
->mclk_dpm_key_disabled
)
5311 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5312 PPSMC_MSG_MCLKDPM_SetEnabledMask
,
5313 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
& mask
);
5318 uint32_t tmp
= mask
& data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
;
5324 if (!data
->pcie_dpm_key_disabled
)
5325 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
5326 PPSMC_MSG_PCIeDPM_ForceLevel
,
5337 static int fiji_print_clock_levels(struct pp_hwmgr
*hwmgr
,
5338 enum pp_clock_type type
, char *buf
)
5340 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5341 struct fiji_single_dpm_table
*sclk_table
= &(data
->dpm_table
.sclk_table
);
5342 struct fiji_single_dpm_table
*mclk_table
= &(data
->dpm_table
.mclk_table
);
5343 struct fiji_single_dpm_table
*pcie_table
= &(data
->dpm_table
.pcie_speed_table
);
5344 int i
, now
, size
= 0;
5345 uint32_t clock
, pcie_speed
;
5349 smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_API_GetSclkFrequency
);
5350 clock
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5352 for (i
= 0; i
< sclk_table
->count
; i
++) {
5353 if (clock
> sclk_table
->dpm_levels
[i
].value
)
5359 for (i
= 0; i
< sclk_table
->count
; i
++)
5360 size
+= sprintf(buf
+ size
, "%d: %uMhz %s\n",
5361 i
, sclk_table
->dpm_levels
[i
].value
/ 100,
5362 (i
== now
) ? "*" : "");
5365 smum_send_msg_to_smc(hwmgr
->smumgr
, PPSMC_MSG_API_GetMclkFrequency
);
5366 clock
= cgs_read_register(hwmgr
->device
, mmSMC_MSG_ARG_0
);
5368 for (i
= 0; i
< mclk_table
->count
; i
++) {
5369 if (clock
> mclk_table
->dpm_levels
[i
].value
)
5375 for (i
= 0; i
< mclk_table
->count
; i
++)
5376 size
+= sprintf(buf
+ size
, "%d: %uMhz %s\n",
5377 i
, mclk_table
->dpm_levels
[i
].value
/ 100,
5378 (i
== now
) ? "*" : "");
5381 pcie_speed
= fiji_get_current_pcie_speed(hwmgr
);
5382 for (i
= 0; i
< pcie_table
->count
; i
++) {
5383 if (pcie_speed
!= pcie_table
->dpm_levels
[i
].value
)
5389 for (i
= 0; i
< pcie_table
->count
; i
++)
5390 size
+= sprintf(buf
+ size
, "%d: %s %s\n", i
,
5391 (pcie_table
->dpm_levels
[i
].value
== 0) ? "2.5GB, x1" :
5392 (pcie_table
->dpm_levels
[i
].value
== 1) ? "5.0GB, x16" :
5393 (pcie_table
->dpm_levels
[i
].value
== 2) ? "8.0GB, x16" : "",
5394 (i
== now
) ? "*" : "");
5402 static inline bool fiji_are_power_levels_equal(const struct fiji_performance_level
*pl1
,
5403 const struct fiji_performance_level
*pl2
)
5405 return ((pl1
->memory_clock
== pl2
->memory_clock
) &&
5406 (pl1
->engine_clock
== pl2
->engine_clock
) &&
5407 (pl1
->pcie_gen
== pl2
->pcie_gen
) &&
5408 (pl1
->pcie_lane
== pl2
->pcie_lane
));
5411 int fiji_check_states_equal(struct pp_hwmgr
*hwmgr
, const struct pp_hw_power_state
*pstate1
, const struct pp_hw_power_state
*pstate2
, bool *equal
)
5413 const struct fiji_power_state
*psa
= cast_const_phw_fiji_power_state(pstate1
);
5414 const struct fiji_power_state
*psb
= cast_const_phw_fiji_power_state(pstate2
);
5417 if (equal
== NULL
|| psa
== NULL
|| psb
== NULL
)
5420 /* If the two states don't even have the same number of performance levels they cannot be the same state. */
5421 if (psa
->performance_level_count
!= psb
->performance_level_count
) {
5426 for (i
= 0; i
< psa
->performance_level_count
; i
++) {
5427 if (!fiji_are_power_levels_equal(&(psa
->performance_levels
[i
]), &(psb
->performance_levels
[i
]))) {
5428 /* If we have found even one performance level pair that is different the states are different. */
5434 /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
5435 *equal
= ((psa
->uvd_clks
.vclk
== psb
->uvd_clks
.vclk
) && (psa
->uvd_clks
.dclk
== psb
->uvd_clks
.dclk
));
5436 *equal
&= ((psa
->vce_clks
.evclk
== psb
->vce_clks
.evclk
) && (psa
->vce_clks
.ecclk
== psb
->vce_clks
.ecclk
));
5437 *equal
&= (psa
->sclk_threshold
== psb
->sclk_threshold
);
5438 *equal
&= (psa
->acp_clk
== psb
->acp_clk
);
5443 bool fiji_check_smc_update_required_for_display_configuration(struct pp_hwmgr
*hwmgr
)
5445 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5446 bool is_update_required
= false;
5447 struct cgs_display_info info
= {0,0,NULL
};
5449 cgs_get_active_displays_info(hwmgr
->device
, &info
);
5451 if (data
->display_timing
.num_existing_displays
!= info
.display_count
)
5452 is_update_required
= true;
5454 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_SclkDeepSleep
)) {
5455 if(hwmgr
->display_config
.min_core_set_clock_in_sr
!= data
->display_timing
.min_clock_in_sr
)
5456 is_update_required
= true;
5459 return is_update_required
;
5462 static int fiji_get_sclk_od(struct pp_hwmgr
*hwmgr
)
5464 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5465 struct fiji_single_dpm_table
*sclk_table
= &(data
->dpm_table
.sclk_table
);
5466 struct fiji_single_dpm_table
*golden_sclk_table
=
5467 &(data
->golden_dpm_table
.sclk_table
);
5470 value
= (sclk_table
->dpm_levels
[sclk_table
->count
- 1].value
-
5471 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
) *
5473 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
;
5478 static int fiji_set_sclk_od(struct pp_hwmgr
*hwmgr
, uint32_t value
)
5480 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5481 struct fiji_single_dpm_table
*golden_sclk_table
=
5482 &(data
->golden_dpm_table
.sclk_table
);
5483 struct pp_power_state
*ps
;
5484 struct fiji_power_state
*fiji_ps
;
5489 ps
= hwmgr
->request_ps
;
5494 fiji_ps
= cast_phw_fiji_power_state(&ps
->hardware
);
5496 fiji_ps
->performance_levels
[fiji_ps
->performance_level_count
- 1].engine_clock
=
5497 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
*
5499 golden_sclk_table
->dpm_levels
[golden_sclk_table
->count
- 1].value
;
5504 static int fiji_get_mclk_od(struct pp_hwmgr
*hwmgr
)
5506 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5507 struct fiji_single_dpm_table
*mclk_table
= &(data
->dpm_table
.mclk_table
);
5508 struct fiji_single_dpm_table
*golden_mclk_table
=
5509 &(data
->golden_dpm_table
.mclk_table
);
5512 value
= (mclk_table
->dpm_levels
[mclk_table
->count
- 1].value
-
5513 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
) *
5515 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
;
5520 static int fiji_set_mclk_od(struct pp_hwmgr
*hwmgr
, uint32_t value
)
5522 struct fiji_hwmgr
*data
= (struct fiji_hwmgr
*)(hwmgr
->backend
);
5523 struct fiji_single_dpm_table
*golden_mclk_table
=
5524 &(data
->golden_dpm_table
.mclk_table
);
5525 struct pp_power_state
*ps
;
5526 struct fiji_power_state
*fiji_ps
;
5531 ps
= hwmgr
->request_ps
;
5536 fiji_ps
= cast_phw_fiji_power_state(&ps
->hardware
);
5538 fiji_ps
->performance_levels
[fiji_ps
->performance_level_count
- 1].memory_clock
=
5539 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
*
5541 golden_mclk_table
->dpm_levels
[golden_mclk_table
->count
- 1].value
;
5546 static const struct pp_hwmgr_func fiji_hwmgr_funcs
= {
5547 .backend_init
= &fiji_hwmgr_backend_init
,
5548 .backend_fini
= &fiji_hwmgr_backend_fini
,
5549 .asic_setup
= &fiji_setup_asic_task
,
5550 .dynamic_state_management_enable
= &fiji_enable_dpm_tasks
,
5551 .dynamic_state_management_disable
= &fiji_disable_dpm_tasks
,
5552 .force_dpm_level
= &fiji_dpm_force_dpm_level
,
5553 .get_num_of_pp_table_entries
= &tonga_get_number_of_powerplay_table_entries
,
5554 .get_power_state_size
= &fiji_get_power_state_size
,
5555 .get_pp_table_entry
= &fiji_get_pp_table_entry
,
5556 .patch_boot_state
= &fiji_patch_boot_state
,
5557 .apply_state_adjust_rules
= &fiji_apply_state_adjust_rules
,
5558 .power_state_set
= &fiji_set_power_state_tasks
,
5559 .get_sclk
= &fiji_dpm_get_sclk
,
5560 .get_mclk
= &fiji_dpm_get_mclk
,
5561 .print_current_perforce_level
= &fiji_print_current_perforce_level
,
5562 .powergate_uvd
= &fiji_phm_powergate_uvd
,
5563 .powergate_vce
= &fiji_phm_powergate_vce
,
5564 .disable_clock_power_gating
= &fiji_phm_disable_clock_power_gating
,
5565 .notify_smc_display_config_after_ps_adjustment
=
5566 &tonga_notify_smc_display_config_after_ps_adjustment
,
5567 .display_config_changed
= &fiji_display_configuration_changed_task
,
5568 .set_max_fan_pwm_output
= fiji_set_max_fan_pwm_output
,
5569 .set_max_fan_rpm_output
= fiji_set_max_fan_rpm_output
,
5570 .get_temperature
= fiji_thermal_get_temperature
,
5571 .stop_thermal_controller
= fiji_thermal_stop_thermal_controller
,
5572 .get_fan_speed_info
= fiji_fan_ctrl_get_fan_speed_info
,
5573 .get_fan_speed_percent
= fiji_fan_ctrl_get_fan_speed_percent
,
5574 .set_fan_speed_percent
= fiji_fan_ctrl_set_fan_speed_percent
,
5575 .reset_fan_speed_to_default
= fiji_fan_ctrl_reset_fan_speed_to_default
,
5576 .get_fan_speed_rpm
= fiji_fan_ctrl_get_fan_speed_rpm
,
5577 .set_fan_speed_rpm
= fiji_fan_ctrl_set_fan_speed_rpm
,
5578 .uninitialize_thermal_controller
= fiji_thermal_ctrl_uninitialize_thermal_controller
,
5579 .register_internal_thermal_interrupt
= fiji_register_internal_thermal_interrupt
,
5580 .set_fan_control_mode
= fiji_set_fan_control_mode
,
5581 .get_fan_control_mode
= fiji_get_fan_control_mode
,
5582 .check_states_equal
= fiji_check_states_equal
,
5583 .check_smc_update_required_for_display_configuration
= fiji_check_smc_update_required_for_display_configuration
,
5584 .force_clock_level
= fiji_force_clock_level
,
5585 .print_clock_levels
= fiji_print_clock_levels
,
5586 .get_sclk_od
= fiji_get_sclk_od
,
5587 .set_sclk_od
= fiji_set_sclk_od
,
5588 .get_mclk_od
= fiji_get_mclk_od
,
5589 .set_mclk_od
= fiji_set_mclk_od
,
5592 int fiji_hwmgr_init(struct pp_hwmgr
*hwmgr
)
5594 hwmgr
->hwmgr_func
= &fiji_hwmgr_funcs
;
5595 hwmgr
->pptable_func
= &tonga_pptable_funcs
;
5596 pp_fiji_thermal_initialize(hwmgr
);